*原创作者:nickchang(FB特约作者)
近期,朋友的电脑中毒了,杀毒软件警报如下。
Detection time(UTC time): 12/11/2015 11:12:39 AM Malware file path: file:_C:\Users\****\WuMorbSrkSs\ASAW2adgQ6k.oDhoel; file:_C:\Users\****\WuMorbSrkSs\ASAW2adgQ6k.oDhoel->main/AUx.class; file:_C:\Users\****\WuMorbSrkSs\ASAW2adgQ6k.oDhoel->main/Con.class; file:_C:\Users\****\WuMorbSrkSs\ASAW2adgQ6k.oDhoel->main/cOn.class; regkey:_HKCU@\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\\5Nna53uK5a4; runkey:_HKCU@\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\\5Nna53uK5a4; Remediation action: Quarantine Action status: Succeeded
从杀毒软件的告警信息看,这个被隔离的文件的扩展名是oDhoel,但是它包含了几个.class文件。所以初步判断这个病毒应该是打包的jar文件。而jar 文件一般都是用java(javaw) –jar命令打开的。那我们就从日志上找找看最近一次什么时候执行了java/javaw。
2015-12-08T10:58:38,%PROGRAMFILES%\MICROSOFT OFFICE\OFFICE14\WINWORD.EXE 2015-12-08T11:00:56,%PROGRAMFILES%\JAVA\JRE1.8.0_60\BIN\JAVAW.EXE 2015-12-08T11:00:57,%SYSTEM32%\XCOPY.EXE 2015-12-08T11:01:02.38,%SYSTEM32%\REG.EXE 2015-12-08T11:01:02.41,%SYSTEM32%\ATTRIB.EXE 2015-12-08T11:01:02.48,%OSDRIVE%\USERS\****\APPDATA\ROAMING\ORACLE\BIN\JAVAW.EXE
可以看见最近一次执行javaw是4天前,虽然日志没有记录其具体执行参数,但是随后的行为: “xcopy, reg, attrib and javaw”具有adwind类病毒的特征。特别值得注意的是第二个javaw是在用户目录运行的。Adwind类病毒会先把JRE环境复制到用户目录中,修改注册表开机自启动项,并且把自己的文件属性设置为隐藏,然后再用复制到用户目录中的javaw执行下载的其他jar文件。Hybrid-analysis上有些java病毒具有非常相似的行为,例子如下:
1. https://www.hybrid-analysis.com/sample/eff25d0449480c132e4427ad9a19da8680419dfe4bc1b21f090eab56c320d7c0?environmentId=4 2. https://www.hybrid-analysis.com/sample/ccb79d1030b291b4adbe02077247a6dba6773a61848a0c5ee0ed8c50314e1ea9?environmentId=1 3. https://www.hybrid-analysis.com/sample/1da960759932ff0158f579573e2544aaa84331f5bee2152deb18010a01534668?environmentId=1
1、第一阶段
被隔离的ASAW2adgQ6k.oDhoel基本属性如下:
·大小: 115.4kb
· Md5: 3836416d7099c06508f2bd67ee3a366c
· Virustotal 检测率: 15/55 (2015年12月21日) ,国内大多数av比如江明,瑞星都没有查杀。而趋势,麦卡费,赛门铁克都可查杀。还有貌似360已经不在virustotal上面了?
我们知道,一个.jar文件其实就是一个zip压缩包,里面包含一些java二进制文件 (.class) 和配置文件。那我先试着在winxp上把这些class文件解压出来。奇怪的是,我能看见文件列表,可是解压总是失败。
仔细一看,原来一些.class文件是重名的,只不过名字字母大小写不一样,比如NUL.class和NuL.class。这当然会在大小写不敏感的操作系统比如windows下会造成某些问题。没关系,用linux好了。在ubuntu下成功解开。
· 载荷(payload)文件: 红圈里面的是载荷文件。该文件大小是107kb,几乎占个整个.jar包大小的95% 。这个文件在一个6层的随机目录下面。后来我们发现这个载荷文件其实是另一个.jar文件。但是一开始这个文件是加密的,所以没法直接读取其内容。
· 配置文件: 绿圈里面的Config.pl 是一个配置文件, 同样也是加密的。这个配置文件主要提供了一个用于解密载荷文件的密钥。
· 若干 .class文件 : main 目录下包含一些.class文件。它们的主要功能是先解密配置文件,读取密钥,再用该密钥解密载荷文件。最后载入载荷文件执行。
· Manifest文件: jar的资源配置文件,用于定位程序入口。
下一步,我用 Krakatau 把这些 .class 文件反编译成 .java 文件。但是从这些.java文件可以看出该病毒作者使用了各种代码混淆技术,举例如下:
1. 把java 关键字当作变量名和函数名,比如下图的true, short, goto等。
这样会给分析带来两个问题,1反编译出来的java代码比较难读懂。2如果我们想再编译并且debug,编译器会报错。为了解决这些问题,我先把.class文件中的所有关键字全部替换掉,然后再用 Krakatau反编译。
find ./ -type f -exec sed -i -e 's/class/ssalc/g' {} \; find ./ -type f -exec sed -i -e 's/enum/mune/g' {} \; find ./ -type f -exec sed -i -e 's/short/trohs/g' {} \; find ./ -type f -exec sed -i -e 's/true/erut/g' {} \; find ./ -type f -exec sed -i -e 's/void/diov/g' {} \; find ./ -type f -exec sed -i -e 's/goto/otog/g' {} \; find ./ -type f -exec sed -i -e 's/case/esac/g' {} \; find ./ -type f -exec sed -i -e 's/super/repus/g' {} \;
2. 代码中的所有字符串都是加密的。
没法读取字符串就没法理解作者的意图,所以必须先对这些字符串解密。很容易就在代码中找到了两个解密函数。但是用于解密的密钥是会变化的。事实上,调用解密函数的类名称和函数名称就是解密的密钥。比如,当类nUI的构造函数调用解密函数解密某些字符串时,解密的密钥就是main.nUL.<clinit>。而当类auX的run()函数调用解密函数时,密钥就变成了main.auX.run。这个是通过读取栈,getstacktrace来实现的。
当然对于分析来说,一个比较方便的解密方法就是设置好断点,然后把程序跑起来,用debug功能来读取解密过的字符串。然而这样也会带来一个问题:在第一步中,我替换掉了一些函数名,比如从enum改到mune。这样的修改同样也会改变解密密钥,从而使解密结果不准确。 针对这个问题,我做出了一些相应的修改。最终把所有的字符串逆回明文。
3. 重复调用一些无意义的函数
这个比较简单,找到它们然后注释掉就可以了。
4. 定义两个成员函数,这两个成员函数有相同的函数名,相同类型,相同数量的参数,但是不同的返回类型。这个像overload但不是overload,在java语法里面是不允许的,编译的时候会报错。
在这种情况下,我只好重命名这两个函数. 比如 mune1(byte[]) 和 mune2(byte[])。
Debug以后,我对这个jar文件有了大致的理解:
1. 它会先解密嵌在 .class文件里的字符串. 这些字符串有的是配置文件config.pl的相对路径,有的是用来解密配置文件的密钥。
2. 用密钥 “VY999sisosouuqjqhyysuhahyujssddqsad22rhggdsfsdfs” 来解密config.pl, 解密算法是典型的异或算法。 解密后的内容将以 XML格式载入。
3. 配置文件 config.pl 包含两部分信息, 一个是 “password”, 另一个是 “server”。 它们的值分别为"CnqPOFxY6l" 和载荷文件的相对路径。
4. 它把 “kevthehermitGAYGAYGAYD” (这句话看起来像是骂人的,本文最后将会解释) 和 “CnqPOFxY6l” 结合起来形成一个新的密钥, 用来解密载荷文件。 这一次,解密算法是 RC6, 因为子密钥生成代码有显著的RC6的特征,对比如下图。
5. 解密完成以后,载荷文件将会被作为jar文件载入 (JarInputStream)并且执行。
到目前为止,我们知道了第一阶段的目的仅仅是解密并且调入包含的另一个.jar文件。
出于静态分析的目的,我修改了一些代码,把解密后的载荷存在本地文件系统。
2、第二阶段
载荷的基本属性如下:
·大小: 105.1kb ·Md5: 5c9409ad20fc16aea2c7ae80ed981cf5 ·Virustotal 检测率: 19/54 (21/Dec/2015) ,这次,卡巴、趋势、赛门铁克也不能查杀。
jar的文件结构如下:
├── [ 4096] META-INF │ └── [ 139] MANIFEST.MF ├── [ 4096] module │ └── [ 674] Server.class ├── [ 4096] org │ ├── [ 4096] jsocket │ │ ├── [ 4096] a │ │ │ ├── [ 2403] iiIiiIIIii.class │ │ │ ├── [ 1837] iiIIiIIIIi.class │ │ │ ├── [ 2135] iIiIIIiIiI.class │ │ │ ├── [ 2182] iIIiiiiIII.class │ │ │ ├── [ 552] iIIiIiiIiI.class │ │ │ ├── [ 1052] iIIIiiIiiI.class │ │ │ ├── [ 988] IiiiIIIiIi.class │ │ │ ├── [ 6230] IiiIIiiIIi.class │ │ │ └── [ 3607] IiIiIiiIiI.class │ │ ├── [ 4096] b │ │ │ ├── [ 2647] iiiiIiIIii.class │ │ │ ├── [ 2558] iiIiiIIIii.class │ │ │ ├── [ 564] iiIIiIIIIi.class │ │ │ ├── [ 2593] iIiIIIiIiI.class │ │ │ ├── [ 2145] iIIiiiiIII.class │ │ │ ├── [ 1404] iIIiIiiIiI.class │ │ │ ├── [ 1882] iIIiIiIiII.class │ │ │ ├── [ 1101] iIIIiiIiiI.class │ │ │ ├── [ 2306] iIIIIIiIii.class │ │ │ ├── [ 1175] IiiiIIIiIi.class │ │ │ ├── [ 2960] IiiIIiiIIi.class │ │ │ ├── [ 1501] IiIiIiiIiI.class │ │ │ ├── [ 3286] IiIiIIiiII.class │ │ │ └── [ 2481] IIiiiIiiii.class │ │ ├── [ 4096] c │ │ │ ├── [ 4379] iiIiiIIIii.class │ │ │ ├── [ 1492] IiiIIiiIIi.class │ │ │ └── [ 2745] IiIiIiiIiI.class │ │ ├── [ 4096] d │ │ │ ├── [ 3753] iiIiiIIIii.class │ │ │ ├── [ 2386] iiIIiIIIIi.class │ │ │ ├── [ 2584] iIiIIIiIiI.class │ │ │ ├── [ 1196] iIIiiiiIII.class │ │ │ ├── [ 3255] iIIiIiiIiI.class │ │ │ ├── [ 1191] iIIiIiIiII.class │ │ │ ├── [ 3803] iIIIiiIiiI.class │ │ │ ├── [ 3219] IiiiIIIiIi.class │ │ │ ├── [ 449] IiiIIiiIIi.class │ │ │ └── [ 1430] IiIiIiiIiI.class │ │ ├── [ 4096] main │ │ │ └── [ 9473] Start.class │ │ └── [ 4096] resources │ │ ├── [ 355] config.json │ │ └── [ 2970] key.dll │ └── [ 4096] json │ ├── [ 4387] CDL.class │ ├── [ 13755] JSONArray.class │ ├── [ 754] JSONException.class │ ├── [ 6584] JSONML.class │ ├── [ 196] JSONObject$1.class │ ├── [ 24447] JSONObject.class │ ├── [ 881] JSONObject$Null.class │ ├── [ 156] JSONString.class │ ├── [ 604] JSONStringer.class │ ├── [ 5916] JSONTokener.class │ ├── [ 4109] JSONWriter.class │ ├── [ 1757] Property.class │ ├── [ 7554] XML.class │ └── [ 4715] XMLTokener.class └── [ 4096] tools ├── [ 1868] Base64.class ├── [ 1529] Compress.class ├── [ 1300] Copy.class ├── [ 3564] Helper.class ├── [ 1980] Reader.class ├── [ 1643] RunJarFile.class └── [ 1490] WscriptProcess.class
位于 /org/jsocket/resources目录下有一个配置文件 config.json。这是一个明文json格式配置文件。
{"NETWORK":[{"PORT":1960,"DNS":"millzjsoctrinwi80gm.duckdns.org"}],"INSTALL":true,"PLUGIN_FOLDER":"OMewSKDQMyT","JRE_FOLDER":"fbAP1V","JAR_FOLDER":"WuMorbSrkSs","JAR_EXTENSION":"oDhoel","DELAY_INSTALL":2,"NICKNAME":"GODTHEFATHER","VMWARE":true,"PLUGIN_EXTENSION":"wmQYM","JAR_NAME":"ASAW2adgQ6k","JAR_REGISTRY":"5Nna53uK5a4","DELAY_CONNECT":2,"VBOX":true}
注意network下的DNS值,"millzjsoctrinwi80gm.duckdns.org”。 duckdns.org提供免费的动态子域名服务。 任何人都可以在duckdns.org上面申请子域名,并且用一个脚本动态上传修改dns记录. 这个域名很可能就是肉鸡服务器。目前这个域名指向 89.163.154.140,可是已经连不上了。
从Threatcrowd 上面看, 这个域名(millzjsoctrinwi80gm.duckdns.org) 也被其他一些java病毒当作肉鸡服务器。
其他一些配置信息,比如 “plugin_folder”, “jar_folder” 和 “jre_folder”定义了jre环境和病毒的安装目录。 “delay_install” 和 “delay_connect”定义了潜伏的时间。 “vbox” 和 “vmware” 定义了是否侦测虚拟环境。所有这些配置信息都是明文的,所以,很可能这是一个商业化的后门?
继续反编译.class文件,发现所有内嵌的字符串也都是加密的。解密方法和第一阶段完全相同:用调用函数的函数名和类名作为解密密钥。最终我把所有的字符串还原成了明文。
结合代码,发现很明显这是个远控后门程序。
首先,它从config.json里面读取基本配置信息,并放入 settings。
如果配置要求的话,它会检查当前运行环境是否是虚拟机(只检测vmware和virtualbox)。检测基于是否有一些特殊的目录,“virualbox guest additions” 和 “VMware tools”。如果发现是虚拟环境,它会停止运行,立即退出。主要目的是防止被动态分析。
它会继续监测目标电脑的软件硬件信息ip地址等,并且存放于settings。
Java程序可以跨平台执行,所以有可能运行在不同的操作系统上。因此该病毒会检查受害者的操作系统。针对windows, linux, mac,它都有相应的代码。
该病毒会潜伏一段时间以后,开始安装。
对于windows平台,它会用 “xcopy” 把 jre 环境复制到用户目录下。
xcopy "%PROGRAMFILES%\Java\jre1.8.0_25" "C:\Users\%USERNAME%\AppData\Roaming\Oracle\" /e
对于流行的杀毒软件,它会修改注册表进行镜像劫持。在Image File Execution Options (IFEO)下面新建一个debugger 项,重定向为svchost.exe。
用“attrib”把自己文件的属性设置为隐藏。
attrib +h "%USERPROFILE%\qPL63CO8myp\*.*
用https连接配置文件中指定的肉鸡服务器。
SSL的证书,密钥信息是从key.dll里面读取的。这个文件包含在jar包里面。
它还会登陆maxmind 并且取出感染主机的地理位置信息。
继续下载更多的jar文件,把它们存放在一个临时文件里,并且伪装成png文件。然后载入这些下载的文件。
用“wmic” 命令检测被感染主机是否有摄像头。
如果是以 admin 权限运行的, 它会把自己加到 “current version/ run” 键里面,以实现开机自启动。如果在linux下面它会配置autostart。
在某些时候,它会生成一个vb脚本删除自己,包括文件,目录,和注册表信息。
3、后记
根据这些信息,搜索后发现其实这个后门叫做jsocket, 是 “alienspy” 和 “adwind”的新版本。 它是个商业化的后门,网址是 https://jsocket.org。 售价大约是25美刀一个月,或者300美刀一年。看起来像是一个合法的后门,可是网站却宣称它可以杀掉或者绕过某些杀毒软件。
Fidelissecurity 对该后门的免费版本做过一些研究并且在上个月写过一篇报告[2],而且统计了被感染主机的地理位置,如图所示,重灾区在美国。当然在欧洲和中国也有一定程度的感染。
图来自 [2]
而肉鸡服务器主要位于美国、俄罗斯和尼日利亚。中国几乎没有。
图来自[2]
笑点在最后, 安全专家Kevin Breen曾经在github上开源了一个解密Alienspy病毒配置文件的程序[3]。他的github 名字是 “Kevthehermit”。而前文说过Alienspy是jSocket的早期版本,病毒作者可能是同一个人。
还记得吗,在第一阶段分析的时候,解密载荷文件的密钥的开头是“kevthehermitGAYGAYGAYD”。 骂别人是gay, 看来该病毒的作者真的恨死Keven Breen了。
4、文献
[1] jsocket home page https://jsocket.org/
[2] Fidlis cysbersecurity, Ratcheting Down on JSocket: A PC and Android,Threat https://www.fidelissecurity.com/sites/default/files/FTA_1019_Ratcheting_Down_on_JSocket_A_PC_and_Android_Threat_FINAL.pdf
[3] Alienspy decoders https://github.com/kevthehermit/RATDecoders/blob/master/AlienSpy.py
*原创作者:nickchang,本文属FreeBuf原创奖励计划文章,未经许可禁止转载。