ret2dlresolve
ret2dlresolve
原理概述
linux 动态链接的程序使用 _dl_runtime_resolve(link_map_obj, reloc_offset)
来对动态链接的函数进行重定位。
动态链接器在解析符号(函数)地址时需要使用:重定位表项、动态符号表、动态字符串表等。如果能够修改其中的某些内容,就能使得动态链接器解析的符号(函数)是我们想要解析的符号(函数)。
攻击效果
让被攻击的函数变成我们所需要的函数,且被攻击函数 got 表也被劫持为目标函数的地址
使用限制
依据保护分几种的
使用场景
利用ROP技巧,可以绕过NX和ASLR保护,比较适用于一些比较简单的栈溢出情况,但是同时难以泄漏获取更多信息的情况(比如没办法获取到libc版本)
延迟绑定技术
以下基于 32 位程序,64 位差异不大
ret2dlresolve 需要了解动态链接的基本过程以及 ELF 文件中动态链接相关的结构(段、表)
延迟绑定相关段、表、结构体
结构体定义文件:/glibc-2.23/elf/elf.h
PLT表
在程序中以 .plt 节表示
每一个表项表示了一个与要重定位的函数相关的若干条指令,每个表项长度为 16 个字节,存储的是用于做延迟绑定的代码
对于每个表项:
- 第一条指令:跳转到对应函数 got 表
- 第二条指令(首次调用时 got 调回到这里):压入函数偏移
- 第三条指令:跳转到压入 link_map
- 第四条指令:跳转到 got[1] ,即跳转执行
_dl_runtime_resolve(link_map_obj, reloc_index)
GOT表
在程序中以 .got.plt 表示
每一个表项存储的都是一个地址,每个表项长度是当前程序的对应需要寻址长度(32位程序:4字节,64位程序:8字节)
![image-20210805143452036](../../../Library/Application Support/typora-user-images/image-20210805143452036.png)
- .got.plt[0]:.dynamic 段地址
- .got.plt[1]:
link_map
结构地址(启动后写入) - .got.plt[2]:
_dl_runtime_resolve
函数地址(启动后写入)
![image-20210805143521976](../../../Library/Application Support/typora-user-images/image-20210805143521976.png)
- .got.plt[x]:各函数的真实地址;未被调用时是各函数 plt+6
.dynamic - 动态节
在加载过程中,.dynmic 节整个以一个段的形式加载进内存,所以说在程序中的 .dynmic 节也就是运行后的 .dynmic 段 。
该段保存了许多 Elf64_Dyn 结构,Elf64_Dyn 里面保存的是其他节的信息,主要是其他节的地址:
1 | typedef struct |
.dynamic 主要用于动态链接时寻找其他相关节(.dynsym、.dynstr、.rela.plt 等节)。
![image-20210803145147658](../../../Library/Application Support/typora-user-images/image-20210803145147658.png)
**着重关注DT_SYMTAB,DT_STRTAB,DT_JMPREL,DT_VERSYM(64位下才需要关注)**:
DT_SYMTAB:.dynsym段地址
DT_STRTAB:.dynstr段地址
DT_JMPREL:.rel.plt段地址
DT_VERSYM:.gnu.version段地址
.dynsym - 动态符号表
存储着在动态链接中所需要的每个函数所对应的符号信息
![image-20210803145718465](../../../Library/Application Support/typora-user-images/image-20210803145718465.png)
每个结构体分别对应一个符号 (函数)
1 | typedef struct |
.dynstr - 动态字符串表
该表是一个字符串数组,存放了一系列符号字符串(函数名)
![image-20210803145835255](../../../Library/Application Support/typora-user-images/image-20210803145835255.png)
.rel.plt - 重定向节
保存了重定位相关的信息。保存在链接或者运行时,对 ELF 目标文件的某部分内容或者进程镜像进行补充或修改信息。每个结构体也与某一个重定位的函数相关。
![image-20210805110223398](../../../Library/Application Support/typora-user-images/image-20210805110223398.png)
1 | typedef struct |
link_map 结构
1 | struct link_map |
延迟绑定相关函数
_dl_runtime_resolve
源码文件:glibc/sysdeps/i386/dl-trampoline.S
_dl_runtime__resolve(link_map_obj, reloc_arg)
第一个参数是一个 link_map 结构,第二个参数是一个重定位参数
该函数最后通过调用 _dl_fixup(link_map_obj, reloc_arg)
解析函数名获得最后真实地址
_dl_fixup
源码文件:/glibc/elf/dl-runtime.c
延迟绑定过程
demo 程序:
1 | // gcc -m32 -g hello_world.c -o hello_world |
首次 call printf@plt
:
![image-20210803170610338](../../../Library/Application Support/typora-user-images/image-20210803170610338.png)
跳转到 got 表,第一次调用 got 表里存储是 printf@plt+6
![image-20210803172647795](../../../Library/Application Support/typora-user-images/image-20210803172647795.png)
跳转回 printf@plt+6
将函数偏移(reloc_index)压栈,然后再跳转到 plt[0](plt表头部):
![image-20210803173419006](../../../Library/Application Support/typora-user-images/image-20210803173419006.png)
将 .got.plt[1] 压栈,即将 link_map 结构体地址压栈;然后跳转到 .got.plt[2] ,即跳转运行 _dl_runtime_resolve
:
程序启动后自动向 .got.plt[1] 写入 link_map 结构体;同理在 .got.plt[2] 写入 _dl_runtime_resolve 函数地址
_dl_runtime_resolve(link_map_obj, reloc_index)
![image-20210803223537464](../../../Library/Application Support/typora-user-images/image-20210803223537464.png)
经过一系列指令后,进入函数 _dl_fixup(link_map_obj, reloc_arg)
(解析符号地址的函数)
然后涉及一段宏定义、结构体定义,具体源码分析:
https://bbs.pediy.com/thread-253833.htm
![image-20210803232407915](../../../Library/Application Support/typora-user-images/image-20210803232407915.png)
上:.got.plt ,第一个
.dynamic
、第二个link_map
、第三个_dl_resolved
下:link_map ,第三个就是
.dynamic
地址
通过 link_map 找到
.dynamic
在从
.dynamic
中的DT_SYMTAB
、DT_STRTAB
、DT_JMPREL
分别取出.dynsym段地址
、.dynstr段地址
、.rel.plt段地址
.rel.plt + 第二个参数
求出当前函数的重定位表项Elf32_Rel
的指针,记作rel
rel->r_info >> 8
作为.dynsym
的下标,求出当前函数的符号表项Elf32_Sym
的指针,记作sym
.dynstr + sym->st_name
得出符号名字符串指针在动态链接库查找这个函数的地址,并且把地址赋值给
*rel->r_offset
,即 GOT 表
RELRO保护
无保护
![image-20210805153804291](../../../Library/Application Support/typora-user-images/image-20210805153804291.png)
重定位相关表段不进行任何保护,.dynamic
允许修改:
![image-20210805154416971](../../../Library/Application Support/typora-user-images/image-20210805154416971.png)
部分保护
![image-20210805153920005](../../../Library/Application Support/typora-user-images/image-20210805153920005.png)
重定位相关表段在初始化后被标识为只读
![image-20210805233725067](../../../Library/Application Support/typora-user-images/image-20210805233725067.png)
完全保护
![image-20210805154051144](../../../Library/Application Support/typora-user-images/image-20210805154051144.png)
在部分保护基础上:
- 所有函数在开始时就被解析,GOT 表初始化为目标函数的最终地址,且标记为只读
- .got.plt[1]\.got.plt[2] 不会被写入 link_map、_dl_runtime_resolve 均为 0
![image-20210805233830391](../../../Library/Application Support/typora-user-images/image-20210805233830391.png)
攻击思路
无保护
伪造函数名称对应字符串所在地址
修改 .dynamic 段的 DT_STRTAB ,也就是篡改 .dynstr 段地址,将 .dynstr 劫持到可控区域进行伪造字符串表,让某个函数偏移在伪造字符串表上对应的字符串刚好是 system ,然后动态解析时调用的就是 system
这种攻击手法无论 32 位或者 64 位都适用
对应例题:
- [2015-xdctf-pwn200_no_relro_32](# 2015-xdctf-pwn200_no_relro_32)
部分保护
32位
伪造reloc_arg,伪造结构体
_dl_runtime_resolve 不会对第二个参数 reloc_arg(函数偏移)进行检查,也就是存在越界的问题。
- 设计一个 reloc_offset ,将函数重定向表劫持到可控区域(如.bss),在上面伪造 elf_rel (r_offset、r_info)
- 依据 r_info 信息,在对应区域内写入 fake elf_sym 结构,同时将 st_name 指向 fake 字符串
对应例题:
- [2015-xdctf-pwn200_relro_32](# 2015-xdctf-pwn200_relro_32)
64位
完全保护
ret2dl 无法利用
实例
无保护
2015-xdctf-pwn200_no_relro_32
题目 RELRO 保护全关,也就是 .dynamic 段有写入权限
1 | Arch: i386-32-little |
利用条件上也满足前面总结的无保护攻击利用思路:修改 .dynamic
的字符串表地址,伪造字符串表,这里选择 write 函数攻击,程序中其他函数也是可以的(read\setbuf)。
- 修改
.dynamic
的字符串表地址为伪造字符串表地址(可控的区域) - 构造 fake 字符串表,将 write 替换为 system
- 读取 /bin/sh
- 调用 write@plt[1] 指令,即与首次调用函数流程相同,调用 _dl_runtime_resolve 进行函数解析,将被攻击函数解析为 system
1 | #encoding:utf-8 |
2015-xdctf-pwn200_no-relro_64
与 32 位主要的差别是第三个参数无法控制,导致 read 读取的时候固定 0x100 的长度而导致需要写入多余内容将结构体中其他指针覆盖了。
所以需要用 ret2csu 王能 gadget 控制第三个参数, payload 冗长需要栈迁移到 bss 段上。
1 | #encoding:utf-8 |
2016-xman-level3_x64
这题是无保护版本,无保护题目思路都是修改 dynamic 表里面 dt_strtab 地址,将字符串表劫持到可控区域的伪造字符串表。
与 32 位区别就是控制第三个参数需要用 ret2csu 来控制,可能还需要进行栈对齐。
1 | #encoding:utf-8 |
这题到无法利用,system 进行 execve 调用返回结果是 -1 ,即调用失败。具体原因目前没有分析出来,当然这条题目也是可以用简单做法 ret2libc
![image-20210809223636351](../../../Library/Application Support/typora-user-images/image-20210809223636351.png)
![image-20210809224241524](../../../Library/Application Support/typora-user-images/image-20210809224241524.png)
部分保护
2015-xdctf-pwn200_relro_32
理解修改重定位表项的位置原理之后,用工具快速生成 payload :
1 | #encoding:utf-8 |
2016-xman-level3_x86
部分保护,直接用 pwntools 生成攻击
1 | #encoding:utf-8 |