引言

在 CTF (Capture The Flag) 的 Web 赛道中,信息泄露与代码审计是两大核心考点。这里将以一道经典的 PolarCTF 题目 [web]swp 为切入点,详细复盘从发现敏感文件、代码审计到构造 Payload 绕过的完整解题流程。同时,将对题目中涉及的底层机制(如 Vim 交换文件、PHP PCRE 回溯限制、PHP 弱类型)进行深度剖析,帮助大家建立举一反三的 Web 安全思维。

靶机地址:PolarD&N

实战复盘:PolarCTF [web]swp 解题全流程

发现敏感文件 (.swp 泄露)

  • 题目提示:题目名为 “swp”,指向 Vim 编辑器产生的临时交换文件(Swap file)。

    image-20260730122051950

  • 目录扫描:使用 dirsearch 对靶机地址进行扫描,发现隐藏文件 /.index.php.swp

    image-20260730122246092

  • 获取源码:浏览器直接访问该 .swp 文件并下载,虽然包含乱码,但可从中提取出核心的 PHP 源码。

    image-20260730122320455

代码审计与逻辑分析

恢复出的核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function jiuzhe($xdmtql){
return preg_match('/sys.*nb/is', $xdmtql);
}

$xdmtql = @$_POST['xdmtql'];

if(!is_array($xdmtql)){
if(!jiuzhe($xdmtql)){
if(strpos($xdmtql, 'sys nb') !== false){
echo 'flag{*******}';
}else{
echo 'true .swp file?';
}
}else{
echo 'nijilenijile';
}
}

逻辑拆解

要成功输出 flag,POST 参数 xdmtql 必须同时满足三个条件:

  1. 非数组!is_array($xdmtql) 为真。
  2. 正则匹配失败!jiuzhe($xdmtql) 为真,即 preg_match 必须返回 false
  3. 包含特定字符串strpos($xdmtql, 'sys nb') !== false 为真,即输入必须包含 sys nb

核心矛盾sys nb 本身完全符合正则 /sys.*nb/is 的规则。一旦输入该字符串,preg_match 必定返回 1(匹配成功),导致 !jiuzhe() 为假,程序走入拦截分支。

构造 Payload 破局

利用 PHP 的底层机制打破逻辑闭环:

1
2
3
4
5
6
7
8
9
10
11
12
import requests

url = 'http://2606a418-a36f-4d29-98a7-933bb42de047.www.polarctf.com:8090/'

# 构造超长字符串:'sys nb' + 25万个 'very'
# 总长度远超 100 万次回溯限制,足以让 preg_match 崩溃返回 false
data = {
'xdmtql': 'sys nb' + 'very' * 250000
}

r = requests.post(url=url, data=data)
print(r.text)

运行脚本后,正则引擎因超出回溯限制返回 false,成功绕过过滤,而 strpos 不受影响,最终打印出 flag。

核心知识点深度剖析

敏感信息泄露:版本控制与编辑器残留

这类漏洞的本质是**”配置不当导致源码或历史版本暴露”**。

  • Vim .swp 文件:Vim 在编辑文件时生成隐藏的交换文件(.<原文件名>.swp),用于防止意外断电导致内容丢失。若开发者异常退出,文件将遗留在 Web 目录下。攻击者可通过 vim -r .index.php.swp 恢复源码。
  • .git 泄露:Git 初始化生成的 .git 目录包含完整历史记录。利用 GitHack 工具,攻击者可解析底层对象,还原整个项目源码,甚至找回已被删除的密码或 flag。
  • .svn 泄露:SVN 的 .svn 目录包含 entrieswc.db 文件。利用 dvcs-ripperSeay 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!falsetrue,过滤直接被绕过。

PHP 弱类型与逻辑判断陷阱

PHP 的动态类型是无数 CTF 题目的万恶之源。

  • ==!== 的生死之差== 是宽松比较(会进行类型转换),=== 是严格比较(同时比较值和类型)。
  • 经典陷阱 (strpos):若代码为 if (strpos($url, 'http') == true),当 $url = 'http://evil.com' 时,strpos 返回 0。因为 0 == truefalse,导致校验失败。正确写法必须是 !== false
  • MD5 0e 漏洞:若代码为 if (md5($password) == $hash),攻击者可构造 MD5 值为 0e123456... 格式的字符串。PHP 在 == 比较时会将其识别为科学计数法的浮点数 0,从而实现碰撞绕过。

总结与防御建议

这道题的精髓在于:利用底层机制的缺陷(回溯限制)来打破应用层的逻辑闭环。在实际的 Web 安全防御中,建议采取以下措施:

  1. 规范开发流程:生产环境禁止使用 Vim 直接编辑代码,或配置将 .swp 文件存放在非 Web 目录下。
  2. 服务器安全配置:明确禁止访问隐藏目录(如 .git, .svn, .DS_Store),关闭目录遍历和错误回显(display_errors = Off)。
  3. 输入长度限制:使用正则过滤时,必须在匹配前强制限制输入长度,防止超长字符串触发回溯限制漏洞。
  4. 严格类型比较:在涉及安全校验、密码比对、权限判断的地方,无脑使用 ===!==,避免弱类型转换带来的逻辑漏洞。

CTF 实战条件反射指南

在做 CTF 题时,可以建立以下条件反射:

  1. 看到题目名或提示包含 swp, git, svn, bak立刻上 dirsearch 扫目录,找泄露
  2. 看到 preg_match 做过滤,且没有长度限制 → 立刻想到回溯限制绕过,构造超长 Payload
  3. 看到 == 比较,或者 strpos, md5立刻想到弱类型绕过(0e, 数组绕过, 类型转换)