静默之控:主动与被动双模后门MystRodX的隐匿渗透
背景介绍
2025年6月6日,Xlab大网威胁感知系统监测到 IP 139.84.156.79正在传播一个VT低检测 4/65,名为dst86.bin的可疑ELF文件。多引擎检测模块
将该文件标识为MIRAI僵尸网络,但AI研判模块
却没有给出相应的结果。这个“异常”引起了我们的兴趣,经过分析确认它是Dropper,最终会释放出一个全新的后门木马,和Mirai完全无关,多家杀软将其标记为Mirai是不准确的。基于其传僠中使用的文件名dst,释放样本中的类名cmy_,多种形式的Xor算法,我们将它命名为MystRodX。
MystRodX是一个由c++语言实现的典型后门木马,支持文件管理,端口转发,反弹SHELL,sockets管理等功能。相较于一般的后门,MystRodX在隐匿性,灵活性俩方面具有非常鲜明的特点。其中隐匿性
体现在对于不同级别敏感信息采用了差异化加密策略:
- 虚拟机&调试器检测等相关敏感字符串使用单字节xor加密
- AES密钥,Payload,激活报文使用自定义的Transform算法加密
- 配置文件使用AES CBC模式加密
而灵活性
则是MystRodX会根据不同的配置动态开启不同的功能特性,比如网络协议使用TCP或HTTP,流量直接使用明文或AES加密等。其中最有意思的是支持被动唤醒的触发模式,即MystRodX可配置成被动式后门,在不使用开放端口的情况下由特定的DNS或ICMP网络报文激活。
MystRodX的配置中存在一项用于设定后门生效时间的选项。在已捕获的样本中,该选项所设置的最早时间为2024年01月07日 23:10:20
,表明该后门在真实网络中已潜伏超过20个月,且一直未被安全社区准确识别。此外,基于奇安信网络空间测绘鹰图平台的C2探测服务,发现了3个仍在活跃的C2服务器,并以技术手段确认在野还存在未被捕获的样本。再考虑到该后门所采用的被动通信机制所带来的高隐蔽特性,我们决定撰写本文,公开相关研究成果,以揭示这一长期存在的威胁,为增强网络安全防御能力提供支持。
被动后门模式
当配置中Backdoor Type选项的值为1时,MystRodX开启被动后门模式,它使用RAW SOCKET监听网络流量,可在不使用开放端口的情况下,被特定的DNS或ICMP网络报文激活
。
激活报文采用了Appendix章节中的Transform算法加密,解密后的格式为 Magic(4字节)+ Protocol(4字节)+ Port(4字节)+ C2
。当 Magic 值比对通过后,MystRodX 便会根据报文中指定的协议类型与C2建立通信,等待接收攻击者的后续指令。
不同于知名的SYNfull Knock后门完全利用TCP协议内部字段以传递指令,MystRodX使用的是一种更为简单的方式,即激活指令隐藏在ICMP 载荷或DNS请求的域名中。
0x1: DNS激活报文
首先看一下DNS激活报文,有效的激活报文必须是www.DomainName.com
这种格式。
DomainName {9-bytes mask}UBw98KzOQyRpoSgk5+ViISKmpC6ubi7vao=
使用base64解码后得到以下密文:
00000000: C5 E4 F2 A7 11 73 DD 40 70 F7 C2 B3 39 0C 91 A6 .....s.@p...9...
00000010: 84 A0 93 9F 95 88 84 8A 9A 90 BA B9 B8 BB BD AA ................
使用Transform算法,magic参数为0x0d,magic2参数为密文的最后一字节 0xaa, key参数为key_for_backdoor进行解密,即可得到以下明文。
按照激活报文格式对明文进行解析,可知
- Magic值为CAT
- 协议类型为TCP
- 端口为0x1f4a,即8010
- C2为149.28.137.254
当Magic通过比对之后,MystRodX就与C2 149.28.137.254:8010
建立通信,等待执行其下发的指令。
0x2: ICMP激活报文
接着看一下ICMP激活报文,这次我们从正向的角度,构造报文,观察样本的行为。
首先构造一个简单的ICMP ping请求 08 00 00 00 30 39 00 01
, 接着构造PAYLOAD,指定C2为192.168.96.1,端口为443,协议使用HTTP。
00000000: 43 41 54 00 01 00 00 00 BB 01 00 00 31 39 32 2E CAT.........192.
00000010: 31 36 38 2E 39 36 2E 31 00 00 00 00 00 00 00 00 168.96.1........
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
然后使用Transform算法,magic2参数设为0x9f对Payload进行加密。最终将ICMP 与 Payload合并,形成以下的ICMP报文。
当MystRodX收到该ICMP报文后,就会与192.168.96.1:443建立通信连接,发送HTTP格式的上线报文。这和我们的预期完全一致,验证了分析的正确性。
深入挖掘
在目前捕获的俩个MystRodX样本中,其配置的C2服务器均未开放有效端口。完成逆向分析后,我们面临一个关键问题:MystRodX究竟是一个仍在活跃的威胁,还是已被彻底废弃?为回答这一问题,我们依托于奇安信网络空间测绘鹰图平台分别从BOT端和C2端进行了一些尝试。
0x1: 唤醒BOT
我们尝试在全网范围内发送DNS/ICMP激活报文,意图唤醒处于被动模式的MystRodX后门,从而定位潜在受害者。遗憾的是,除我们自己的测试IP外,并未收到任何有效上线响应。造成这一现象的原因可能包括:在野MystRodX样本并未启用被动后门模式,或者样本使用了新的密钥、Magic值等配置,导致我们发出的激活报文未能匹配生效。
0x2: 探测C2
借助活跃C2探测服务的支持,我们成功发现3个仍在活跃的在野C2服务器。这些服务器对上线报文做出了响应,向Bot回复7号指令,要求开启流量加密。它们从2024年活跃至今,证明了MystRodX威胁的持续存在。
在MystRodX的配置项中包含一组RSA公钥,用于解密7号指令。攻击者通常会在不同活动中部署不同的公钥,目前已发现的两个公钥分别用于“neybquno”和“zoufkcfr”活动。在7号指令报文中,偏移0x110处长度为256字节的部分为MagicString的密文。只有当该密文经解密后得到的MagicString与样本中硬编码的字符串 0x68abut 完全一致时,MystRodX才会尝试开启流量加密。利用这一特性,可以判断某个C2是否用于已知的攻击活动。
在新捕获的三个活跃C2服务器中,仅149.28.137.254下发的7号指令能够被已知公钥成功解密。这一现象表明,另外两个C2(156.244.6.68与185.22.153.228)应归属于某次尚未知晓的攻击活动,意味着当前在野环境中肯定存在尚未被捕获的MystRodX样本。
检测分析
在俩个月内MystRodX的样本检测率稍有提高,目前已升至6/65,主流标签依然是Mirai。
我们推测部分杀软使用Mirai这个标签,是因为样本使用了Mirai经典的单字节Xor的方式加密与虚拟机,调试器相关的字符串。
vmware | vbox | phoenix |
---|---|---|
innotek | lldb | strace |
尝试俩种patch方式:一种是移除样本中虚拟机,调试器相关的加密字串;另一种是使用明文替换对应的密文。杀软对Patch之后文件的检测让人诧异,结果表明这俩种patch方式都有效的降低了检测率。然而这些字串实际上和样本的核心功能完全无关,这说明社区并未真正的识别MystRodX这一威胁。
Dropper分析
0x1: 字串解密
MystRodX使用单字节Xor对敏感的字符串进行加密保护,解密方法很简单:密文最后一字节为xor密钥,将其与密文逐字节进行xor即可。如密文\x13\x08\x12\x04\x17\x00\x65
,它的密钥为0x65,解密后为vmware\x00
。为了分析的方便,可以使用Idapython脚本实现批量解密。
效果如下所示:
解密出的字符串可以分成3大类,分别用于虚拟机检测,调试检测,启动Launcher等功能。
- VM相关:检查/sys/class/dmi/id/bios_vendor的内容是否包含
vmware,vbox,Phoneix,innotek
来判断当前是否处于虚拟化环境 - Debugger相关:检查父进程名是否匹配常见调试工具
gdb,lldb,ltrace,strace
判断当前进程是否被调试 - Launcher相关:下一阶段Launcher文件名,pid文件,以及工作目录
0x2: Payload解密
解密Payload前需要预先设置一个keyinfo的结构体,其中key1的值为0x13,xorkey由样本硬编码,长度为32字节。
struct keyinfo
{
uint8_t key1;
uint8_t unknow[3];
void *xorkey;
uint16_t xorkey_len;
uint8_t key2;
uint8_t notused;
};
xorkey
00000000 02 06 03 09 04 02 0e 0a 01 0f 08 0a 04 0d 0b 09 |................|
00000010 0a 09 01 03 06 05 6d 0c 01 02 0f 03 03 0a 05 00 |......m.........|
而key2则是对xorkey使用类似校验和的算法计算而来,此处它的值为0x90。
获得key1,xorkey,key2 之后使用以下代码片段解密Payload,可以看出Payload的最后一个字节也是一个密钥。这个算法在MystRodX的多个场景中重复使用,如AES密钥的解密,激活报文的解密等,我们称之为MystRodX_Transform。
经过分析后,我们使用Python实现了对该算法的模拟,详情见Appendix章节的Transform Algorithm部分。实际使用只需提供magic,magic2,以及key即可。例如解密Payload,magic为上文所说的key1 0x13,magic2为Payload的最后一字节 0xab,key使用key_for_dropper。
解密后的Payload中包含3个关键文件chargen,busybox,daytime。其中daytime为Launcher组件,负责启动chargen;chargen为核心组件MystRodX后门。Payload 的校验机制依赖 C2 0A D7 A4 22 21 5A
这一 7 字节的校验值。Dropper会比对该值,仅在匹配时才会释放 Launcher 和 MystRodX 后门。
Launcher分析
Launcher使用相同的字串加密算法,解密后的clog,dlog用于保存MystRodX,Launcher的pid。它的核心功能是持续监控MystRodX后门进程chargen的运行状态,若发现chargen未运行,重新启动该后门进程。
MystRodX后门分析
MystRodX是一个C++实现的典型后门,样本中的类名清晰的揭示了它支持的功能,比如文件管理,反弹shell,socks代理,端口转发等。
由于篇幅限制,本文不再对常见功能展开分析,而是从主机行为,网络协议俩个方面,对MystRodX 的特色功能进行剖析,包括:
- 双进程守护机制
- 配置信息的解密
- 通信协议
- 被动后门模式
0x1: 双进程守护
MystRodX会持续监控daytime进程的运行状态。如果发现daytime未运行,MystRodX会立即启动重Launcher进程。这样,Launcher和MystRodX就形成了双进程守护机制,俩者中任意一个进程终止,都会被对方重新拉起,确保长期稳定运行。
0x2: 配置解密
MystRodX的配置使用AES加密,AES密钥和Payload一样使用Transform算法保护,只不过key1,xorkey,key2的值有所不同。
key1:0xd
xorkey
00000000 00 02 07 11 13 19 04 06 16 0e 18 0b 02 2d 0b 19 |.............-..|
00000010 a0 91 02 23 96 45 6c 1c b1 d2 7f e3 22 00 00 00 | ..#.El.±Ò.ã"...|
key2:0xf1
以下是AES相关的密文与解密后的明文,AES密钥从明文的0x08偏移处开始,长度为32字节。
使用上述 AES 密钥,配合硬编码的 IV 0D 0F 02 04 08 07 2D 1C 01 04 0D 01 02 07 06 02
,采用CBC模式即可解密配置信息,感兴趣的读者可以参阅Appendix的CyberChef。
以下为样本72d377fa8ccf23998dd7c22c9647fc2a的配置:
以下为样本a46f2c771fb580e2135ab898731be9a7的配置:
配置中包含活动名、时间、C2,端口,公钥等信息。下表列出了各属性及其在配置中的偏移量(注:配置因样本而异):
Offset | Field |
---|---|
0x00 | Campaign |
0x08 | Backdoor Type |
0x0c | MainC2 Port |
0x10 | BackupC2 Port |
0x1c | Interval |
0x24 | Effective date |
0x78 | Main C2 |
0x178 | Backup C2 |
0x278 | Public Key |
当Backdoor Type等于1时,MystRodx进入被动后门模式,等待激活报文;当Backdoor Type的值不为1时,MystRodX进入主动后门模式与配置中的C2建立通信,等待执行下发的指令。目前捕获的俩个样本中的Backdoor Type的值均为0。
0x3: 网络通信
MystRodX 后门支持 TCP 和 HTTP 两种通信模式,并可配置是否启用 AES 加密。当前捕获的样本均采用 TCP 模式,且未启用加密功能。网络报文格式为Packet Length (4bytes) + Main Code(4 bytes) + Sub Code(4 bytes) + Packet Direction(4 bytes) + Data
。
以报文10 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00
为例,它表示该报文由于BOT发往C2,长度为16字节,MainCode,SubCode分别为1,其实它正是MystRodX 的上线报文。
Little Endian
10 00 00 00 ---> Pakcet length, 0x10 bytes
01 00 00 00 ---> Main Code, 0x01
01 00 00 00 ---> Sub Code, 0x01
01 00 00 00 ---> Direction, 0x01, bot_to_c2
协议中的MainCode的值可以是:1,2,5,7,8。其中2、5、7、8分别对应反弹shell、文件管理、端口转发和socks管理功能。
而1则表示通用管理功能,主要用于C2对Bot的控制操作,例如更新配置文件、上传设备信息等。这些操作被分配了不同的SubCode,下表为SubCode以及它们对应的功能。
SubCode | Function |
---|---|
1 | Beacon |
2 | Uplaod DeviceInfo |
4 | Heartbeat |
7 | Enable Traffic encryption |
14 | Set a new interval |
15 | Update Configuration |
16 | Teardown |
19 | Upload TimeInfo |
以实际捕获的流量为例,当bot收到MainCode为1,SubCode为2的指令后,就会将设备信息上报给C2。
另外值得一提的是,当启用流量加密后,网络报文格式有所变化,升级为CipherText Length(4bytes)+ PlainText Length(4bytes) + padding(8bytes) + CipherText
。
总结
至此,我们对 MystRodX 的分析暂告一段落。以上是目前所掌握的全部相关情报,网络管理员可参考技术分析中的各项细节,以判断自身系统是否已遭受该后门入侵。
由于视野所限,我们目前尚不清楚 MystRodX 的具体入侵途径、攻击目标与真实意图。我们诚挚欢迎掌握更多信息的业内伙伴向我们提供情报,共同助力网络安全防御。
如果您对我们的研究感兴趣,或了解与该后门相关的线索,欢迎通过X平台与我们联系。
IOC
Downloader
http://139.84.156[.]79/dst-x86.bin
C2 & Campaign
airtel.vpndns.net:443 neybquno
149.28.130.195:443 zoufkcfr
149.28.137.254:8010 neybquno
149.28.137.254:8443 zoufkcfr
156.244.6.68:443 unknown
185.22.153.228:443 unknown
Sample MD5
Dropper
5e3a2a0461c7888d0361dd75617051c6 *dst
72d377fa8ccf23998dd7c22c9647fc2a *chargen
5bf67ce1b245934965557de6d37f286f *daytime
fa3b4d5fd1f6c995395244f36c18ffec *dst
a46f2c771fb580e2135ab898731be9a7 *chargen
e8fcb7f3f0edfc7d1a99918dc14527d1 *daytime
1f003437e3d10e07f5ee5f51c61c548f *networkd
Patched By Xlab
4dc20d1177da7932be3d63efe939b320
2775d9eac1c4a5eb2c45453d63ea6379
4db35e708c2d0cabe4709fa0540bafb7
Public Key
neybquno
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs7/nw8KnB3Ow2uUR1bNW
60UQKOI7emuau8AyCK4KqK/iUGQJzOoopLgi2D4DWrK5Wi+qtgLPt7WSTFUnMGge
XRbXdHamEasF/8kNhuv7F/CKSc+sCy/TrtLeYAQH4nuT+PhMym0aOLEwSJIuDu+4
wgUzONdgpkZZnx2h8TQmzv3LmeQWx1iOk+L4SrwbG3Cs889eWlj2O66hyT5kz6s5
6HxRjZD4V1zuWzcuoNpdqaKKA4DaraF4onYNNctIiSdkaTKPeJaim+whljmuFn8Q
y9WKcT2yogoUaUd3fkx+MPaK80R6nIEN+ooreBkf2eXXJwuTRFl1eocaUENENo5h
QwIDAQAB
-----END PUBLIC KEY-----
zoufkcfr
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5blT2R1XzP3T0Eu0vatg
u8h15ysd+TYQWYCrm1LT9bISVx9Jhzhbf3l5oFQD/TBstZQ6hjhUZuDCczdaYZJu
4HVzhkmVKsyjLV16aG5mCbDiF/bR879jSDJMZoqZJOitAA0xQQ2FqmuOxlFkN8Ab
Rd87xcDTF/SzWcV2nj6UlNHcFilxz48kai3/lcypnIoUtnEMtkMGsRX81LVniyUm
yrvvRAA7PQqHa1qFbJSt3xY+FAzC/Iy6QbSnrMoc8FVMCDUR/YKLCDU2c3SUshUs
Xkanh6odvXOBjEKoEbaBgc3Bb2uAPdiDkEGqDiZl0yitzopA9+f+606Q5UG9CVcW
OwIDAQAB
-----END PUBLIC KEY-----
Appendix
Transform Algorithm
key_for_dropper=bytes.fromhex('02 06 03 09 04 02 0e 0a 01 0f 08 0a 04 0d 0b 09
0a 09 01 03 06 05 6d 0c 01 02 0f 03 03 0a 05 00')
key_for_backdoor=bytes.fromhex('00 02 07 11 13 19 04 06 16 0E 18 0B 02 2D 0B 19
A0 91 02 23 96 45 6C 1C B1 D2 7F E3 22 00 00 00')
def calc_sum(buf):
checksum = 0
for i, v in enumerate(key):
checksum ^= (v << (i&7)) & 0xFF
return checksum
def transform(magic,magic2,buf,key):
buf_len=len(buf)-1
key_len=len(key)
key1=magic ^ calc_sum(key)
key2=(key[(key1^buf_len)%key_len]) ^ magic2 ^ buf_len
out=bytearray()
for i, value in enumerate(buf):
out.append((key[(i^key1)%key_len] ^ key2 ^ value ^ i)&0xff)
return out
CyberChef
https://gchq.github.io/CyberChef/#recipe=AES_Decrypt(%7B'option':'UTF8','string':'z7bcjTSKrFiHYUB63NZendVvtJ2RGfo8'%7D,%7B'option':'Hex','string':'0d%200f%2002%2004%2008%2007%202d%201c%2001%2004%200d%2001%2002%2007%2006%2002'%7D,'CBC','Raw','Raw',%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D)To_Hexdump(16,false,false,false)&input=PBpcVtR8VHCFl/oaqAGk0w7pCVMMe1xQ1Ma0FBs2X2P9vpD6GrVC/b6XqKDWb/eFS/g9najMHOO3r38h3V9lZvvSKl31GM2FJbIKw91n/r6Z9TgKmrlLdLroahpV91HmQPi2ttGAyXrF9SmsLMCBqA6X5fIPZ/v3cEI69nKREj1Fq%2BHffi6q4s3sfzgDmFDZL9XFff9g2AtSVm7MLBAhNjMXqifFPxIbo5L0McZ%2B%2B78Wrdv3VnsvZIZTBLLM%2BEY/EqiKf73OIvmRGrI3Q4ksiGyG8CTcau6hrlJUN91IWdSjRU0vNPxvwIU4qy9aTSKhTI2Be2Cc53B3aRu%2BGKMcFG0d/IioT0fb1MxeIMPKtPViBzHRRj0OGbK5OFpX0nfdTyAEW85fnXos14I6yO7%2B/JfsaF4YQv7OVCKgQnYXFrjMMajtE%2BoiGInB6d4ybrNNXA3u3p%2BQ3leErM8yuIpvzSre6wPsyJ4VZxyPQA4iRn1AnZO7QA5UG2IzqPCXZfAvLHhvMqMNI9D8bwInx1pnVdx2kwHQhxvyzLGFxkVrhvTcZSGSG708jkAYfzjItoPANBc0WMg0NWuSs53gVmuc/UJk%2BvEiZTjHayg4o1yLANpPtRTfmIMcLfSRIw2BCdthqmPLwx8L46rvUycpHvL3Nb7vl9Uwr12%2BqRjMQj5aaLg4veTaOnRCSJTjVq9aRrzjZutk1hb9CiS/JigJYJoxhCnZ82ZpTIzrjMR8RjES5UX9%2B9/3xkARRcAunSTQP8SZiPVuMOXTHyKB8nr7NsfoUeQ1ixisswp7E3FOqmel92N2CdmrifZzdD3KmnPubHhM5OIX7x0X9004py1zlMSZCAPPLvrCxLpBwqkmuxNjlW7Qz6FKMgXoiwucVrYUzj3rWPBpENrqBAkWvKR3c9Y6dKzTmOPT/CRsEvdbe/l5MWmg5n7vog0TOR3TQpaDRBVC6HMsCSIS/NG0lteKVEevZQDQvSqtWbjMneAUvQ8RLEl8e7CDAQN7xfmQpdRVbaqUtD7hzvz9pfsHgWCG5g0lMkYA6NQFtfyH98/DwB/Jo5fmUANQZGu8XJ6pDF7KSqbqKDxk2EzVNK7po3llMavonwq9JxHk8xoywqGhNoKLWbFlatzFx6fTqn%2BtLZBZcYzb/csSzWeq9t3ireaZw3EJGaxOX09YvlTZbCMIyIEed17qkdNbufSJ4hPWsLHzmnihehvy1xOPlmVX%2BjLnBHRX5mNgVdWednIL0duHduvvCOejxcn5QFTwaspWfeSXYXlNoMFrVfCvrv%2BscinLs2OvtUlBV3mijU2pnE0tmTn%2BZqpYCeht5cWA5VAPbz63mOEIAl9%2BNcYsrUAaZf51jiyzhBI%2BW0pH5kATshWsI0Ltl6rThYzCOYdgzaSRDEjOw/dNqJdK2k8Ut4t5uUvcgw4oryOrhQOJVaVcGX%2BvRVnwYzfeF5ryWFbfvlVp661XNlA7