本文仅用于技术研究,禁止用于非法用途。
Author:枷锁
pwn 017
题目描述
有些命令好像有点不一样?
不要一直等,可能那样永远也等不到flag
【题目核心】:利用 Linux 命令连字符绕过限制。
将题目拖入PWN机,开启模拟远程换环境
将 pwn 程序挂载在 12345 端口
socat TCP-LISTEN:12345,reuseaddr,fork EXEC:./pwn
解题过程:
先访问一下程序看看

根据题目给我们的提示,我们可以先进行尝试,看到3比较特别,我们试一试

提示Flag 不在这里
先checksec pwn检查程序

可以看到64位置,保护全开
拖入IDA,找到mian函数,F5反汇编C,查看关键部分

-
源码深入分析
通过 IDA 逆向分析 main 函数,我们可以看到一个 while(1) 循环构建的菜单。其中最值得关注的是 Case 2 和 Case 3:
- Case 3 的陷阱:程序会打印一堆提示文字,最后确实会执行 system("cat /ctfshow_flag")。但问题在于它中间穿插了大量的 sleep() 函数,最后一个 sleep 甚至长达数万秒。在远程连接中,你根本等不到它执行完就会断开。
- Case 2 的漏洞:
- 程序提示:Which directory?
- 使用 read(0, &buf, 0xAuLL) 读取用户输入,限制为 10 字节。
- 关键动作:strcat(dest, &buf),其中 dest 预设了初始命令(通常是 ls )。
- 执行:system(dest)。
漏洞点:程序没有对用户输入的 buf 进行任何过滤,就直接拼接到命令字符串 dest 中执行。这就构成了典型的命令注入(Command Injection)。
攻击思路:分号截断
在 Linux Shell 中,分号 ; 是命令分隔符。执行 cmd1 ; cmd2 时,系统会先执行 cmd1,无论成功与否,接着执行 cmd2。
-
构造 Payload:;cat /ctf*
-
长度检查:;cat /ctf* 一共 9 个字符,完美契合 read 的 10 字节限制。
-
执行效果: 程序实际执行的命令变为 ls ;cat /ctf*。
-
系统先执行 ls(列出当前目录)。
-
接着执行 cat /ctf*。

进阶技巧:通配符 *
为什么用 /ctf* 而不是 /ctfshow_flag?
其他可用 Payload:
-
;/bin/sh:直接弹回一个 shell(8 字节),拿到 shell 后想干什么都行。

知识点小结
- ;:顺序执行多条命令。
- &:让前一个命令后台运行,接着执行后面的命令。
- &&:只有前一个命令成功执行,才执行后面的命令。
- ||:只有前一个命令执行失败,才执行后面的命令。
- *:匹配任意长度字符的通配符。
pwn 018
题目描述
仔细看看源码,或许有惊喜
假作真时真亦假,真作假时假亦真
将题目拖入PWN机,开启模拟远程换环境
将 pwn 程序挂载在 12345 端口
socat TCP-LISTEN:12345,reuseaddr,fork EXEC:./pwn
解题过程:
【题目核心】:理解 > 与 >> 的区别。
先checksec pwn检查程序

可以看到64位置,保护全开
拖入IDA,找到mian函数,F5反汇编C,查看关键部分

