
aiohttp CWE-444 अनुरोध तस्करी को अस्वीकृत WebSocket अपग्रेड के माध्यम से पुनः उत्पन्न करता है, Python/Rust पेलोड और Docker लैब के साथ जो प्रॉक्सी एक्सेस-नियंत्रण बाईपास प्रदर्शित करती है।
aiohttp < 3.14.2 में अस्वीकृत WebSocket अपग्रेड के माध्यम से अनुरोध स्मगलिंग।
जब कोई रिवर्स प्रॉक्सी Connection: Upgrade + Upgrade: websocket हेडर फॉरवर्ड करता है,
तो कमजोर aiohttp पार्सर अनुरोध बॉडी को छोड़ देता है और अंतिम बाइट्स को
पाइपलाइन अनुरोध के रूप में व्याख्या करता है — एज एक्सेस नियंत्रणों को बायपास करते हुए।
aiohttp 3.14.2 में ठीक किया गया (कमिट 6ae358f)।
लेखक: João Victor Botelho (JV Botelho) — https://glitchedcat.com
पायथन संस्करण को कॉपी-पेस्ट करें (शून्य निर्भरताएँ, केवल stdlib):
curl -O https://raw.githubusercontent.com/JVBotelho/cve-2026-69243-poc-aiohttp-smuggling/main/poc.py
python3 poc.py <proxy-host> <proxy-port> <backend-host>
या रस्ट संस्करण बनाएँ (शून्य निर्भरताएँ, केवल std):
git clone https://github.com/JVBotelho/cve-2026-69243-poc-aiohttp-smuggling
cd cve-2026-69243-poc-aiohttp-smuggling/poc
cargo build --release
./target/release/cve-2026-69243-poc <proxy-host> <proxy-port> <backend-host>
प्रीबिल्ट बाइनरी को रिलीज़ वर्कफ़्लो के माध्यम से Releases पर प्रकाशित किया जाएगा।
दोनों बाइट-समान पेलोड उत्पन्न करते हैं (CI पैरिटी परीक्षण द्वारा सुनिश्चित)। यदि लैब चल रही है:
python3 poc.py nginx-upgrade 80 backend-vuln
अपेक्षित आउटपुट: 1 HTTP प्रतिक्रिया (WebSocket upgrade rejected)। फिर सत्यापित करें:
# Backend processed 2 requests (/ws + smuggled /admin):
docker logs backend-vuln | grep -c '"path".*"/admin"'
# Nginx only logged 1 request (the /ws):
docker exec nginx-upgrade cat /logs/nginx-upgrade.access.log | grep -c '/admin'
बैकएंड गिनती > 0 और Nginx गिनती = 0 का मतलब है CWE-444 विभाजन पुष्ट। यह PoC एक एकल TCP खंड भेजता है — बॉडी ही स्मगल किया गया अनुरोध है; Nginx इसे बॉडी मानता है, aiohttp इसे दूसरा अनुरोध मानता है।
_http_parser.pyx बॉडी खपत होने से पहले
अपग्रेड डिटेक्शन पर 2 (स्किप बॉडी) लौटाता है (लाइन ~863)। बॉडी बाइट्स
_message_tail में रहती हैं और web_protocol.py के finish_response
में पार्सर को वापस फीड की जाती हैं (लाइन ~771)।location /admin { deny all; } होता है,
स्मगल किया गया /admin फिर भी बैकएंड तक पहुँचता है क्योंकि Nginx रूटिंग
निर्णय केवल बाहरी अनुरोध पर किए जाते हैं।await request.read() 0 बाइट्स लौटाता है — बॉडी हैंडलर परत के नीचे रोक दी जाती है।
पैच करें, या प्रॉक्सी पर उन रूट्स के लिए अपग्रेड हेडर हटाएँ जिन्हें प्रोटोकॉल
स्विच नहीं करना चाहिए।git clone https://github.com/JVBotelho/cve-2026-69243-poc-aiohttp-smuggling
cd cve-2026-69243-poc-aiohttp-smuggling
docker compose up -d
# Run the PoC:
docker compose run --rm --entrypoint /app/poc attacker nginx-upgrade 80 backend-vuln
सेवाएँ:
चरण 1-3 के पूर्ण निष्कर्ष findings/ में।
Connection: close भेजते हैं या Connection/Upgrade हेडर हटाते हैं,
वे असुरक्षित नहीं हैं। विभाजन को उजागर करने वाला कॉन्फ़िग Nginx के स्वयं के
प्रॉक्सिंग दस्तावेज़ से लिया गया विहित WebSocket map स्निपेट है।/ws प्रतिक्रिया प्राप्त होती है। स्मगलिंग का
सबूत बैकएंड लॉग में है, हमलावर की प्रतिक्रिया में नहीं — इस टोपोलॉजी में एक ब्लाइंड,
एकतरफा प्रिमिटिव है। अन्य प्रॉक्सी टोपोलॉजी का परीक्षण नहीं किया गया।Transfer-Encoding: chunked स्मगल नहीं करता है — कच्ची चंक-आकार लाइन
(जैसे 3e) पार्सर को अमान्य मेथड के रूप में लगती है और कनेक्शन समाप्त हो जाता है।
Nginx के माध्यम से यह काम करता है, लेकिन सामान्यीकरण के द्वारा: Nginx बॉडी को
de-chunk करता है और एक संश्लेषित Content-Length फॉरवर्ड करता है, इसलिए बैकएंड
उसी CL पथ के माध्यम से शोषित होता है। --chunked फ़्लैग प्रॉक्सी पथ को प्रदर्शित करता है।WebSocketResponse लौटाना चाहिए। अधिकांश ऐप जो किसी रूट पर
WebSocket का उपयोग नहीं करते, वे डिफ़ॉल्ट रूप से अस्वीकार कर देंगे (फ्रेमवर्क 404
लौटाता है या अगले हैंडलर पर चला जाता है)।poc/ # Rust cargo project
├── Cargo.toml
├── src/main.rs # CLI binary
├── src/lib.rs # Library + unit tests
├── tests/parity.rs # Cross-language payload parity test
└── fuzz/ # cargo-fuzz targets
poc.py # Python PoC (copy-paste from blog)
attacker/ backend/ frontend/ # Docker lab services
docker-compose.yml # 7-service lab
findings/ # Research notes (Phase 1-3)
.github/workflows/
├── ci.yml # Build, test, clippy, parity, integration, fuzz
└── release.yml # Cross-compile + GitHub Release
पूर्ण विश्लेषण के लिए findings/fase3-deteccao.md देखें। सारांश, उन
चेतावनियों के साथ जो प्रोडक्शन में मायने रखती हैं:
X-Forwarded-For/Proxy Protocol को सामान्यीकृत करना आवश्यक है, या एक
अपस्ट्रीम कनेक्शन ID + प्रति-कनेक्शन अनुरोध अनुक्रम लॉग करना आवश्यक है। केवल
क्लाइंट IP + समय विंडो कमजोर है (NAT, keep-alive, समवर्तीता)।content_length बनाम request.read() से बाइट्स):
3.14.1 पर सक्रिय होता है, 3.14.2 पर शांत। पहचान करता है, शमन नहीं करता।
इसे सीमित करें (अपग्रेड-उम्मीदवार रूट्स, छोटी बॉडी, गैर-101 स्थितियाँ) —
नैव संस्करण हर बॉडी को मेमोरी में बफर करता है।reqlen — अकेले कम
विश्वास (cookies/JWT/tracing हेडर शोरगुल वाले होते हैं), लेकिन जब क्लाइंट कोई
Content-Length नहीं भेजता (chunked इनग्रेस) तो यह एकमात्र एज सिग्नल है।| Container | Purpose |
|---|
backend-vuln | aiohttp 3.14.1 (असुरक्षित), READ_BODY=false |
backend-vuln-read | aiohttp 3.14.1, READ_BODY=true (सिद्ध करता है कि हैंडलर मदद नहीं कर सकता) |
backend-patched | aiohttp 3.14.2 (ठीक किया गया) |
nginx-upgrade | अपग्रेड हेडर फॉरवर्ड करता है (deny all on /admin) |
nginx-default | कोई अपग्रेड फॉरवर्डिंग नहीं (बग को निष्क्रिय कर देता है) |
nginx-strip | Connection "" स्ट्रिप (बग को निष्क्रिय कर देता है) |
attacker | रस्ट बाइनरीज़: reproduce, fase2, poc |