file_get_contents与trim组合漏洞解析
TOPIC SOURCE
对方不想和你说话并扔了一段代码
在一次 CTF 赛后复盘时,团队发现一道题目只用了两行 PHP 代码,却让选手们在几分钟内完成了全局变量注入和文件读取的组合攻击。核心代码是 $c = trim(file_get_contents($b));,看似普通的输入过滤,却在特定的 $b 取值下把整个读取结果清空,从而绕过后续的空值检查。
漏洞成因剖析
PHP 的 file_get_contents 可以接受本地路径、URL 甚至 php://input 等包装协议,只要传入的字符串合法就会把目标内容直接返回。随后 trim 默认去除两端的空白字符、换行、制表符和 Unicode 的空格符。如果读取的文件恰好只包含这些字符,trim 的返回值便是空字符串。
攻击者只需控制 $b,将其指向一个仅包含空白的文件(例如 /tmp/blank.txt),或者利用 php://filter 包装把原始内容全部过滤掉,trim 便把返回值压成 ''。随后代码中常见的 if ($c) 检查就会失效,导致后续逻辑误以为读取失败,从而触发错误信息泄露或默认路径 fallback,进而执行任意文件包含。
利用链路示例
<?php
// 漏洞片段
$b = $_GET['file']; // 可控参数
$c = trim(file_get_contents($b)); // 关键点
if ($c) {
// 正常业务处理
echo "Data: ".$c;
} else {
// 触发错误路径,包含 flag.php
include 'flag.php';
}
?>
利用者把 file 参数设为 php://filter/convert.base64-encode/resource=flag.php,读取的原始二进制会被 Base64 编码后返回。因为编码结果以字母和数字组成,不会被 trim 剔除,$c 非空,导致 if 分支走向正常路径,进而把 flag 直接打印出来。
防御建议
- 严禁直接把用户输入传给
file_get_contents,应使用白名单校验或固定目录前缀。 - 对返回值进行内容完整性检查,而非仅靠
trim判断空值。 - 禁用不必要的包装协议(如
php://filter、data),或在php.ini中关闭allow_url_fopen。 - 在关键路径使用
realpath与is_file双重验证,防止路径遍历。
把这些细节写进代码审计清单,哪怕是看似无害的 trim,也能在特定场景下成为攻防的分水岭。别再掉进同样的坑了。

参与讨论
暂无评论,快来发表你的观点吧!