冰蝎,从入门到魔改

访客4年前关于黑客接单891

0x01 什么是冰蝎?

"冰蝎"是一个动态二进制加密网站管理客户端。在实战中,之一代webshell管理工具"菜刀"的流量特征非常明显,很容易就被安全设备检测到。基于流量加密的webshell变得越来越多,"冰蝎"在此应运而生。
image
"冰蝎"客户端基于JAVA,所以可以跨平台使用,最新版本为v2.0.1,兼容性较之前的版本有较大提升。主要功能为:基本信息、命令执行、虚拟终端、文件管理、Socks *** 、反弹shell、数据库管理、自定义代码等,功能非常强大。

0x02 加密原理

我们以PHP版本为例,"冰蝎"在服务端支持open_ssl时,使用AES加密算法,密钥长度16位,也可称为AES-16。此在软件及硬件(英特尔处理器的AES指令集包含六条指令)上都能快速地加解密,内存需求低,非常适合流量加密。

加密流程大致如下图所示:

image

首先客户端以Get形式发起带密码的请求。

服务端产生随机密钥,将密钥写入Session并将密钥返回客户端。

客户端获取密钥后,将payload用AES算法加密,用POST形式发送请求。

服务端收到请求,用Session中的密钥解密请求的Body部分,之后执行Payload,将直接结果返回到客户端。

客户端获取返回结果,显示到UI界面上。

我们看到在图中,"冰蝎"在执行Payload之后的返回,并没有显示加密,这点我们可以从自带的webshell中看出。

image

image

这个问题需要解密一下"冰蝎"的流量,才能知道答案。

0x03 通信过程

我们用wireshark来抓包看下"冰蝎"通信过程:

image

从抓包结果上粗略来看,加密效果是不错的,全程基本没有可读的执行代码。

我们用服务端返回的密钥,对客户端发送的报文内容进行解密。

解密结果为如下代码:

image

我们发现核心内容只是一个简单的 *** ON格式的success的返回,但是会将结果使用AES包装一层加密,所以我们看到webshell中没有加密,而流量却是加密的。

0x04 时过境迁

攻防技术一直都在不断发展的,要想保证攻防的持续有效,就需要不断地更新自我。"冰蝎"的最新版本v2.0.1,在发布于2019.2之后就没有进行过更新。而各大厂商的检测系统及WAF均已经对其特征进行分析并加入规则。

image

image

各路分析其流量规则的文章也层出不穷。

image

原版"冰蝎"已经不能满足攻防对战的要求了,这时我们需要自己动手。

image

0x05 魔改准备

首先用JD-GUI等反编译工具,反编译JAR包获得源码。可以从中可以看到UI文件引入的包名看到,"冰蝎"使用了SWT框架作为UI。

image

既然这样我们直接用Eclipse安装WindowsBuilder,来直接创建SWT项目。

安装WindowsBuilder

在Eclipse的Marketplace里搜索WindowsBuilder,点击Install即可安装。

image

之后我们直接创建基于SWT项目,即可避免因swt包缺失导致的报错问题。

image

我们将反编译之后的源码和JAR包导入项目,在通过搜索源码和修复报错(会有一 *** 报错等待你修复,可以多种反编译工具对比结果来修改)等方式尝试将源码跑起来。

image

最终我们终于成功跑起来了反编译之后的代码。

image

可以看到项目结构比较简单清晰,主要逻辑都在net包下,Main.java为程序入口。这里简单介绍下各个模块代码的作用:

image

出于对原作者的瑞思拜,不会放出任何项目文件。

image

0x06 特征擦除

经过对网上多篇对"冰蝎"特征的资料参考,总结出几条特征并将其特征给予修改擦除。以PHP版本为例,其他语言版本异曲同工。

1.密钥交换时的URL参数

首当其冲的就是密钥交换时的参数,用GET请求方式,默认webshell的密码为pass,并且参数值为3位随机数字。

image

从webshell上看,参数值的随机数字并没有任何实际作用:

image

客户端代码上看也只是随机数:
image

我们来看下一般对此情况的检测规则:

该规则可以匹配1-10位密码的webshell,并且参数值位2-3位的数字。

修改思路:

增加随机数量的随机参数和随机值(随机值不为全数字),并且密码参数不能固定为之一个。

修改后的效果:

image

2.header中的Content-Type

默认在header中的Content-type字段,在一般情况下的GET形式访问是没有该字段的,只有POST形式的访问才会有。但"冰蝎"不论是GET形式还是POST形式的访问均包含此字段。此处露出了较大破绽,而且该字段的大小写有点问题,所以基于这个规则基本可以秒杀。

image

我们来看下这块相关的的代码:

image

ShellService代表一个Shell服务,在其构造函数中31行判断了,如果类型是php则在header中加入
Content-type
头。但在35行的getKeyAndCookie向服务端发送GET请求获取密钥时,也将此header头带入其中,所以发送GET请求包时也会携带此参数。

修改思路:

GET形式访问时在header中去掉此字段,POST形式访问时将值改为
Content-Type值改为"text/html;
charset=utf-8"以规避安全检测(值也可以不改)。

