Relro
Reading time: 9 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
Relro
RELRO 代表 Relocation Read-Only,这是链接器(ld
)实施的一种缓解措施,它在所有重定位应用后将 ELF 的数据段的一个子集设置为 只读。 其目的是阻止攻击者覆盖 GOT(全局偏移表) 或其他在程序执行期间被解引用的与重定位相关的表(例如 __fini_array
)中的条目。
现代链接器通过 重新排序 GOT(和其他几个部分)来实现 RELRO,使其位于 .bss 之前,并且最重要的是,通过创建一个专用的 PT_GNU_RELRO
段,该段在动态加载器完成应用重定位后被重新映射为 R–X
。 因此,典型的 .bss 中的缓冲区溢出不再能够到达 GOT,任意写入原语无法用于覆盖位于 RELRO 保护页面内的函数指针。
链接器可以发出 两级 保护:
Partial RELRO
- 使用标志
-Wl,-z,relro
(或在直接调用ld
时仅使用-z relro
)生成。 - 仅将 GOT 的 非 PLT 部分(用于数据重定位的部分)放入只读段。 需要在运行时修改的部分 – 最重要的是支持 懒绑定 的 .got.plt – 保持可写。
- 因此,任意写入 原语仍然可以通过覆盖 PLT 条目(或通过执行 ret2dlresolve)来重定向执行流。
- 性能影响微乎其微,因此 几乎每个发行版多年来都在发布至少具有部分 RELRO 的软件包(自 2016 年起,它是 GCC/Binutils 的默认设置)。
Full RELRO
- 使用 两个 标志
-Wl,-z,relro,-z,now
(也称为-z relro -z now
)生成。-z now
强制动态加载器提前解析 所有 符号(急切绑定),以便 .got.plt 不再需要被写入,并且可以安全地映射为只读。 - 整个 GOT、.got.plt、.fini_array、.init_array、.preinit_array 和一些额外的内部 glibc 表最终位于只读的
PT_GNU_RELRO
段中。 - 增加可测量的启动开销(所有动态重定位在启动时处理),但 没有运行时开销。
自 2023 年以来,几种主流发行版已切换为默认使用 Full RELRO 编译 系统工具链(和大多数软件包) – 例如 Debian 12 “bookworm” (dpkg-buildflags 13.0.0) 和 Fedora 35+。 因此,作为渗透测试人员,您应该预期遇到 每个 GOT 条目都是只读 的二进制文件。
如何检查二进制文件的 RELRO 状态
$ checksec --file ./vuln
[*] '/tmp/vuln'
Arch: amd64-64-little
RELRO: Full
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
checksec
(是 pwntools 和许多发行版的一部分)解析 ELF
头并打印保护级别。如果您无法使用 checksec
,请依赖 readelf
:
# Partial RELRO → PT_GNU_RELRO is present but BIND_NOW is *absent*
$ readelf -l ./vuln | grep -E "GNU_RELRO|BIND_NOW"
GNU_RELRO 0x0000000000600e20 0x0000000000600e20
# Full RELRO → PT_GNU_RELRO *and* the DF_BIND_NOW flag
$ readelf -d ./vuln | grep BIND_NOW
0x0000000000000010 (FLAGS) FLAGS: BIND_NOW
如果二进制文件正在运行(例如,一个 set-uid root 助手),你仍然可以通过 /proc/$PID/exe
检查可执行文件:
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
在编译自己的代码时启用 RELRO
# GCC example – create a PIE with Full RELRO and other common hardenings
$ gcc -fPIE -pie -z relro -z now -Wl,--as-needed -D_FORTIFY_SOURCE=2 main.c -o secure
-z relro -z now
适用于 GCC/clang(在 -Wl,
后传递)和直接使用 ld。 当使用 CMake 3.18+ 时,您可以通过内置预设请求完整的 RELRO:
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) # LTO
set(CMAKE_ENABLE_EXPORTS OFF)
set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,-z,relro,-z,now")
绕过技术
RELRO 级别 | 典型原语 | 可能的利用技术 |
---|---|---|
无 / 部分 | 任意写入 | 1. 重写 .got.plt 条目并转移执行。 2. ret2dlresolve – 在可写段中构造伪造的 Elf64_Rela 和 Elf64_Sym 并调用 _dl_runtime_resolve 。3. 重写 .fini_array / atexit() 列表中的函数指针。 |
完全 | GOT 是只读的 | 1. 寻找 其他可写代码指针(C++ vtables, __malloc_hook < glibc 2.34, __free_hook , 自定义 .data 段中的回调, JIT 页)。2. 滥用 相对读取 原语泄露 libc 并执行 SROP/ROP 进入 libc。 3. 通过 DT_RPATH/ LD_PRELOAD 注入恶意共享对象(如果环境由攻击者控制)或 ld_audit 。4. 利用 格式字符串 或部分指针重写来转移控制流而不触碰 GOT。 |
💡 即使是完全 RELRO,加载的共享库(例如 libc 本身)的 GOT 也是 仅部分 RELRO,因为这些对象在加载器应用重定位时已经被映射。如果你获得了一个 任意写入 原语,可以针对另一个共享对象的页面,你仍然可以通过重写 libc 的 GOT 条目或
__rtld_global
栈来转移执行,这是一种在现代 CTF 挑战中经常被利用的技术。
现实世界的绕过示例 (2024 CTF – pwn.college “enlightened”)
该挑战附带了完全 RELRO。利用了一个 越界 来破坏堆块的大小,通过 tcache poisoning
泄露了 libc,最后重写了 __free_hook
(在 RELRO 段外)并使用一个单一 gadget 获得代码执行。无需进行 GOT 写入。
最近的研究与漏洞 (2022-2025)
- glibc 2.40 废弃
__malloc_hook
/__free_hook
(2025) – 大多数利用这些符号的现代堆漏洞现在必须转向替代向量,如rtld_global._dl_load_jump
或 C++ 异常表。由于钩子位于 RELRO 之外,它们的移除增加了完全 RELRO 绕过的难度。 - Binutils 2.41 “最大页面大小” 修复 (2024) – 一个错误允许 RELRO 段的最后几个字节与某些 ARM64 构建中的可写数据共享一个页面,留下一个微小的 RELRO 缺口,可以在
mprotect
之后写入。上游现在将PT_GNU_RELRO
对齐到页面边界,消除了这个边缘情况。
参考文献
- Binutils 文档 –
-z relro
,-z now
和PT_GNU_RELRO
- “RELRO – 完全、部分和绕过技术” – 博客文章 @ wolfslittlered 2023
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。