
CVE-2026-87902 के लिए डिटेक्शन टूलकिट और प्रतिलिपि-योग्य लैब, जो एक अनधिकृत WordPress पाथ ट्रैवर्सल है। इसमें रिमोट चेकर, IoC विश्लेषक, Sigma नियम, और Docker टेस्ट बेंच शामिल हैं।
पता लगाने के लिए टूलिंग और पुनरुत्पादनीय टेस्ट बेंच GHSA-7hp8-65ch-5whp / CVE-2026-87902 — page-template resolution में unauthenticated path traversal जो conditional RCE की ओर ले जाता है (WordPress, CWE-98, CVSS 4.0 : 9.2)।
check/ | रिमोट, पैसिव कंट्रोलर, सर्वर तक पहुँच के बिना |
detect/ | IoC विश्लेषक + Sigma नियम |
offensive/ | ट्रेस जनरेटर, वास्तविक लॉग पर डिटेक्शन को मान्य करने के लिए |
docker-compose.yml + provision/ | टेस्ट बेंच, तीन कॉन्फ़िगरेशन |
tests/validate.py | क्वालिटी गेट — किसी भी प्रकाशन को नियंत्रित करता है |
docs/ANALYSIS.md | भेद्यता, पैच, मापी गई पहुँच-विश्लेषण |
make up # मोंटे le banc make ioc # corpus d'attaque -> journaux -> détection
make scan # contrôle le banc make test # porte de qualité
127.0.0.1 पर तीन WordPress इंस्टेंस, जो निर्णय के प्रत्येक कारक को अलग करते हैं।
8092 सबसे शिक्षाप्रद है : 8091 जैसा ही भेद्य कोर, लेकिन थीम पूर्वापेक्षा अनुपस्थित है। यही दर्शाता है कि केवल संस्करण पर आधारित ट्राइएज एक्सपोज़र को अधिक आँकता है। 8091 और 8092 के बीच थीम ही एकमात्र चर है, 8091 और 8093 के बीच पैच ही एकमात्र है : तीनों एक ही प्रकार की कस्टम सामग्री (provision/mu-plugins/00-lab-cpt.php) और एक ही रिक्वेस्ट-स्टेट प्रोब (10-lab-debug.php, X-Lab-* हेडर जो is_page(), लोडर द्वारा देखा गया pagename मान और अंततः शामिल किया गया टेम्पलेट उजागर करते हैं) शामिल करते हैं।
make up # démarre et provisionne — idempotent, relançable
make status # version de chaque instance
make down # arrêt make clean : supprime aussi les volumes
आधिकारिक Docker इमेज /var/log/apache2/access.log को /dev/stdout पर पॉइंट करती है : लॉग कंटेनर के आउटपुट पर निकलते हैं, किसी फ़ाइल में नहीं।
docker compose logs --no-log-prefix vuln-pre # accès + erreurs
docker compose logs --no-log-prefix vuln-pre > access.log # pour analyse
docker compose logs -f --no-log-prefix vuln-pre # en direct
make logs # les trois instances
पारंपरिक सर्वर पर : /var/log/apache2/access.log, /var/log/nginx/access.log, या अधिकांश शेयर्ड होस्टिंग प्रदाताओं पर /home/*/logs/। फ़ॉर्मेट में क्वेरी स्ट्रिंग शामिल होनी चाहिए — %r या combined फ़ॉर्मेट इसे शामिल करते हैं, %U पर आधारित LogFormat इसे खो देता है, और इसके बिना कोई डिटेक्शन संभव नहीं है।
check/wp-ghsa-7hp8-check.pyइंटरनेट से, सर्वर तक पहुँच के बिना। कोई पेलोड नहीं, कोई traversal नहीं, कोई राइट नहीं। प्रत्येक होस्ट के लिए : WordPress डिटेक्शन, पाँच स्रोतों पर मिलान किया गया संस्करण (meta generator, RSS फ़ीड, wp-links-opml.php, readme.html, कोर संसाधनों का ?ver=), सक्रिय थीम, और page-* डायरेक्टरी की प्रोबिंग।
python3 check/wp-ghsa-7hp8-check.py --hosts-file hosts.txt --csv out.csv --json out.json
« AFFECTÉ » का अर्थ है कि भेद्य कोड मौजूद है, यह नहीं कि कोई हमलावर कोड निष्पादित कर सकता है। देखें docs/ANALYSIS.md।
--transport browser (डिफ़ॉल्ट) इंस्टॉल किए गए Google Chrome को चलाता है ; उप-अनुरोध एक fetch() से निकलते हैं जो पेज के भीतर निष्पादित होता है और उसके TLS स्टैक, उसके HTTP/2 हेडर क्रम और उसके कुकीज़ को विरासत में लेता है, जिससे URL पढ़े जाने से पहले किसी CDN द्वारा फ़िल्टर होने से बचा जाता है। --transport direct केवल मानक लाइब्रेरी का उपयोग करता है। --scheme http|https https → http फ़ॉलबैक से बचाता है, जो अन्यथा लक्ष्य के लॉग में कच्चे TLS ClientHello के साथ एक 400 पंक्ति छोड़ देता है।
प्रत्येक अनुरोध एक JSONL लॉग में मिलीसेकंड तक टाइमस्टैम्प किया जाता है : सेशन आइडेंटिफ़ायर, अनुरोध संख्या, चरण, URL, स्टेटस, आकार, अवधि, आउटगोइंग IP, मार्कर। मार्कर SECAUDIT/<nonce> X-Security-Audit हेडर और User-Agent सफ़िक्स दोनों में जाता है — जोड़ा जाता है, कभी प्रतिस्थापित नहीं, ताकि ब्राउज़र हस्ताक्षर तोड़े बिना मानक access log में दिखाई दे। --marker के माध्यम से अनुकूलन योग्य।
कोई रिमोट ओरेकल नहीं। विकल्प
--probe-inclusionनिष्क्रिय लक्ष्य (wp-includes/version.php, जो पहले से बूटस्ट्रैप पर लोड होता है :require_onceइसे पूर्ण no-op बना देगा) पर विभेदक तुलना करता है। मानक इंस्टॉलेशन पर यहNOT_REACHABLEलौटाता है भेद्य कोर पर भी, संशोधित और असंशोधित इंस्टेंस के बीच बाइट-दर-बाइट समान प्रतिक्रियाओं के साथ। यह टूल की सीमा नहीं है : WordPress टेम्पलेट पदानुक्रम से परामर्श करने से पहले 404 लौटाता है। संख्यात्मक प्रदर्शनdocs/ANALYSIS.md, अनुभाग 3 में।
pagename=.*%2e%2e%2f जैसी शाब्दिक regex को केस बदलकर (%2E), एक बार और एन्कोड करके (%252e), या शाब्दिक और एन्कोडेड को मिलाकर (templates/..%2f../) बायपास किया जा सकता है। पैटर्न की कोई भी सूची निर्माण से ही अपूर्ण होती है।
इसलिए हम कोड से शुरू करते हैं, हमलावर की लेखन-शैली से नहीं :
pagename डिस्क तक पहुँचने से पहले अधिकतम दो डिकोडिंग से गुज़रता है — क्वेरी स्ट्रिंग पर PHP की, फिर get_page_template() का स्पष्ट urldecode()।file_exists() को दिए गए पथ में एक .. घटक होना चाहिए। Linux पर, पैरेंट डायरेक्टरी ठीक दो बाइट्स 0x2E 0x2E पर लिखी जाती है ; फ़ाइल सिस्टम स्तर पर कोई अन्य प्रतिनिधित्व मौजूद नहीं है।इसलिए : फिक्सपॉइंट तक डिकोड करें और प्रत्येक स्तर पर परीक्षण करें। यह WordPress जो करता है उसका एक सख्त सुपरसेट है — एन्कोडिंग की एक परत जोड़ने से केवल मिलान एक स्तर पर स्थानांतरित होता है, जिसे हम भी पार करते हैं।
python3 detect/wp-ghsa-7hp8-ioc.py access.log
docker compose logs --no-log-prefix vuln-pre | python3 detect/wp-ghsa-7hp8-ioc.py -
Sigma नियम detect/sigma-wp-ghsa-7hp8.yml में। Sigma पुनरावर्ती रूप से डिकोड करना नहीं जानता, इसलिए वे स्तर 0 से 3 तक की गणना करते हैं : यह एक स्वीकृत अनुमान है, प्रथम-स्तरीय ट्राइएज के लिए। निर्णय लेने के लिए मिलानों को विश्लेषक में दोबारा चलाएँ।
WP::parse_request() $_GET से पहले $_POST पढ़ता है। इसलिए pagename किसी रिक्वेस्ट बॉडी में आ सकता है, जो किसी भी access log में अनुपस्थित है। WAF या ModSecurity स्तर पर, बॉडी पर कवरेज आवश्यक है।access log पर कोई भी नियम पहले बिंदु को कवर नहीं करता। यह सपोर्ट की सीमा है, नियम की नहीं — लेकिन पूर्ण कवरेज की घोषणा करने से पहले इसे जाना जाना चाहिए।
offensive/generate-traces.py एक ही पेलोड के 12 विभिन्न लेखनों (शाब्दिक, एकल/दोहरी/तिहरी एन्कोडिंग, ऊपरी और निचली केस, मिश्रण, UTF-8 ओवर-एन्कोडिंग, डॉट-स्पेस) के साथ-साथ 7 वैध अनुरोध जो उनसे मिलते-जुलते हैं (डॉट्स वाला slug, slug में wp-includes, दिनांक permalink, एन्कोडेड प्रतिशत) को रीप्ले करता है।
यह कुछ प्राप्त नहीं करता : मानक इंस्टॉलेशन पर इस वेक्टर के लिए कोई रिमोट एक्सप्लॉइट मौजूद नहीं है। यह ट्रेस उत्पन्न करता है — यही इसका पूरा उद्देश्य है।
make ioc # génère le corpus, récupère les journaux réels, passe l'analyseur
अपेक्षित, और वास्तविक Apache लॉग पर make test द्वारा सत्यापित :
12 में से 12 पेलोड का पता चला (11 CRITICAL, ओवर-एन्कोडिंग MEDIUM क्योंकि यह Linux पर शोषणीय नहीं है), 7 वैध अनुरोधों पर 0 अलर्ट, और तीन अलग-अलग डिकोडिंग स्तरों पर प्रभावी डिटेक्शन।
लक्ष्य स्थानीय बेंच तक सीमित ; किसी अन्य के लिए --i-have-authorization आवश्यक है।
php.ini में register_argc_argv = Off ; यदि अप्रयुक्त हो तो PEAR अनइंस्टॉल करें — यह अधिसूचना में उद्धृत inclusion → execution का पिवट है।open_basedir को साइट रूट तक सीमित करें : किसी भी स्थानीय inclusion को सीमित करता है।make test प्रकाशन की शर्त है : अधिसूचना की 25 शाखाओं का मैट्रिक्स (तुलना के जाल सहित — 6.8.9 < 6.8.10 संख्यात्मक रूप से, पूर्व-संस्करण, मैट्रिक्स से बाहर की शाखाएँ), तीन इंस्टेंस के विरुद्ध कंट्रोलर, और वास्तविक लॉग पर मान्य IoC नियम। प्रोब का NOT_REACHABLE अभिकथन वहाँ जानबूझकर स्थिर किया गया है : यदि यह टूटता है, तो व्यवहार बदल गया है और विश्लेषण को फिर से शुरू करना होगा।
केवल उन संपत्तियों पर उपयोग करें जिनकी ज़िम्मेदारी आपकी है, या लिखित अधिदेश के तहत। बेंच केवल 127.0.0.1 पर सुनता है ; भेद्य इंस्टेंस को कभी उजागर नहीं किया जाना चाहिए। प्रोब 10-lab-debug.php सर्वर पथ उजागर करता है : यह बेंच के लिए आरक्षित है।
| पोर्ट | इंस्टेंस | कोर | सक्रिय थीम | अपेक्षित निर्णय |
|---|
| 8091 | vuln-pre | 6.8.1 — असंशोधित | Twenty Twelve, page-templates/ के साथ | AFFECTED_PRECONDITION_MET |
| 8092 | vuln-nopre | 6.8.1 — असंशोधित | Twenty Twenty-Four, page-* के बिना | AFFECTED_CORE_ONLY |
| 8093 | patched | 6.8.10 — संशोधित | Twenty Twelve, page-templates/ के साथ | NOT_AFFECTED |
| निर्णय | अर्थ |
|---|
AFFECTED_PRECONDITION_MET | भेद्य कोर और सक्रिय थीम पर page-* डायरेक्टरी। प्राथमिकता। |
AFFECTED_THEME_UNKNOWN | भेद्य कोर, थीम अनिर्धारित। |
AFFECTED_CORE_ONLY | भेद्य कोर, थीम पूर्वापेक्षा अनुपस्थित। फिर भी ठीक करना है। |
VERSION_UNKNOWN | WordPress का पता चला, संस्करण छिपा हुआ। |
NOT_AFFECTED | संस्करण ≥ उसकी ब्रांच का पैच। |
| नियम | गंभीरता | ट्रिगर |
|---|
GHSA-7hp8-traversal-pagename | CRITICAL | pagename में .. घटक, डिकोडिंग के किसी भी स्तर पर |
GHSA-7hp8-traversal-param | HIGH | किसी अन्य पैरामीटर में वही प्रिमिटिव (थीम और एक्सटेंशन भी locate_template() कॉल करते हैं) |
GHSA-7hp8-traversal-path | HIGH | URL पथ में .. घटक (nginx %2f को जाने देता है, Apache डिफ़ॉल्ट रूप से नहीं) |
GHSA-7hp8-overlong-encoding | MEDIUM | UTF-8 ओवर-एन्कोडिंग (%c0%ae)। Linux पर अप्रभावी, लेकिन कभी वैध नहीं |
GHSA-7hp8-theme-page-dir-probe | LOW | थीम page-* डायरेक्टरी की प्रोबिंग — पुनरावलोकन |