[ pwn 学习 ] CTFshow-pwn0
2026-08-22 20:36:38

写在前面

大一上初涉 CTF,选择了先学习 Misc 这个板块。在我看来, Misc 恰似一款开放世界的沙盒游戏,随处都是彩蛋。它富有极大的趣味性,带来了密集的正反馈,在玩乐中把基础打扎实,也是我坚持打 CTF 直到现在的动力之一。

大一下过半开始接触 pwn。 一开始觉得自己的编程不好,对 pwn 畏惧。一直蜗牛一样慢吞吞地学一点点。后来我才明白。慢是最正常不过的,快反而是运气,或者是绝对的天赋。没必要过度焦虑了。

pwn 学习是借力打力——pwn 的本质不是写繁复的汇编语言,而是理解执行流。其实汇编语言不需要会太多。做 pwn 只需要认识这些指令、偏移量、栈、堆、程序段。上述指令已经覆盖了 90%的漏洞分析场景,剩下那 10%遇到现查就可以。

1
2
3
4
5
6
7
call  xxx      → 调用函数
lea eax, [ebp-xx] → 取局部变量地址
push xxx → 参数压栈
mov xxx → 赋值
cmp xxx → 比较
jmp/jz/jnz → 跳转
ret → 返回

506

长期坚持的秘诀其实是无视中断。搞砸了也要继续。中断不可怕,可怕的是中断之后就不再回来。人生和调试一样,断点是用来观察状态,调整寄存器的,不是用来停止进程的。一以贯之的努力,不得懈怠的人生。每天的微小积累会决定最终结果,这就是答案。

如果说 Misc 像沙盒游戏,那我觉得 pwn 像越狱……

一日一日地找图纸(理解程序逻辑),磨钥匙(构造 payload)你不需要会设计整个监狱(写大型工程),只需要知道狱警几点换岗,哪扇门没上电磁锁。最终在看似铜墙铁壁的牢房里打出/bin/sh的那扇暗门

C 语言函数

strcpy

C 语言最基础的字符串复制函数

1
2
3
4
5
strcpy(v0, a0)
│ │ │
│ │ └── 源头:从哪复制(你的输入)
│ └─────── 目标:复制到哪(栈上的缓冲区)
└────────────── string copy(字符串复制)

a0的内容 原封不动地复制到v0

1
2
3
4
5
6
7
8
9
10
11
// 假设 a0 = "hello"
strcpy(v0, "hello");

// 复制结果:
// v0[0] = 'h'
// v0[1] = 'e'
// v0[2] = 'l'
// v0[3] = 'l'
// v0[4] = 'o'
// v0[5] = '\x00' ← 自动补一个结束符

关键是它不知道什么时候停

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
strcpy 只有一个停止条件:碰到 \x00

v0 只有 66 格:
┌──── v0(66格) ────┬── 旧ebp(4格) ──┬── 返回地址(4格) ──┐
│ │ │ │
└───────────────────┴───────────────┴────────────────────┘

你输入 100'A'(不含 \x00):
┌──── 全填满 ───────┬── 全填满 ────┬── 全填满 ────────┐
│ AAAAAAAA... │ AAAAAAAA │ 0x41414141
└───────────────────┴───────────────┴────────────────────┘
↑ ↑
旧 ebp 坏了 返回地址 = 0x41414141

一返回就崩

做题时看到strcpy且 Canary 没开。第一反应就是:溢出,算偏移

pwn0

1
ssh ctfshow@pwn.challenge.ctf.show -p28110

等待程序跑完

1
2
cat /ctfshow_flag
# 把ctfshow_flag这个文件里的内容输出到终端

获得flag


相关笔记

  • pwn23 — strcpy 栈溢出实战(SIGSEGV 信号劫持)
  • pwn5 — ELF 结构与寄存器基础
  • pwn4 — 同样涉及 strcmp / strcpy 的入门题
  • pwn17 — 危险函数表(strcpy/strcat/gets/read
  • pwn24 — 栈溢出 → shellcode 注入(NX 关闭)
  • pwn25 ret2libc 栈溢出利用 (NX 绕过) — NX 开启时的 ret2libc 攻击
上一页
2026-08-22 20:36:38