修改后的效果:

GET请求:

image

POST请求:

image

3.header中的User-Agent

User-Agent是代表一般指用户 *** ,会包含浏览器和操作系统等信息标志。在"冰蝎"的早期版本存在User-Agent特例化问题,最新版本已经解决了这个问题。解决方案是:每个shell连接会从17个内置的UA里随机选择一个。

image

来看下这部分的JAVA代码:

image

可以看到是随机从常量Constants.userAgents中取了一个值。

image

这块的问题是UA包含的浏览器版本比较旧,比如:Chrome/14.0.835.163是2011年发布的版本,Firefox/6.0也是2011年的版本。这种浏览器基本很少人使用,所以特征较为明显,可以作为规则参考。

修改思路:

使用较新版本的常见浏览器UA来替换内置的旧的UA常量。

修改后的效果:

2020年发布的Firefox 75.0:

image

2019年11月发布的Chrome 78.0.3904.108:

image

4.header中的Accept

在请求header中的Accept字段默认会是一个比较奇怪的值,此值在GET形式和POST形式的请求中均存在。而在正常的浏览器或其他设备访问的报文中Accept的值不会是这样的,所以此处也可以作为一个强力有效的规则检测依据。

GET请求:

image

POST请求:

image

此处产生的原因是JAVA的HTTPURLConnection库("冰蝎"使用的HTTP通信库)在没有设置Accept值时会自动设置该值作为默认值,而源码中默认并没有对Accept进行处理。

修改思路:

修改请求header中的Accept的值。

修改后的效果:

GET请求:

image

POST请求:

image

5.二次密钥获取

在"冰蝎"的默认流量中,会有两次通过GET形式的请求获取密钥的过程,这点比较奇怪。

此处也可作为一个检测点。

image

我们来看下代码实现:

image

这一步是将密钥存入rawkey_1变量中。

image

再次获取的密钥存到rawkey_2变量中,之后rawkey_1和rawkey_2进行了异或操作,通过异或结果来判从而结束循环条件,最多尝试获取10次密钥。实话说这块代码没太看出来作用,实际是大部分情况2次就OK了,3次获取密钥的情况都不太多。个人感觉这块是为了校验获取到的密钥是否可用以及控制获取密钥的次数。

修改思路:

删掉多次获取密钥的过程,可以改成一次获取密钥。或者直接把密钥写到webshell里,省去获取密钥的过程。

修改后的效果:

image

6.response中返回密钥

在获取密钥时,密钥返回是直接以16位字符的形式返回到客户端。这时会有比较大的破绽,我们来看下常用的检测规则:

检测内容是:以两个\r 完整换行加上16位字母小写+数字组合为结尾,再配合Content-Length:
16 为规则一起检测。

image

我们来看下客户端代码对于密钥的匹配规则:
image

源码只匹配了16位的字母a-f大小写+数字,hah~ 这是因为啥呢???

image

原因在"冰蝎"默认自带的webshell里:

image

因为webshell
生成的密码算法为md5,md5输出结果显示是16进制,所以只有0-9a-f。

修改思路:

GET形式访问时,可以加入一些混淆的返回内容,或者将密钥变型。

修改后的效果:

可以先从视觉效果上隐藏起来:

image

流量侧:

image

这里只是简单的加了一些内容作为演示,实战时可以根据情况混淆。

7.header中的Cookie

因为"冰蝎"默认自带的webshell中的key在将密钥返回客户端后,会将密钥保存在Session中。而SessionId在之一次客户端请求时作为Cookie发送给了客户端,所以Cookie也是作为我们一个重要检查点。

image

Cookie中的问题是"path=/"这部分。在访问服务器时,服务端将Cookie以Set-Cookie的response头中的形式返回,其中Path是该Cookie的应用路径。

举个例子:

Cookie1; Path=/

Cookie2; Path=/admin/

当浏览器访问网站 "/" 路径时,只会携带Cookie1。当访问 "/admin/"
路径时,会同时携带Cookie1和Cookie2。

在正常浏览器访问下,path是不会作为Cookie本身的一部分发送到服务端的。

来看下客户端代码:

image

此处将服务端返回的Cookie所有字符都在客户端存储起来,当客户端发送请求时全部将这些字符作为Cookie发送出去。

修改思路:

将发送请求中Cookie的Path字段去掉。

修改后的效果:

image

0x07 总结

在实际检测中,单一的规则检测对"冰蝎"的误报率会比较高,一些比较明显的特征相互结合使用,会有事半功倍的效果。通过魔改程序也只能在一定时间内绕过安全设备的检测。真正想要持续有效必须不断更新,不断学习,在这攻防的浪潮中砥砺前行。

安全路漫漫,与君共勉。

image

相关文章

冰蝎,从入门到魔改(续)

冰蝎,从入门到魔改(续)

0x01 前言本篇文章是《冰蝎,从入门到魔改》的续篇。有小伙伴读过上一篇文章后联系笔者,说只介绍了 PHP 版本的特征擦除,希望可以获知其它语言版本的特征擦除思路和方法。本篇首先简单介绍一下上一篇文章...