
स्व-निहित Docker पुनरुत्पादन और CVE-2024-23897 का विश्लेषण, जो args4j @-सिंटैक्स तर्क विस्तार के माध्यम से Jenkins CLI में मनमाना फ़ाइल पठन है।
CVE-2024-23897 का एक स्व-निहित, पूर्णतः स्थानीय पुनरुत्पादन, जो Jenkins CLI में गंभीर (CVSS 3.1 आधार स्कोर 9.8) मनमाना फ़ाइल पठन है। यह प्रोजेक्ट दो Docker स्टैक चालू करता है जो केवल Jenkins माइनर संस्करण में भिन्न होते हैं, दोनों पर समान प्रूफ ऑफ कॉन्सेप्ट चलाता है, और दिखाता है कि भेद्यता अनपैच्ड कंट्रोलर पर सक्रिय होती है और पैच किए गए कंट्रोलर पर शांत रहती है।
सब कुछ एक ही Python प्रोग्राम, poc.py, द्वारा संचालित होता है। हार्नेस केवल परिवेश का ऑर्केस्ट्रेशन करता है (Docker Compose, आधिकारिक jenkins-cli.jar क्लाइंट, और आउटपुट का शब्द-प्रति-शब्द कैप्चर)। भेद्यता स्वयं Jenkins के अपने Java कोड में होती है और इसे यहाँ दोबारा लागू नहीं किया गया है।
पैच समीक्षा और CVSS विघटन सहित एक पूर्ण लिखित विश्लेषण report/report.pdf में उपलब्ध है।
Jenkins CLI अपना आर्गुमेंट पार्सर args4j लाइब्रेरी के साथ बनाता है। args4j में expandAtFiles नामक एक फीचर है, जो atSyntax फ्लैग द्वारा नियंत्रित होता है और डिफ़ॉल्ट रूप से सक्षम होता है, जो @/path/to/file रूप के किसी भी आर्गुमेंट को कमांड चलने से पहले उस फ़ाइल की सामग्री में बदल देता है। फ़ाइल Jenkins कंट्रोलर प्रोसेस के विशेषाधिकारों के साथ खोली जाती है। चूँकि सभी तीन CLI ट्रांसपोर्ट (HTTP, WebSocket, SSH) एक ही पार्सर में आकर मिलते हैं, कोई भी क्लाइंट जो कोई भी CLI कमांड भेज सकता है, कंट्रोलर से मनमानी फ़ाइलें पढ़ सकता है। फिक्स (कमिट 554f0378) एक ALLOW_AT_SYNTAX कॉन्स्टेंट जोड़ता है जो डिफ़ॉल्ट रूप से false होता है, जिससे विस्तार बंद हो जाता है।
यह शास्त्रीय पाथ ट्रैवर्सल नहीं है: इसमें न तो ../ है और न ही बचने के लिए कोई बेस डायरेक्टरी। पाथ सीधे खोला जाता है। परिणाम की दृष्टि से यह मनमाना फ़ाइल पठन है; तंत्र की दृष्टि से यह आर्गुमेंट विस्तार है।
cve-2024-23897-jenkins-poc/
README.md # this file
LICENSE
poc.py # Python reproduction harness (all subcommands)
Dockerfile.vuln # jenkins/jenkins:2.426.2-lts + matrix-auth
Dockerfile.fix # jenkins/jenkins:2.426.3-lts + matrix-auth
docker-compose.vuln.yml # jenkins-vuln + attacker-vuln
docker-compose.fix.yml # jenkins-fix + attacker-fix
init.groovy.d/
01-create-users.groovy # bootstraps admin + readuser via matrix-auth
evidence/
docker-versions.txt # host Docker + Compose versions
output-vulnerable.txt # captured during `poc.py exploit`
output-fixed.txt # captured during `poc.py verify-fix`
report/
report.pdf # full written analysis
report.tex # LaTeX source (self-contained, no external figures)
होस्ट पर किसी JDK की आवश्यकता नहीं है। Java अटैकर कंटेनर के अंदर चलता है। कंपोज़ फ़ाइलें platform: linux/amd64 पिन करती हैं ताकि इमेज Apple Silicon पर समान व्यवहार करें; यह एक परिचालनात्मक विकल्प है और भेद्यता को प्रभावित नहीं करता, जो प्लेटफ़ॉर्म-स्वतंत्र है।
रिपॉजिटरी के अंदर से:
python3 poc.py up-vuln # build and start the vulnerable stack, fetch the CLI jar
python3 poc.py place-proof # write the harmless marker file inside the controller
python3 poc.py exploit # run the PoC, writes evidence/output-vulnerable.txt
python3 poc.py up-fix # tear down vuln, build and start the patched stack
python3 poc.py verify-fix # run the same PoC, writes evidence/output-fixed.txt
python3 poc.py teardown # stop and remove both stacks
पहला रन कुछ मिनट लेता है (इमेज पुल के साथ प्लगइन इंस्टॉलेशन)। उसके बाद के रन बहुत तेज़ होते हैं।
poc.py exploit तब पास होता है जब मार्कर स्ट्रिंग POC-PROOF-LINE कैप्चर किए गए आउटपुट में दिखाई देती है (यानी लीक हुआ)। poc.py verify-fix विपरीत शर्त पर पास होता है: मार्कर अनुपस्थित होना चाहिए। दोनों सबकमांड विफलता पर गैर-शून्य (non-zero) एग्ज़िट कोड देते हैं, इसलिए दोनों एविडेंस फ़ाइलें अपनी एग्ज़िट स्थिति सहित स्वयं परीक्षण परिणाम हैं।
दोनों कंपोज़ फ़ाइलें एक Docker नेटवर्क पर समान दो सेवाएँ चलाती हैं: एक Jenkins कंट्रोलर (पीड़ित) और एक छोटा eclipse-temurin:17-jre अटैकर कंटेनर। poc.py होस्ट पर चलता है और subprocess के माध्यम से Docker को नियंत्रित करता है, लेकिन वास्तविक java -jar jenkins-cli.jar ... इनवोकेशन अटैकर कंटेनर के अंदर चलता है। अटैकर के पास Jenkins डेटा वॉल्यूम तक कोई पहुँच नहीं है; वह कंट्रोलर तक केवल नेटवर्क के माध्यम से पहुँचता है, जैसे कोई रिमोट अटैकर पहुँचता है।
init.groovy.d/01-create-users.groovy matrix-auth प्लगइन का उपयोग करके जानबूझकर अलग-अलग अनुमतियों वाले दो खाते बनाता है:
यह आधिकारिक एडवाइज़री में बताए गए सटीक विभाजन को पुनरुत्पादित करता है — Overall/Read बनाम anonymous — न कि उस ढीले "कोई भी लॉग-इन उपयोगकर्ता बनाम anonymous" विभाजन को जो Jenkins कोर डिफ़ॉल्ट उत्पन्न करता। इसलिए पूर्ण फ़ाइल लीक का कारण केवल CVE है, न कि प्रशासनिक पहुँच।
PoC प्रत्येक कंट्रोलर के विरुद्ध चार संदर्भ चलाता है। नीचे दी गई तालिका A/B तुलना का सारांश देती है; पूर्ण कैप्चर evidence/ में हैं।
दोनों कॉलमों के बीच बदलने वाला एकमात्र चर Jenkins माइनर संस्करण है, और उसके माध्यम से पैच के बाद का atSyntax डिफ़ॉल्ट। इसलिए विपरीत परिणाम व्यवहार परिवर्तन का श्रेय कमिट 554f0378 में किए गए पार्सर फिक्स को देते हैं।
Jenkins को कंटेनर में चलाना कोई शमन नहीं है। पार्सर Jenkins JVM के विशेषाधिकारों के साथ फ़ाइलें पढ़ता है, और वे फ़ाइलें उसी कंटेनर फाइलसिस्टम के अंदर रहती हैं जिसमें क्रेडेंशियल स्टोर स्थित है। कंटेनर सीमा होस्ट को Jenkins प्रोसेस से सुरक्षित रखती है, न कि Jenkins प्रोसेस को स्वयं से। यहाँ Docker सेटअप एक प्रदर्शन सैंडबॉक्स है, और कुछ नहीं।
पैच किए गए रिलीज़ में अपग्रेड करें: 2.442 (weekly), या 2.426.3 या 2.440.1 (LTS), सभी 24 जनवरी 2024 को प्रकाशित हुए। यदि तत्काल अपग्रेड संभव नहीं है, तो सिस्टम प्रॉपर्टी hudson.cli.CLICommand.allowAtSyntax को अनसेट (इसका डिफ़ॉल्ट) छोड़ दें, जो ALLOW_AT_SYNTAX को false रखता है और विस्तार को अक्षम कर देता है। व्यक्तिगत CLI ट्रांसपोर्ट को अक्षम करना केवल एक आंशिक उपाय है, क्योंकि तीनों एक ही पार्सर पर आकर मिलते हैं।
सारा कार्य एक स्थानीय Docker परिवेश में एक हानिरहित तीन-पंक्ति मार्कर फ़ाइल (/tmp/poc-proof.txt) के विरुद्ध चलता है, जिसे हार्नेस स्वयं बनाता है। किसी सार्वजनिक Jenkins इंस्टेंस को स्कैन या संपर्क नहीं किया जाता, और secrets/master.key या credentials.xml जैसे किसी वास्तविक रहस्य को कभी नहीं पढ़ा जाता।
554f0378: https://github.com/jenkinsci/jenkins/commit/554f03782057c499c49bbb06575f0d28b5200edbParserProperties.withAtSyntax): https://github.com/kohsuke/args4j| आवश्यकता | टिप्पणियाँ |
|---|
| Docker Engine 24 या नया | उपयोग किया गया सटीक संस्करण evidence/docker-versions.txt में दर्ज है |
| Docker Compose v2 | बिल्ट-इन docker compose प्लगइन के रूप में उपलब्ध है |
| Python 3.8 या नया | केवल स्टैंडर्ड लाइब्रेरी, किसी pip install की आवश्यकता नहीं |
| डिस्क स्थान | दो Jenkins इमेज, temurin इमेज और matrix-auth प्लगइन के लिए लगभग 1.5 GB |
| खाता | अनुमतियाँ | PoC में भूमिका |
|---|
admin | Jenkins.ADMINISTER | केवल "कम से कम एक एडमिन" की शर्त पूरी करने के लिए मौजूद है, हमले के लिए कभी उपयोग नहीं होता |
readuser | केवल Jenkins.READ (Overall/Read) | प्रमाणित अटैकर |
| anonymous | कोई नहीं | अप्रमाणित अटैकर |
| अवलोकन | भेद्य 2.426.2 | पैच किया गया 2.426.3 |
|---|
@-टोकन हैंडलिंग | फ़ाइल सामग्री में विस्तारित | शाब्दिक स्ट्रिंग के रूप में माना गया |
readuser + connect-node | पूर्ण फ़ाइल प्रकटीकरण (3 में से 3 पंक्तियाँ) | कोई प्रकटीकरण नहीं |
anonymous + who-am-i / help | auth गेट से पहले पार्सर त्रुटि के माध्यम से आंशिक लीक (पहली पंक्ति) | कोई प्रकटीकरण नहीं |
आउटपुट में मार्कर POC-PROOF-LINE | उपस्थित | अनुपस्थित |