背景
自从Log4J漏洞被曝光后,正所谓"忽如一夜漏洞来,大黑小灰笑开怀”。无数黑产团伙摩拳擦掌加入了这个“狂欢派对”,其中既有许多业界非常熟悉的恶意软件家族,同时也有一些新兴势力想趁着这股东风在黑灰产上分一杯羹。36.NETlab作为专注于蜜罐和Botnet检测跟踪的团队,我们自该漏洞被公开后就一直关注它会被哪些僵尸网络利用,期间我们看到了Elknot,Gafgyt,MirAI等老朋友的从不缺席,也见证了一些新朋友的粉墨登场。
2022年2月9日,360Netlab的蜜罐系统捕获了一个未知的ELF文件通过Log4J漏洞传播,此文件在运行时产生的网络流量引发了疑似DNS Tunnel的告警,这引起了我们的兴趣。经过分析,我们确定是一个全新的僵尸网络家族,基于其传播时使用的文件名"b1t",XOR加密算法,以及RC4算法秘钥长度为20字节,它被我们命名为B1txor20。
简单来说,B1txor20是一个针对linux平台的后门木马, 它利用DNS Tunnel技术构建C2通信信道,除了传统的后门功能,B1txor20还有开启socket5代理,远程下载安装Rootkit,反弹SHELL等功能,这些功能可以很方便的将被侵入的设备变成跳板,供后续渗透时使用。
另外一个有意思的点是我们发现许多开发好了的功能并没有投入使用(在IDA中表现为,没有交叉引用);有些功能存在BUG。我们推测B1txor20的作者会持续完善,并根据的不同场景,定制式地开启不同的功能,或许以后我们将遇到B1txor20的兄弟姐妹。
鉴于B1txor20所使用漏洞的高危性,以及其C2信道的隐蔽性,我们决定撰写本文向社区分享我们的发现,共同维护网络安全。
B1txor20概览
我们一共捕获了4个不同MD5的B1txor20样本文件,它们的功能几乎一样,一共支持15个功能号,根据这些功能,可以将B1txor20定性为:一个使用DNS Tunnel技术构建隐蔽的C2信道,支持直连和中继2种方式,同时使用ZLIB压缩,RC4加密,BASE64编码的方式保护流量的后门木马,目前通过Log4j漏洞传播,主要针对ARM,X64 CPU架构的Linux平台。
目前支持的主要功能如下所示:
它的基本流程图如下所示:
逆向分析
本文选择2022年2月09日的样本为主要分析对象,它的基本信息如下所示:
MD5:0a0c43726fd256ad827f4108bdf5e772ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, strippedPacker:None
B1txor20的样本是动态链接的,因此在逆向上比较容易,简单来说,当B1txor20在被侵入设备动行后,首先会将自身伪装成[netns]进程,通过/var/run/.netns.PID这个PID文件实现单一实例,然后使用/etc/machine-id,/tmp/.138171241或/dev/urandom3者中任意一个,生成BotID,接着解密用于DNS Tunnel的域名,以及用于加密流量的RC4秘钥并测试DNS服务器的连通性,最后使用DNS Tunnel技术向C2发送上线信息,等待执行C2下发的指令。其中进程伪装,单一实例这些功能比较简单,就再不细述,下文将围绕DNS Tunnel剖析B1txor20的实现。
生成Bot ID
B1txor20通过以下代码片段从etc/machine-id,或/tmp/.138171241,读取32字节用于生成BotId,如果失败,则通过/dev/urandom生成16字节数据,并将它写入到前面2个文件。
下面的代码片段是BotId的计算过程:
以我们虚拟机的machine-id值ab3b49d10ec42c38b1093b8ce9ad12af为例,通过下面等效的Python/ target=_blank class=infotextkey>Python代码,可以算出BotId的值为0x125d。
import structid='ab3b49d10ec42c38b1093b8ce9ad12af'values=struct.unpack("<16H",id)sum=0for i in values:sum ^= iprint hex(sum)if sum&0xff <0xf:sum+=0x10if sum>>8 < 0xf:sum+=0x1000print hex(sum) # sum=0x125d
解密
B1txor20通过以下代码片段解密存储在样本中的域名和RC4秘钥,
它的原理非常简单,就是单字节xor操作,其中xor_key为49 D3 4F A7 A2 BC 4D FA 40 CF A6 32 31 E9 59 A1
通过下图的CyberChef实现等效的解密过程,可知域名为.dns.webserv.systems,RC4秘钥为EnLgLKHhy20f8A1dX85l。
测出DNS服务器的连通性
B1txor20通过以下代码片段测试3个DNS (8.8.8.8:53,8.8.8.4:53,194.165.16.24:443)服务器的连通性。
它的原理是使用res_mkqueryAPI构建“google.com”的DNS请求报文,然后通过res_send发送请求,只要能够发送成功,就认为和相应DNS服务器的网络是连通,把它们保存起来供后续使用。
实际中Bot与194.165.16.24产生的流量如下所示:
C&C通信
当上述的准备工作完成后,B1txor20进入最终阶段,使用DNS Tunnel技术和C2建立通信,等待执行C2下发的指令。
一般来说恶意软件使用DNS Tunnel的场景是这样的:Bot把窃取的敏感信息,命令的执行结果等等任何需要传递的信息,在使用特定的编码技术隐藏之后,以DNS请求的方式,将它发送到C2;C2到接收到请求之后,把payload做为DNS请求的响应,将它发送到Bot端。这样一来,Bot与C2就在DNS协议的帮助之下实现了通信。在这样的网络结构中,有3个关键的点值得注意
下文将围绕这些点,结合B1txor20在实际中产生的流量,分析B1txor20的通信技术细节。
0x01:定位C2
通过上图的流量,可以看出B1txor20使用的SLD是webserv.systems,使用DIG命令可知此SLD绑定的IP为194.165.16.24;而194这个IP上又开启了DNS解析服务,因此我们可以确定B1txor20的C2正是194.165.16.24。
0x02:生成Tunnel域名
B1txor20的Tunnel域名格式为Base64-Like String+.dns.websrv.systems 很明显前面
类似Base64的字串就是Bot发往C2的信息,它是如何生成的呢?
首先,B1txor20数据包的有一个前置构造过程,可以看出其格式为0xFF + BotId + 0xFF + Stage + 0xFF + Other Info,0xFF用于分隔不同的项,当成完构造后,再根据不同的Stage值,进入不同的任务,填充Other Info部分。
以上线这个任务为例,Stage值为1,通过gather_info函数,将"sysinfo_uptime,uid,hostname"这些信息填充到Other Info中,它们使用0x0a分隔。
当所需的信息都已准备好之后,B1txor20接着使用process_query函数对上面的信息进一步处理,它包括ZLIB压缩,RC4加密,Base64编码3个过程。
其中RC4加密所使用的秘钥就是前文解密章节所说的字串“EnLgLKHhy20f8A1dX85l”,Base64使用的Alphabet String为ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789^_。
最后B1txor20在上面生成的Base64字串前加入1字节表示status,4字节随机字串,再和domain进行拼接,就么得了最终要查询的域名。其中status的取值为['0', '1', '2'],0表示当前的查询被截断了,后续的查询和当前应该拼成同一个;1表示当成查询是完整的。
以实际产生的一个查询1HQoOKPvBKs8yqO1tTUQkCqGWN9anB4RAGWhnJy8A.dns.webserv.systems为例,去除前5字节,以及.dns.webserv.systems部分,得到KPvBKs8yqO1tTUQkCqGWN9anB4RAGWhnJy8A,然后使用Base64解码,RC4解密,ZLIB解压,就能得到了以下原始数据。
从数据内容和格式来看,它和我们前文的描述能一一对应,说明我们前面的分析是正确的。
Botid =0x125dStage=1sysinfo.uptime = 34uid=30hostname=debian
0x3:发送DNS请求
当上述域名构造完成后,B1txor20使用RES系列API生成并发送DNS请求。
根据前文测试DNS连通情况的不同,发送DNS请求的方式有3种。
其中2这种方式,它的速度较快,但蔽性弱,很容易被探测追踪;1,3这种俩种方式隐蔽性强,但速度稍慢。
0x4:处理C2指令
当Bot通过上述方式发送DNS请求后,就等待执行C2下发的指令。C2的指令存放在DNS请求的响应报文中,它的格式为Status(1 byte):Body,其中Body部分也使用了“ZLIB压缩,RC4加密,BASE64编码”这种保护方法。
以下图实际收到的指令“1VSE6NZwczNMm2zgaXeLkZro= ”为例,
Body部分为"VSE6NZwczNMm2zgaXeLkZro=",它经过Base64解码,RC4解密后,就能得到了以下格式的数据,再将红色部分解压,就得到了最终的指令FF 02 FF 0A FF,可以看出它的格式和上文查询产生的格式是一致的,此时可知Bot将去执行0x02号功能,至此Bot与C2的一轮交互就完成了。
C&C指令
B1txor20一共支持15条指令,指令号与功能的对应关系如下表所示:
CMD ID
FUNCTION
0x1
Beacon/Heartbeat
0x2
Upload system info
0x3
Create "/dev/pamd" (unix domain socket) which can get a shell
0x4
Exec arbitrary system cmd via popen
0x5
Traffic forwarding
0x6
Write File
0x7
Read File
0x8
Deliver info via "/var/tmp/.unetns"(unix domain socket),Not used
0x9
Upload specific info,Not used
0x10
Stop proxy service
0x11
Start proxy service
0x1a
Create proxy service
0x21
Reverse shell
0x50
Upload "/boot/conf- XXX" info,Not used
0x51
install M3T4M0RPH1N3.ko rootkit
表中"Not used"表示这个功能,在样本中有应的处理代码,但没有被调用,我们不确定这些代码是用于调试的,或是在别的样本中使用。
另外有意思的一点是,我们发现有些功能在实现上是有Bug的,如0x3,它在bind 域套接字后,使用remove函数删除了套接字文件,这会让此套接字无法被connect,进而整个功能失效。
花絮
域名一买就是6年,这是想要大干一票?
webserv.systems createddate 2021-02-08 15:13:22webserv.systems updateddate 2021-02-24 22:27:23webserv.systems expiresdate 2027-02-08 15:13:22