<返回更多

双头龙(RotaJakiro),一个至少潜伏了3年的后门木马

2023-02-23     Alex.Turing
加入收藏

版权

版权声明:本文.NETlab原创,依据 CC BY-SA 4.0 许可证进行授权,转载请附上出处链接及本声明。

概述

2021年3月25日,360 NETLAB的BotMon系统发现一个的VT 0检测的可疑ELF文件(MD5=64f6cfe44ba08b0babdd3904233c4857),它会与4个业务类型截然不同的域名进行通信,端口均为TCP 443(HTTPS),但流量却并非TLS/SSL类型,这个异常行为引起了我们的兴趣,进一步分析发现它是一个针对linux X64系统的后门木马,该家族至少已经存在3年但目前还是0检测。基于该家族使用rotate加密,并且运行后对root/non-root账户有不同的行为,犹如一只双头龙,一体双向,我们将它命名为RotaJakiro

RotaJakiro隐蔽性较强,对加密算法使用比较多,包括:使用AES算法加密样本内的资源信息;C2通信综合使用了AES,XOR,ROTATE加密和ZLIB压缩算法。指令方面,RotaJakiro支持12种指令码,其中3种是和特定plugin相关的,遗憾的是目前我们并没有捕获到这类payload,因此并不知道它的真正目的。从广义的后门角度来看,RotaJakiro支持的功能可以归纳成以下4类:

当所有分析结束后,我们尝试对RotaJakiro进行溯源,根据解密后的资源以及编码的风格的相似性,我们推测它是Torii Botnet作者的又一作品。

潜伏了多少?

我们从捕获的样本出发,寻找RotaJakiro同源者,最终发现了以下4个样本,它们在VT上都是0检测,从VT的First Seen时间来看,RotaJakiro至少已经存在了3年

FILENAME MD5 DETECTION FIRST SEEN IN VT
systemd-daemon 1d45cd2c1283f927940c099b8fab593b 0/61 2018-05-16 04:22:59
systemd-daemon 11ad1e9b74b144d564825d65d7fb37d6 0/58 2018-12-25 08:02:05
systemd-daemon 5c0f375e92f551e8f2321b141c15c48f 0/56 2020-05-08 05:50:06
gvfsd-helper 64f6cfe44ba08b0babdd3904233c4857 0/61 2021-01-18 13:13:19

这批样本都内嵌了以下4个C2,目前它们在VT上也是0检测。这4个C2域名有非常接近的Crteated Updated Expired时间,我们推测它们一直以来用于同一个业务,从这个角度来看,RotaJakiro背后的团伙至少已经活动了6年

DOMAIN DETECTION CREATED LAST UPDATED EXPIRED
news.thaprior.net 0/83 2015-12-09 06:24:13 2020-12-03 07:24:33 2021-12-09 06:24:13
blog.eduelects.com 0/83 2015-12-10 13:12:52 2020-12-03 07:24:33 2021-12-10 13:12:52
cdn.mirror-codes.net 0/83 2015-12-09 06:24:19 2020-12-03 07:24:32 2021-12-09 06:24:19
status.sublineover.net 0/83 2015-12-09 06:24:24 2020-12-03 07:24:32 2021-12-09 06:24:24

逆向分析

4个RotaJakiro样本,时间分布从2018到2021,它们的功能非常接近,本文选取2021年的样本为分析对象,它的基本信息如下:

MD5:64f6cfe44ba08b0babdd3904233c4857
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped
Packer:No

从编码层面来说,RotaJakiro采用了动态AES,双层加密的通信协议等技术来对抗安全人员的二进制&网络流量分析。

从功能层面来说,RotaJakiro运行时首先会判断当时用户是root,还是non-root,不同的账户有不同的执行策略,然后使用AES&ROTATE解密出相关的敏感资源供后续的持久化,进程守护和单一实例使用,最后和C2建立通信,等待执行C2下发的指令。

下文将从上述角度出发剖析RotaJakiro具体实现。

样本对抗技巧

加密算法

RotaJakiro中所有的敏感资源都是加密的,在IDA中我们可以看出解密方法dec_proc调用了60次,它是由AES,Rotate俩部分组成。

AES解密入口如下所示:

其中aes_dec的采用的是AES-256, CBC模式,key&iv都是硬编码。

Rotate解密入口如下所示:

所谓Rotate即循环移位,可以看出此处使用的循环左移,其中移位的次数由plain_len(明文长度)&7的值决定。

以解密以下C2密文为例:

