
स्व-निहित Docker प्रयोगशाला जो CVE-2023-24329 का प्रदर्शन करती है, एक Python urllib पार्सर डिफरेंशियल जो URL स्कीम और होस्ट फ़िल्टर को बायपास करता है, जिसमें हैंड्स-ऑन सुरक्षा शिक्षा के लिए कमजोर और पैच किए गए वातावरण शामिल हैं।
केवल शैक्षिक उपयोग। यह प्रयोगशाला एक सुरक्षित, पृथक वातावरण में एक वास्तविक कमजोरी को प्रदर्शित करने के लिए मौजूद है। इसे उन प्रणालियों पर कभी न चलाएं जिनके आप स्वामी नहीं हैं। किसी भी उत्पादन प्रणाली में जानबूझकर तोड़े गए फ़िल्टर कोड का पुनः उपयोग कभी न करें।
एक स्व-निहित Docker प्रयोगशाला जो CVE-2023-24329 — Python के urllib.parse.urlparse() में एक पार्सर विभेद का प्रदर्शन करती है, जो Python < 3.11.4 पर URL योजना और होस्ट फ़िल्टर को बायपास करने की अनुमति देता है।
प्रयोगशाला एक API दिखाती है जो स्पष्ट रूप से file:// URL और आंतरिक होस्टनामों को ब्लॉक करती है, जिसे अपने स्वयं के कंटेनर से /etc/passwd पढ़ने और एक निजी आंतरिक सेवा को हिट करने के लिए धोखा दिया जा सकता है — फिर यह साबित करती है कि वही एक्सप्लॉइट पैच किए गए Python पर विफल हो जाता है।
Python का urlparse() और अंतर्निहित HTTP/फ़ाइल फ़ेचर्स इस बात पर असहमत हैं कि अग्रणी रिक्त स्थान वाले URL को कैसे संभाला जाए। प्रभावित संस्करणों पर:
from urllib.parse import urlparse
urlparse(" file:///etc/passwd").scheme # → "" (खाली — फ़िल्टर पास)
urlparse(" file:///etc/passwd").hostname # → None (खाली — फ़िल्टर पास)
लेकिन urllib.request.urlopen(" file:///etc/passwd") रिक्त स्थान को हटा देता है और वैसे भी file:///etc/passwd को लाता है।
वह अंतर जो पार्सर देखता है और जो फ़ेचर करता है — यही कमजोरी है।
Python 3.11.4 ने पार्स करने से पहले अग्रणी रिक्त स्थान/नियंत्रण वर्णों को हटाकर इस अंतर को बंद कर दिया।
| चरण | आप क्या देखते हैं | यह क्या सिखाता है |
|---|---|---|
| 1 — मूल | file:///etc/passwd → 403 blocked scheme | फ़िल्टर उचित दिखता है |
| 2 — एक्सप्लॉइट | एक स्थान उपसर्ग के साथ वही URL → 200 + /etc/passwd और आंतरिक रहस्य की सामग्री | एक स्थान पूरे फ़िल्टर को हरा देता है |
| 3 — पैच | Python 3.11.4 के विरुद्ध वही पेलोड → 403 blocked | पैच किया गया urlparse पहले रिक्त स्थान हटाता है; फ़िल्टर इसे सही ढंग से पकड़ता है |
एक पृथक Docker ब्रिज नेटवर्क (cve-lab-net) पर चार सेवाएँ:
| सेवा | Python संस्करण | भूमिका | होस्ट पोर्ट |
|---|---|---|---|
vulnerable-api | 3.11.3 | भोले URL फ़िल्टर के साथ लक्ष्य API | 8000 |
fixed-api | 3.11.4 | समान कोड, पैच किया गया इंटरप्रेटर | 8000 |
internal-service | 3.12 | नकली आंतरिक मेटाडेटा एंडपॉइंट | कोई नहीं |
attacker | 3.12 | एक्सप्लॉइट ड्राइवर | कोई नहीं |
internal-service का कोई होस्ट पोर्ट मैपिंग नहीं है — यह केवल Docker नेटवर्क के अंदर से पहुंच योग्य है, एक वास्तविक विश्वास सीमा का अनुकरण करता है।
git clone <repo-url>
cd CVE-2023-24329-lab
docker compose -f docker-compose.vulnerable.yml up --build -d
docker compose -f docker-compose.vulnerable.yml exec attacker python exploit.py baseline