fake():
](https://www.171host.com/wp-content/uploads/2026/01/20260115161353-696912414628d.png)
real():

源码逻辑拆解
程序会问你一个直击灵魂的问题:“Which is the real flag?”。 随后让你输入一个数字,根据输入进入不同的函数:
- 如果你输入 9:调用 fake() 函数。 执行命令:system("echo 'flag is here' >> /ctfshow_flag")
- 如果你输入其他:调用 real() 函数。 执行命令:system("echo 'flag is here' > /ctfshow_flag")
最后,程序都会统一执行:system("cat /ctfshow_flag")。
关键:> vs >> 的生死时速
很多人看到 real() 函数就想往里冲,但这就是出题人的“逻辑陷阱”。我们来看看这两个符号的本质区别:
| > | 覆盖重定向 | 先清空目标文件的内容,再写入新数据。 | 毁灭性:原来的真 Flag 直接被删了 |
| >> | 追加重定向 | 在目标文件的末尾添加数据,保留原内容。 | 保护性:真 Flag 还在,只是后面多了一行。 |
为什么说“假的是真的”?
解题总结:这是一个经典的逻辑博弈。在 PWN 中,不仅要看代码逻辑,还要看代码对**环境(文件系统)**造成的副作用。记住:覆盖(>)是不可逆的,追加(>>)才是正确的选项。
解析
-
> (覆盖):会把文件原来的内容清空,写进新内容。
-
>> (追加):在文件末尾添加内容,保留原内容。 为了不让原有的 Flag 被删掉,我们必须选 9。

pwn 019
题目描述
关闭了输出流,一定是最安全的吗?
将题目拖入PWN机,开启模拟远程换环境
将 pwn 程序挂载在 12345 端口
socat TCP-LISTEN:12345,reuseaddr,fork EXEC:./pwn
解题过程:
【题目核心】:当程序关闭了标准输出流(stdout)时,如何通过重定向找回丢失的 Flag。
尝试连接一下

没有明显提示,先checksec pwn检查程序

可以看到64位置,保护全开
拖入IDA,找到mian函数,F5反汇编C,查看关键部分


通过 IDA 观察,这一关的代码逻辑非常有意思:

fork() 进程分身:程序创建了一个子进程。
父进程:只是简单地等待并打印“flag is not here”。
子进程(重点):

-
执行了 fclose(); —— 关键点! 这一行直接把程序的“嘴”封上了。
-
执行了 read(0, &buf, 0x20); —— 给你 32 字节的机会输入命令。
-
执行了 system(&buf); —— 执行你的命令。
困境:即使输入 cat /ctfshow_flag,由于 stdout(标准输出)已经被 fclose 关闭了,Flag 内容会从文件读入内存,但无法吐到屏幕上。

前置知识:什么是文件描述符(FD)?
在 Linux 看来,一切皆文件。程序每打开一个流,都会分配一个数字编号:
- 0 (stdin):标准输入,相当于程序的“耳朵”(听你输入)。
- 1 (stdout):标准输出,相当于程序的“嘴巴”(打印给你看)。
- 2 (stderr):标准错误,相当于程序的“求救声”(打印错误信息)。
在本题中,1号管子(嘴巴) 被拔掉了。但幸运的是,0号管子(耳朵) 还在,而且它是双向的(在 Socket 连接中,stdin 和 stdout 往往指向同一个双工通道)。
破局逻辑:水管重定向接头
既然“嘴巴”(1)没了,我们就把数据强行塞进“耳朵”(0)里传出去。
Payload:exec cat /ctf* 1>&0

我们将这个 Payload 拆解来看:
exec:这个命令会用新的进程(这里是 cat)替换当前的 shell 进程。这能确保文件描述符的改动在当前环境中立即生效。
cat /ctf*:读取 Flag 的常规操作。
1>&0:这就是我们的“骚操作”。
-
1 代表标准输出。
-
> 代表重定向。
-
&0 代表文件描述符 0。
pwn 020
题目描述
提交ctfshow{【.got表与.got.plt是否可写(可写为1,不可写为0)】,【.got的地址】,【.got.plt的地址】}
例如 .got可写.got.plt表可写其地址为0x400820 0x8208820
最终flag为ctfshow{1_1_0x400820_0x8208820}
若某个表不存在,则无需写其对应地址
如不存在.got.plt表,则最终flag值为ctfshow{1_0_0x400820}
解题过程:
【题目核心】:通过手动分析 ELF 文件的节头(Section Header),判断程序是否开启了 RELRO 保护,并找到 GOT 表的精确地址。
前置硬核知识:程序是怎么“认路”的?
当程序想要调用 puts() 函数时,它其实并不知道这个函数在动态链接库(libc)里的确切地址。它需要查两张表:
漏洞点:如果这本“电话簿”(GOT表)是可写的,黑客就可以把 puts() 的地址涂掉,换成 system() 的地址。这样程序只要一调用 puts,实际上执行的就是 system 了。这种攻击叫 GOT Hijacking(GOT 劫持)。
什么是 RELRO 保护?
为了对付 GOT 劫持,RELRO (RELocation Read-Only) 应运而生。
RELRO(RELocation Read-Only)是一种可选的二进制保护机制,用于增加程序的安全性。它主要
通过限制和保护全局偏移表(Global Offset Table,简称 GOT)和过程链接表(Procedure Linkage
Table,简称 PLT)的可写性来防止针对这些结构的攻击。
它有三种等级:
- No RELRO:电话簿完全不设防,你想怎么改就怎么改。.got 和 .got.plt 都是 WA (可写)。
- Partial RELRO(部分保护):电话簿的一部分(如编译信息)被锁死,但关键的函数跳转部分 .got.plt 还是 WA (可写)。
- Full RELRO(全保护):电话簿在程序启动时就彻底焊死了。整个 GOT 表都是 R (只读)。任何修改都会导致程序崩溃。
实战:如何解开 PWN 020?
本题要求提交:ctfshow{可写状态_地址_地址}。我们需要分两步走:
第一步:检查保护状态
使用 PWN 选手的必备神器 checksec:
checksec pwn

输出显示 RELRO: No RELRO,说明这间房子的门是开着的,所有的表都可写。那么“可写状态”就是 1。
第二步:寻找表的地址
我们需要查阅 ELF 文件的“户口本”。使用 readelf 命令查看所有的节(Sections):
readelf -S pwn

在输出的大表中,寻找以下两项:

第三步:利用程序行为进行验证
这一关的 pwn 程序其实是一个“写入测试器”。它接受一个地址作为参数,并尝试往这个地址写入字符串 "RELR"。

- 可写情况: 运行 ./pwn 0x600f18,程序会尝试把 "RELR" 写进去。 如果成功了,它会打印出该地址的内容:RELRO: 52454c52。 注:52 45 4c 52 分别是 ‘R’, ‘E’, ‘L’, ‘R’ 的 ASCII 码十六进制表示。
- 不可写情况: 如果你尝试往一个只读地址写入,Linux 内核会立即介入并抛出 Segmentation Fault(段错误),程序会直接崩溃。
第四步:Flag 构造总结
Flag 的构造逻辑是:ctfshow{状态1_状态2_地址1_地址2}。
- 状态位:可写填 1,不可写填 0。
- 顺序:第一个是 .got 的信息,第二个是 .got.plt 的信息。
那么最终 Flag 拼接结果: ctfshow{1_1_0x600f18_0x600f28}
小结:系统级思考
宇宙级免责声明
🚨 重要声明:本文仅供合法授权下的安全研究与教育目的!🚨
1.合法授权:本文所述技术仅适用于已获得明确书面授权的目标或自己的靶场内系统。未经授权的渗透测试、漏洞扫描或暴力破解行为均属违法,可能导致法律后果(包括但不限于刑事指控、民事诉讼及巨额赔偿)。
2.道德约束:黑客精神的核心是建设而非破坏。请确保你的行为符合道德规范,仅用于提升系统安全性,而非恶意入侵、数据窃取或服务干扰。
3.风险自担:使用本文所述工具和技术时,你需自行承担所有风险。作者及发布平台不对任何滥用、误用或由此引发的法律问题负责。
4.合规性:确保你的测试符合当地及国际法律法规(如《计算机欺诈与滥用法案》(CFAA)、《通用数据保护条例》(GDPR)等)。必要时,咨询法律顾问。
5.最小影响原则:测试过程中应避免对目标系统造成破坏或服务中断。建议在非生产环境或沙箱环境中进行演练。
6.数据保护:不得访问、存储或泄露任何未授权的用户数据。如意外获取敏感信息,应立即报告相关方并删除。
7.免责范围:作者、平台及关联方明确拒绝承担因读者行为导致的任何直接、间接、附带或惩罚性损害责任。
🔐 安全研究的正确姿势:
✅ 先授权,再测试
✅ 只针对自己拥有或有权测试的系统
✅ 发现漏洞后,及时报告并协助修复
✅ 尊重隐私,不越界
⚠️ 警告:技术无善恶,人心有黑白。请明智选择你的道路。
布平台不对任何滥用、误用或由此引发的法律问题负责。
4.合规性:确保你的测试符合当地及国际法律法规(如《计算机欺诈与滥用法案》(CFAA)、《通用数据保护条例》(GDPR)等)。必要时,咨询法律顾问。
5.最小影响原则:测试过程中应避免对目标系统造成破坏或服务中断。建议在非生产环境或沙箱环境中进行演练。
6.数据保护:不得访问、存储或泄露任何未授权的用户数据。如意外获取敏感信息,应立即报告相关方并删除。
7.免责范围:作者、平台及关联方明确拒绝承担因读者行为导致的任何直接、间接、附带或惩罚性损害责任。
🔐 安全研究的正确姿势:
✅ 先授权,再测试
✅ 只针对自己拥有或有权测试的系统
✅ 发现漏洞后,及时报告并协助修复
✅ 尊重隐私,不越界
⚠️ 警告:技术无善恶,人心有黑白。请明智选择你的道路。
希望这个教程对你有所帮助!记得负责任地进行安全测试。

