Mirai源码分析
大概看了下整体结构和流程,然后细看了一下加解密部分。
代码结构:
1 2 3 4 5 6
| loader/src 将payload上传到受感染的设备 mirai/bot 在受感染设备上运行的恶意payload mirai/cnc 恶意者进行控制和管理的接口 mirai/tools 提供的一些工具
其中,cnc部分是Go语言编写的,余下都是C语言
|
整体网络拓扑关系如下图所示,受感染的设备扫描其他可能受感染的设备,扫描到之后就讲设备信息等提供给loader,loader将payload下载到可能受感染的设备上,比如宏病毒,js下载者等。被感染的设备与c2服务器连接,并向特定受害者发起ddos攻击。

loader
主要功能是向感染设备上传(wget、tftp、echo方式)对应架构的payload文件
目录结构
1 2 3 4 5 6 7
| headers/ 头文件目录 binary.c 将bins目录下的文件读取到内存中,以echo方式上传payload文件时用到 connection.c 判断loader和感染设备telnet交互过程中的状态信息 main.c loader主函数 server.c 向感染设备发起telnet交互,上传payload文件 telnet_info.c 解析约定格式的telnet信息 util.c 一些常用的公共函数
|
1)通过待感染节点的telnet用户名和密码成功登录;
2)执行/bin/busybox ps,根据返回结果kill掉某些特殊进程;
3)执行/bin/busybox cat /proc/mounts,根据返回结果切换到可写目录;
4)执行/bin/busybox cat /bin/echo,通过返回结果解析/bin/echo这个ELF文件的头部来判断体系架构,即其中的e_machine字段;
5)选择一种方式上传对应的payload文件,当然首先需要进行判断
6)执行payload并清理
payload
发起DoS攻击以及扫描其它可能受感染的设备,代码在mirai/bot目录,可简单划分为如下几个模块
- scanner:扫描其它可能受感染的设备,如果能满足telnet弱口令登录则将结果进行上报,恶意者主要借此扩张僵尸网络
- attack:解析下发的攻击命令并发动DoS攻击
- killer:此模块主要有两个作用,其一是关闭特定的端口并占用,另一是删除特定文件并kill对应进程,简单来说就是排除异己
- public:主要是一些常用的公共函数,供其它几个模块调用
table.c中的table_unlock_val
、table_retrieve_val
和 table_lock_val
函数组合,即获取table中的数据,程序中用到的一些信息是硬编码后保存到table中的,如果获取就要用到这个组合,其中涉及到简单的异或加密和解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
void table_init(void);
void table_unlock_val(uint8_t id);
void table_lock_val(uint8_t id);
char *table_retrieve_val(int id, int *len);
static void add_entry(uint8_t id, char *buf, int buf_len);
static void toggle_obf(uint8_t id);
|
一个具体的例子如下所示。所以加密字符串可以寻找类似的\x
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| add_entry(TABLE_EXEC_SUCCESS, "\x4E\x4B\x51\x56\x47\x4C\x4B\x4C\x45\x02\x56\x57\x4C\x12\x22", 15);
uint8_t k1 = table_key & 0xff, k2 = (table_key >> 8) & 0xff, k3 = (table_key >> 16) & 0xff, k4 = (table_key >> 24) & 0xff;
for (i = 0; i < val->val_len; i++) { val->val[i] ^= k1; val->val[i] ^= k2; val->val[i] ^= k3; val->val[i] ^= k4; }
|
cnc
cnc目录主要提供用户管理的接口、处理攻击请求并下发攻击命令
1 2 3 4 5 6
| admin.go 处理管理员登录、创建新用户以及初始化攻击 api.go 向感染的bot节点发送命令 attack.go 处理用户的攻击请求 clientList.go 管理感染的bot节点 database.go 数据库管理,包括用户登录验证、新建用户、处理白名单、验证用户的攻击请求 main.go 程序入口,开启23端口和101端口的监听
|
tools目录主要提供了一些工具,相应的功能如下
1 2 3 4 5
| enc.c 对数据进行异或加密处理 nogdb.c 通过修改elf文件头实现反gdb调试 scanListen.go 监听payload(bot)扫描后上报的telnet信息,并将结果交由loader处理 single_load.c 另一个loader实现 wget.c 实现了wget文件下载
|
enc.c中table_key = 0xdeadbeef被硬编码到里面,不过可能不是所有样本都这样(?
加解密逻辑和table.c中的基本一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| int main(int argc, char **args) { **************if (argc != 3) { printf("Usage: %s <string | ip | uint32 | uint16 | uint8 | bool> <data>\n", args[0]); return 0; } printf("XOR'ing %d bytes of data...\n", len); data = x(data, len); for (i = 0; i < len; i++) printf("\\x%02X", ((unsigned char *)data)[i]); printf("\n"); }
void *x(void *_buf, int len) { unsigned char *buf = (char *)_buf, *out = malloc(len); int i; uint8_t k1 = table_key & 0xff, k2 = (table_key >> 8) & 0xff, k3 = (table_key >> 16) & 0xff, k4 = (table_key >> 24) & 0xff;
for (i = 0; i < len; i++) { char tmp = buf[i] ^ k1;
tmp ^= k2; tmp ^= k3; tmp ^= k4;
out[i] = tmp; }
return out; }
|
参考
https://github.com/jgamblin/Mirai-Source-Code/blob/master/mirai/tools/enc.c
https://paper.seebug.org/142/#21-payload
Mirai样本分析
MD5: 9dd6dd5bd577226323ba207c5e1127e2
joesandbox : https://www.joesandbox.com/analysis/683525?idtype=analysisid#iocs
为数不多的ip地址可以直接搜索到的样本

主要加密函数如下图所示,和源码的差不多

密钥和源码一样

应该还是可以先做针对通用的:已知密文的字符串特征(\x…), 密钥(0xdeadbeef), 然后解密之后再匹配ip地址或域名等。 针对更复杂的话,可能需要针对不同的样本实现方式再进一步分析。