Web 实战笔记:从 Vim 源码泄露到 PHP 回溯限制绕过
引言
在 CTF (Capture The Flag) 的 Web 赛道中,信息泄露与代码审计是两大核心考点。这里将以一道经典的 PolarCTF 题目 [web]swp 为切入点,详细复盘从发现敏感文件、代码审计到构造 Payload 绕过的完整解题流程。同时,将对题目中涉及的底层机制(如 Vim 交换文件、PHP PCRE 回溯限制、PHP 弱类型)进行深度剖析,帮助大家建立举一反三的 Web 安全思维。
靶机地址:PolarD&N
实战复盘:PolarCTF [web]swp 解题全流程
发现敏感文件 (.swp 泄露)
题目提示:题目名为 “swp”,指向 Vim 编辑器产生的临时交换文件(Swap file)。

目录扫描:使用
dirsearch对靶机地址进行扫描,发现隐藏文件/.index.php.swp。
获取源码:浏览器直接访问该
.swp文件并下载,虽然包含乱码,但可从中提取出核心的 PHP 源码。
代码审计与逻辑分析
恢复出的核心代码如下:
1 | function jiuzhe($xdmtql){ |
逻辑拆解:
要成功输出 flag,POST 参数 xdmtql 必须同时满足三个条件:
- 非数组:
!is_array($xdmtql)为真。 - 正则匹配失败:
!jiuzhe($xdmtql)为真,即preg_match必须返回false。 - 包含特定字符串:
strpos($xdmtql, 'sys nb') !== false为真,即输入必须包含sys nb。
核心矛盾:sys nb 本身完全符合正则 /sys.*nb/is 的规则。一旦输入该字符串,preg_match 必定返回 1(匹配成功),导致 !jiuzhe() 为假,程序走入拦截分支。
构造 Payload 破局
利用 PHP 的底层机制打破逻辑闭环:
1 | import requests |
运行脚本后,正则引擎因超出回溯限制返回 false,成功绕过过滤,而 strpos 不受影响,最终打印出 flag。
核心知识点深度剖析
敏感信息泄露:版本控制与编辑器残留
这类漏洞的本质是**”配置不当导致源码或历史版本暴露”**。
- Vim
.swp文件:Vim 在编辑文件时生成隐藏的交换文件(.<原文件名>.swp),用于防止意外断电导致内容丢失。若开发者异常退出,文件将遗留在 Web 目录下。攻击者可通过vim -r .index.php.swp恢复源码。 .git泄露:Git 初始化生成的.git目录包含完整历史记录。利用 GitHack 工具,攻击者可解析底层对象,还原整个项目源码,甚至找回已被删除的密码或 flag。.svn泄露:SVN 的.svn目录包含entries或wc.db文件。利用 dvcs-ripper 或 Seay SVN 工具可批量提取源码。- 备份文件泄露 (
.bak/.old):开发者习惯在修改代码前备份。若未删除,攻击者可直接下载旧版代码,寻找已修复的漏洞或硬编码的密钥。 .DS_Store泄露:macOS 自动生成的隐藏文件,记录了当前目录的文件结构。利用 ds_store_exp 解析,可枚举出隐藏的后台目录(如/admin_xxx/)。
PHP PCRE 回溯限制绕过 (Backtrack Limit Bypass)
这是 PHP 独有的底层机制漏洞,在 CTF 中极高频出现。
- 底层原理:PHP 的正则引擎(PCRE)在处理贪婪量词(如
.*)时会进行回溯。为防止 ReDoS(正则表达式拒绝服务)攻击,PHP 在php.ini中设置了pcre.backtrack_limit = 1000000(100万次)。 - 致命缺陷:当回溯次数达到上限时,PCRE 引擎会主动放弃匹配,并返回
false(布尔值),而不是0(未匹配)。 - 利用姿势:若代码使用
if (!preg_match('/dangerous/i', $input))做安全过滤,只要$input长度超过 100 万字符,preg_match就会返回false,!false为true,过滤直接被绕过。
PHP 弱类型与逻辑判断陷阱
PHP 的动态类型是无数 CTF 题目的万恶之源。
==与!==的生死之差:==是宽松比较(会进行类型转换),===是严格比较(同时比较值和类型)。- 经典陷阱 (strpos):若代码为
if (strpos($url, 'http') == true),当$url = 'http://evil.com'时,strpos返回0。因为0 == true为false,导致校验失败。正确写法必须是!== false。 - MD5
0e漏洞:若代码为if (md5($password) == $hash),攻击者可构造 MD5 值为0e123456...格式的字符串。PHP 在==比较时会将其识别为科学计数法的浮点数0,从而实现碰撞绕过。
总结与防御建议
这道题的精髓在于:利用底层机制的缺陷(回溯限制)来打破应用层的逻辑闭环。在实际的 Web 安全防御中,建议采取以下措施:
- 规范开发流程:生产环境禁止使用 Vim 直接编辑代码,或配置将
.swp文件存放在非 Web 目录下。 - 服务器安全配置:明确禁止访问隐藏目录(如
.git,.svn,.DS_Store),关闭目录遍历和错误回显(display_errors = Off)。 - 输入长度限制:使用正则过滤时,必须在匹配前强制限制输入长度,防止超长字符串触发回溯限制漏洞。
- 严格类型比较:在涉及安全校验、密码比对、权限判断的地方,无脑使用
===和!==,避免弱类型转换带来的逻辑漏洞。
CTF 实战条件反射指南
在做 CTF 题时,可以建立以下条件反射:
- 看到题目名或提示包含
swp,git,svn,bak→ 立刻上 dirsearch 扫目录,找泄露。 - 看到
preg_match做过滤,且没有长度限制 → 立刻想到回溯限制绕过,构造超长 Payload。 - 看到
==比较,或者strpos,md5→ 立刻想到弱类型绕过(0e, 数组绕过, 类型转换)。