ff ba a2 3b cd 5b 7b 24 8c 5f e3 4b fc 56 5b 99 
ac 91 cf e3 9a 27 d4 c9 6b 39 34 ce 69 ce 18 60

其与解密相关的各种参数如下图所示,密文长度为32字节,明文长度为26字节

首先使用AES解密后得到以下“次级密文”:

然后从次级密文中取出有效密文,其中有效密文从第8字节开始,长度为明文长度减8,此处即为26-8=18字节。

98 1B DB D9 8B 59 19 5D 59 1B 59 D8 1D DC 8B D8 
DB 5B

最后通过明文长度26可以计算26&7=2,得到移位的次数,将上述有效密文逐字节左移2位,就能得到C2明文。

blog.eduelects.com

持久化

RotaJakiro在实现持久功能时,对root/non-root用户做了区分,不同的账号采用了不同的技术。

针对root账号的持久化实现

针对non-root账号的持久化实现

进程守护

RotaJakiro实现了进程守护以保护自身的运行,和持久化一样,对root/non-root用户有不同的实现方式。

针对root账号的进程守护实现

在root账号下运行时,根据不同Linux系统发行版本,通过向服务的配置文件中写入Restart=always或者respawn,当服务进程被结束时,会自动创建新进程。

实际效果如下图所示,可以看到systemd-daemon进程被结束后,立马就生成了新进程。

针对non-root账号的进程守护实现

在non-root账号下运行时,RotaJakiro生成session-dbusgvfsd-helper俩个进程,它们监控着彼此的存活,当其中一方被结束时,另一方将其恢复,这是非常典型的双进程保护。

RotaJakiro的双进程保护是如何实现的呢?首先以shmget API创建一片共享内存,session-dbus和gvfsd-helper通过这片共享内存实现进程间通信,告诉对方的自己的PID。然后通过/proc/[PID]目录,动态地获取进程的存活情况。当发现对方进程死亡时,通过execvp创建进程,帮助死亡一方“复活”,大致流程如下图所示:

实际效果如下图所示,可以看到session-dbusgvfsd-helper被kill -9结束后,新进程立马就创建了。

单一实例

RotaJakiro通过文件锁来实现单一实例,具体实现如下所示:

其中用到的lockfile在root/non-root账号下有所不同。

以实际中non-root账号为例,通过/proc/locks可以将进程以及文件锁对应起来,此时再执行对应的RotaJakiro的样本,可以看到并不会有对应的新进程创建。

网络通信

RotaJakiro通过以下代码片段和C2建立通信,等待执行后续指令:

这个过程可以分成2个阶段

Stage 1:初始化

通过前文所述的解密算法解密出C2列表,目前样本中内置了以下4个C2:

news.thaprior.net
blog.eduelects.com
cdn.mirror-codes.net
status.sublineover.net

RotaJakiro首先会尝试和它们建立连接,然后通过以下代码片段构造上线信息,

接着将上线信息加密并发送给C2

最后接收C2的回包,解密并校验其合法性,若通过校验,进入Stage 2。

Stage 2:具体业务

通过以下代码片段接收并执行C2下发的指令:

目前RotaJakiro一共支持12条指令,指令码与功能的对应关系如下表所示:

CMDID FUNCTION
0x138E3E6 Exit
0x208307A Test
0x5CCA727 Heartbeat
0x17B1CC4 Set C2 timeout time
0x25360EA Streal Senstive Info
0x18320e0 Upload Device Info
0x2E25992 Deliver File/Plugin
0x2CD9070 Query File/Plugin Status
0x12B3629 Delete File/Plugin Or Dir
0x1B25503 Run Plugin_0x39C93E
0x1532E65 Run Plugin_0x75A7A2
0x25D5082 Run Plugin_0x536D01

其中Run Plugin功能复用相同的代码,通过以下逻辑实现函数调用:

我们目前被没有捕获到这类payload,因此用Plugin_“参数”的形式来表示不同的任务。

RotaJakiro的网络通信包如下图所示,由head,key,payload三部分组成,其中header是必须的,长度为82字节,而body&payload部分是可选的。head&key采用的XOR&Rotate加密,payload采用AES&ZLIB加密压缩。

下面我们将通过BOT与C2的一轮交互,来说明网络流量head&key&payload的组成以及解密过程。

C2 -> BOT

读取前0x52字节,就是head的内容。head如何解密呢?方法很简单,逐字节左移3位,然后和0x1b异或即可,解密后得下以内容:

