[ pwn 学习 ] CTFshow-pwn21
2026-08-22 20:36:38
pwn21
1.基础信息

和 pwn20 唯一区别:RELRO从No RELRO变成了Partial RELRO
2. 回顾:RELRO 三等级
做 pwn20 已经了解:
| 等级 | .got 能写? |
.got.plt 能写? |
|---|---|---|
No RELRO |
✅ | ✅ |
| Partial RELRO | ❌** ** | ✅** ** |
Full RELRO |
❌ | ❌ |
Partial RELRO 的取舍逻辑:
.got** 里的数据初始化后不会再变 → 锁掉。**
.got.plt** 因为延迟绑定还要填函数地址 → 留着能写。**
3.找两张表的地址
段表**(-S)**说的都能写。别信
程序头**(-l)里GNU_RELRO**圈起来那块 运行时会被锁成只读
3.1readelf -S 先看段表
用readelf -S pwn21可以先看一下各个段的分布
段表里两张表都是WA(可写)但是不可信。
段表是静态声明,运行时程序由程序头决定。

| 段名 | 地址 | 说明 |
|---|---|---|
.init_array |
0x600e10 | 初始化函数指针数组 |
.fini_array |
0x600e18 | 析构函数指针数组 |
.dynamic |
0x600e20 | 动态链接信息 |
.got |
0x600ff0 | 杂项数据(全局变量地址等) |
.got.plt |
0x601000 | 外部函数地址表 |
3.2readelf -l 再看程序头(真正权限)
真正决定保护范围的是程序头里的GNU_RELRO段
readelf -l pwn21
关键一行

| 字段 | 值 | 含义 |
|---|---|---|
| VirtAddr | 0x600e10 | 保护区起始地址 |
| MemSiz | 0x1f0 | 保护区大小 = 496 字节 |
| Flags | R | 只读权限 |
保护区范围=[0x600e10,0x60010+0x1f0)=[0x600e10,0x601000)
现在把这个范围和段地址一一对照
保护区范围
1 | 保护区范围:[0x600e10 —————————— 0x601000) |
Section to Segment 映射也验证了这点:

GNU_RELRO段不包含.got.plt
4.解题
Partial RELRO→.got不可写(0)、.got.plt可写(1).got地址 →0x600ff0.got.plt地址 →0x601000
1 | ctfshow{0_1_0x600ff0_0x601000} |
相关笔记
RELRO 三部曲:
关键工具:
- pwn1 —
checksec快速看保护等级 - pwn25 ret2libc 栈溢出利用 (NX 绕过) — Partial RELRO 下的 GOT 泄露