
nginx कॉन्फ़िग्स में CVE-2026-42945 rewrite पैटर्न का पता लगाता है: प्रतिस्थापन में ? के साथ rewrite, साथ ही उसी location में उपभोग किया गया अनाम कैप्चर
उन कॉन्फ़िगरेशनों को ढूँढता है जो CVE-2026-42945 के प्रति संवेदनशील हैं, जो nginx के ngx_http_rewrite_module में हीप बफर ओवरफ़्लो है।
केवल प्रभावित nginx संस्करण (0.6.27 से 1.30.0 तक) चला लेना पर्याप्त नहीं है कि इसे एक्सप्लॉइट किया जा सके। कॉन्फ़िगरेशन में निर्देशों की एक विशिष्ट जोड़ी होनी चाहिए, और वह जोड़ी दुर्लभ है: वास्तविक-दुनिया के कॉन्फ़िगरेशनों की दो स्वतंत्र स्कैन में 1465 में से शून्य और 35633 में से एक एक्सप्लॉइटेबल मिला। यह स्क्रिप्ट आपको बताती है कि आप उस रेखा के किस ओर हैं।
एक rewrite जिसके replacement में ? के बाद arguments हों, उसके बाद उसी location में पढ़ा गया एक अनाम कैप्चर ($1 से $9):
location / {
rewrite ^(.*) /new?c=1; # the ? here raises the internal is_args flag
set $myvar $1; # ...which was never cleared, and leaks into this
return 200 $myvar;
}
एक पास कच्चे स्ट्रिंग के लिए बफर का आकार तय करता है, अगला उसमें एक एस्केप्ड संस्करण कॉपी करता है। दोनों हिस्से अपने आप में सही दिखते हैं।
नीचे दिया गया हर नियम अनुमान से नहीं, बल्कि nginx 1.30.0 पर मापकर तय किया गया है, क्योंकि प्रकाशित विवरणों में उनमें से दो गलत हैं।
दो निहितार्थ जिन्हें स्पष्ट कहना ज़रूरी है:
अंत में आने वाला ? ख़तरनाक नहीं है। /new/$1? इसी तरह से विरासत में मिली क्वेरी स्ट्रिंग को हटाया जाता है, और यह काफी बड़ी संख्या में माइग्रेशन कॉन्फ़िगरेशनों में मिलता है। हर ? को फ़्लैग करना आधे इंटरनेट पर चिल्लाने जैसा होगा।
"Named captures सुरक्षित हैं" कहना गलत है। मायने यह है कि कैप्चर को कैसे पढ़ा जाता है, न कि इसे कैसे घोषित किया गया था। $1 के रूप में पढ़ा गया एक नेम्ड ग्रुप बिल्कुल अनाम कैप्चर की तरह क्रैश करता है।
इसी मापे गए कारणों से अनदेखा भी किया जाता है: regex के अंदर ? (एक क्वांटिफायर), और redirect / permanent / break, जो consumer के चलने से पहले प्रोसेसिंग समाप्त कर देते हैं।
nginx -T | python3 check_rewrite.py
python3 check_rewrite.py /path/to/dump.txt
python3 check_rewrite.py --json /path/to/dump.txt
केवल Python 3, स्टैंडर्ड लाइब्रेरी।
एग्ज़िट कोड: 0 साफ़, 1 एक जोड़ी मिली, 2 कॉन्फ़िग पढ़ा या पार्स नहीं किया जा सका। तीसरा ही मुद्दा है: एक बंद न हुआ quote या असंतुलित braces विश्लेषण को काट देते हैं, और एक चेकर जो उस फ़ाइल के लिए "कुछ नहीं मिला" कहता है जिसे वह पढ़ नहीं सका, उस चेकर से बदतर है जो क्रैश करता है। जब ऐसा होता है तो वह यह बताता है और 2 लौटाता है।
इसे nginx -T खिलाएँ, अलग-अलग फ़ाइलें नहीं: includes कहीं भी हो सकते हैं, और एक जनरेटेड कॉन्फ़िग केवल चल रहे सर्वर पर ही सत्य होती है। निष्कर्ष उस फ़ाइल और लाइन के विरुद्ध रिपोर्ट होते हैं जहाँ निर्देश वास्तव में रहता है, न कि डंप में ऑफ़सेट के आधार पर।
$ python3 check_rewrite.py samples/vuln-nginx-T.txt
[HIGH] находка #1
location: location / (/etc/nginx/nginx.conf:14)
rewrite: rewrite ^(.*) /new?c=1 (/etc/nginx/nginx.conf:15)
захват $N: set -> set $myvar $1 (/etc/nginx/nginx.conf:16)
почему: обработка продолжается в этом же location без редиректа
Итого находок: 1
हर रिपोर्ट के अंत में भी छापा जाता है, ताकि कोई इस टूल को गारंटी न समझे:
location केवल पहली जोड़ी रिपोर्ट होती है;rewrite और set जो location के अंदर न होकर सीधे server में बैठे हों, उन्हें ट्रैक नहीं किया जाता;set $tmp $1; और फिर $tmp का उपयोग) का अनुसरण नहीं किया जाता;try_files, error_page और named locations के माध्यम से कूद का अनुसरण नहीं किया जाता;if के अंदर की जोड़ी जो कभी सक्रिय नहीं होती, फिर भी रिपोर्ट होती है।अपडेट करना किसी भी कॉन्फ़िग जाँच से अधिक विश्वसनीय है। nginx.org से वर्तमान stable या mainline रिलीज़ लें।
python3 -m unittest test_check_rewrite -v
29 परीक्षण। इनमें से अधिकांश नकारात्मक मामले हैं, क्योंकि इस तरह के टूल में जोखिम यह है कि वह ठीक-ठाक कॉन्फ़िगरेशनों पर चिल्लाए। इसे ग्यारह included फ़ाइलों में फैले 250 पंक्तियों के एक प्रोडक्शन कॉन्फ़िग पर भी चलाया गया है, जिसमें एक map regex और quotes के अंदर सेमीकॉलन से भरा CSP हेडर था: शून्य निष्कर्ष, शून्य पार्स शिकायतें, और वास्तविक जोड़ी डालने पर ठीक एक निष्कर्ष।
MIT
| एक location के अंदर कॉन्फ़िग | क्रैश |
|---|
rewrite ^(.*) /new?c=1; + set $x $1; | हाँ |
rewrite ^/old/(.*)$ /new?x=1; + set $x $1; | हाँ |
rewrite ^/old/(.*)$ /new/$1?; + set $x $1; | नहीं |
rewrite ... /mid?c=1; फिर rewrite ... /new; फिर set $x $1; | नहीं |
rewrite ^(.*) /new?c=1 break; + set $x $1; | नहीं |
rewrite ^(?<tail>.*) /new?c=1; + set $x $1; | हाँ |
rewrite ^(?<tail>.*) /new?c=1; + set $x $tail; | नहीं |