[ pwn 学习 ] CTFshow-pwn22 Full RELRO
1. 基础信息

Full RELRO,.got 和 .got.plt 都不可写。
思路是直接放弃延迟绑定,启动时一次性查完所有函数地址填好,然后把整本电话簿焊死。
2. Full RELRO 的两个标志
2.1 BIND_NOW — 立刻绑定
1 | readelf -d pwn22 | grep -i "bind\|flags" |

BIND_NOW 告诉动态链接器:程序启动时就把所有函数地址全部查完,不要等第一次调用再查。 这是 Full RELRO 的硬性标志。pwn20 和 pwn21 没有这一项。
2.2 .got.plt 消失了
1 | readelf -S pwn22 | grep -A 1 "\.got" |

只有一张 .got 表,没有 .got.plt。
既然不搞延迟绑定了,那张留给链接器填地址的 .got.plt 表也就没存在的必要了——所有函数指针直接合进 .got 里,一次性填完就锁。
3. GNU_RELRO — 把 .got 也锁死
1 | readelf -l pwn22 |

保护区范围:[0x600dc0, 0x600dc0 + 0x240) = [0x600dc0, 0x601000)
对照段地址:
1 | 保护区:[0x600dc0 ───────────── 0x601000) |
Section to Segment 映射确认:

GNU_RELRO 把 .got 也罩住了。启动后 mprotect 一把锁死,谁来写谁段错误。
对比 pwn21(Partial RELRO):pwn21 的保护区到 0x601000,.got.plt 刚好在边界外逃过一劫。pwn22 没有 .got.plt,.got 被牢牢圈住。
4. 解题
Full RELRO+ 无.got.plt→.got不可写(0)、.got.plt不存在/不可写(0).got地址 →0x600fc0
1 | ctfshow{0_0_0x600fc0} |
5. 三题对比速查
| pwn20 No RELRO | pwn21 Partial | pwn22 Full | |
|---|---|---|---|
| GNU_RELRO | ❌ | ✅ | ✅ |
| BIND_NOW | ❌ | ❌ | ✅ |
| .got.plt 存在? | ✅ | ✅ | ❌ 消失了 |
| .got 可写 | ✅ 1 | ❌ 0 | ❌ 0 |
| .got.plt 可写 | ✅ 1 | ✅ 1 | ❌ 0 |
| GOT 劫持 | 随便搞 | 只能搞 .got.plt | 💀 彻底没门 |
| Flag | {1_1_0x..._0x...} |
{0_1_0x..._0x...} |
{0_0_0x...} |