docker compose -f docker-compose.vulnerable.yml exec attacker python exploit.py exploit

docker compose -f docker-compose.vulnerable.yml down
docker compose -f docker-compose.fixed.yml up --build -d
docker compose -f docker-compose.fixed.yml exec attacker python exploit.py verify

docker compose -f docker-compose.fixed.yml down
CVE-2023-24329-lab/
├── docker-compose.vulnerable.yml # Python 3.11.3 (प्रभावित)
├── docker-compose.fixed.yml # Python 3.11.4 (पैच)
├── vulnerable-api/
│ ├── app.py # भोले फ़िल्टर के साथ Flask API
│ ├── requirements.txt
│ └── Dockerfile
├── internal-service/
│ ├── app.py # नकली आंतरिक मेटाडेटा एंडपॉइंट
│ ├── requirements.txt
│ └── Dockerfile
└── attacker/
├── exploit.py # डेमो ड्राइवर (baseline / exploit / verify)
├── requirements.txt
└── Dockerfile
कमजोर और फिक्स की गई API सेवाएँ समान स्रोत कोड साझा करती हैं — केवल आधार छवि Python संस्करण भिन्न है। यह प्रयोगशाला का मुख्य वैज्ञानिक-नियंत्रण गुण है।
कमजोर API फ़िल्टर (सरलीकृत):
parsed = urllib.parse.urlparse(url)
if parsed.scheme.lower() in {"file", "gopher", "ftp", "data"}:
return 403 # blocked
if parsed.hostname in {"localhost", "127.0.0.1", "internal-service"}:
return 403 # blocked
urllib.request.urlopen(url) # मूल, असंशोधित स्ट्रिंग लाओ
बायपास पेलोड एक एकल अग्रणी स्थान है:
file:///etc/passwd
^
space (0x20)
Python ≤ 3.11.3 पर, urlparse एक खाली योजना और कोई होस्टनाम देखता है → फ़िल्टर पास। urlopen स्थान हटाता है → file:///etc/passwd लाता है।
Python ≥ 3.11.4 पर, urlparse पहले स्थान हटाता है → सही ढंग से scheme=file देखता है → फ़िल्टर 403 के साथ ब्लॉक करता है।
CPython मुद्दा #102153 — फिक्स पार्स करने से पहले URL की शुरुआत से C0 नियंत्रण वर्ण और स्थान हटाता है। पैच के बाद पार्सर और फ़ेचर दोनों इस बात पर सहमत होते हैं कि URL क्या है, इसलिए फ़िल्टर को इस तरह बायपास नहीं किया जा सकता।
Python संस्करण की परवाह किए बिना सही रक्षात्मक पैटर्न:
# पार्स करें → भागों से पुनर्निर्माण करें → पुनर्निर्मित URL को डाउनस्ट्रीम पास करें।
# फ़िल्टर और फ़ेचर दोनों फिर उसी स्ट्रिंग पर काम करते हैं।
parsed = urllib.parse.urlparse(url)
safe_url = parsed.geturl() # घटकों से पुनर्निर्मित
urllib.request.urlopen(safe_url)
${jndi:...} बायपास को संचालित करता है।internal-service पोर्ट को कभी भी होस्ट पर एक्सपोज़ न करें।vulnerable-api/app.py में फ़िल्टर कोड शिक्षण उद्देश्यों के लिए जानबूझकर तोड़ा गया है — इसे किसी भी वास्तविक प्रणाली में कॉपी न करें।MIT — शैक्षिक उद्देश्यों के लिए एट्रिब्यूशन के साथ उपयोग, साझा और अनुकूलन करने के लिए स्वतंत्र।