[ 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
2
3
4
5
6
7
8
保护区范围:[0x600e10 —————————— 0x601000)
↑ ↑
.init_array(0x600e10) 边界线
.fini_array │
.dynamic │
.got (0x600ff0) ────────────┘ ← 在保护区内,重定位后 → 只读 ❌

.got.plt (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 三部曲:

  • pwn20 — No RELRO:两张表都可写,随意 GOT 劫持
  • pwn22 — Full RELRO:全部锁死

关键工具:

  • pwn1 — checksec 快速看保护等级
  • pwn25 ret2libc 栈溢出利用 (NX 绕过) — Partial RELRO 下的 GOT 泄露
上一页
2026-08-22 20:36:38
下一页