00000000  16 11 10 b9 03 b1 0c fb 04 20 00 00 00 08 00 e0  |...¹.±.û. .....à|
00000010  20 83 01 c2 20 64 20 01 e2 00 00 00 00 c2 0c 00  | .. d .â....Â..|
00000020  00 00 32 42 36 39 33 33 34 46 38 34 31 44 30 44  |..2B69334F841D0D|
00000030  39 46 41 30 36 35 38 45 43 33 45 32 39 46 41 44  |9FA0658EC3E29FAD|
00000040  34 39 c8 53 e6 9c 48 c4 8b 77 24 2e 02 1c 96 d9  |49ÈSæ.HÄ.w$....Ù|
00000050  81 28
------------filed parse------------------
offset 0x09, 4 bytes--->payload length
offset 0x0d, 2 bytes--->body length
offset ox0f, 4 bytes--->cmdid

通过字段解析,可知key的长度为0x8字节,payload的长度为0x20字节,要执行的指令码为0x18320e0,即上报设备信息。

从偏移0x52读取8字节就得到了keyea 9a 1a 18 18 44 26 a0,使用和head一样的解密方法,得到4c cf cb db db 39 2a 1e,它是作为AES的密钥来解密payload。

从偏移0x5a读取32字节,就得到了下面的payload:

54 c1 c3 69 00 18 31 e4 a2 5b 10 7f 67 ab d1 4b 
b2 7b 3d 3f b3 bc 66 6a 26 f6 f6 b3 f7 2e 66 6d

使用解密后的key做为AES-256的密钥,以CBC模式解密以上数据得下以下内容:

3b c7 f8 9b 73 2b d1 04 78 9c e3 60 60 60 d8 df d9 c1 71 56 f7 6f 00 00 13 80 04 28

第8字节起即为ZLIB压缩数据,解压得到如下内容:

08 00 00 00 bf 89 88 08 cd 2d fd 50
------------filed parse------------------
offset 0, 4 bytes--->length

解压后的payload有什么用呢?它是做为新的AES密钥,用来解密部分敏感资源信息
例如Bot在收集设备信息时,有一项是当前操作系统发行版本的信息,它是通过cat /etc/*release | uniq命令实现的。

root@debian:~# cat /etc/*release | uniq
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

cat /etc/*release | uniq这条命令正是以下密文通过新的AES密钥配合下图中的参数解密而来。

cmd ciphertxt
---------------------------
74 00 dd 79 e6 1e aa bb 99 81 7e ca d9 21 6b 81 
6b d9 9d 14 45 73 6a 1c 61 cc 28 a3 0f 2b 41 5a 
6b 33 8c 37 25 89 47 05 44 7e f0 6b 17 70 d8 ca

Bot -> C2

当BOT接收到C2的“上报设备信息”指令后,会向C2发送以下数据,可以看出key部分的值依然是ea 9a 1a 18 18 44 26 a0

从上文已知解密后key值为4c cf cb db db 39 2a 1e,通过这个值将Bot发往C2的payload解密解压后,得到如下数据,正是设备的各种信息,其中有前文提到的通过cat /etc/*release | uniq获取的信息,验证了我们的分析是正确的。

与Torii Botnet团伙的关系

Torii僵尸网络于2018年9月20日被友商Avast曝光,对比RotaJakiro,俩者的相似之处体现在以下3方面:

1:字符串相似性

RotaJakiro&Torii的敏感资源解密后,我们发现它们复用了大量相同的命令。

1:semanage fcontext -a -t bin_t '%s' && restorecon '%s'
2:which semanage
3:cat /etc/*release 
4:cat /etc/issue
5:systemctl enable
6:initctl start
...

2:流量相似性

在构造流量的过程中,大量使用常数,构造方式非常接近。

3:功能相似性

从安全研究人员进行逆向工程的角度来说,RotaJakiro&Torii有着相常相似的风格:使用加密算法隐藏敏感资源,都实现了相当old-school式的持久化,结构化的网络流量等。

基于这些考量,我们推测RotaJakiro和Torii出自同一个团伙之手。

冰山一角

至此RotaJakiro的逆向与溯源告一段落,但真正的工作远没结束,有许多问题依然没有答案:“RotaJakiro是怎么传播的,它的目的是什么?”,“RotaJakiro是否有特定的攻击目标,是不是APT?”,“RotaJakiro与Torii背后的黑手是谁?”......由于我们的视野有限,目前只能向安全社区分享这么多。如果社区有相关的线索,欢迎与我们联系,让我们一起Make Cyber Security Great Again

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>