Skip to content
Exploit for CVE-2026

Exploit for CVE-2026

Sploitus • October 21, 2026

# CVE-2026-109618 / CVE-2026-109619 — PoC, análisis y crónica del patch-day de PHP (21-oct-2026)

El release de emergencia de PHP del 21-oct-2026 (14:00 UTC): **8.5.12 / 8.4.27 / 8.3.36 / 8.2.35** corrigen **dos RCE no-autenticado** en el núcleo, confirmadas por el equipo de PHP. Este repo documenta la **crónica completa del patch-day** (leak → corrección → auditoría → release) y el **trabajo de laboratorio que hicimos ese mismo día**: qué reproducimos, qué quemamos, qué queda abierto.

**Créditos y fuentes**: material original filtrado por **@J4ck3LSyN** ([jackalsyn.com/posts/php-up-2026.html]( con las correcciones de Andrew Dorman (@acd421) y Arch&Yuki (@ArchKnight23)); auditoría de **xuehuolll** ([CVE-2026-109618-109619-audit]( confirmación por **watchTowr**; aviso oficial de **php.net** ([advisory 21-oct](

⚠️ **Disclaimer**: todo el material va marcado **lab-only**. Los PoCs existen para reproducir el bug en **TU entorno controlado y autorizado** — nunca contra sistemas ajenos. El parche quedó publicado el **21-oct-2026 a las 14:00 UTC**: actualizar es la única defensa completa; este repo es crónica forense, no munición.

| 20-oct 15:20 UTC | **El leak**: post anónimo en Hacker News («2x PHP RCE CVEs with CVSS 10.0 Incoming»). Circulan: CVSS 10.0 (no oficial), «afecta desde PHP 5», y la captura de una herramienta **PHP2Shell** acreditada a Calif.IO con banner «funciona desde PHP 5.4.0» |

| 20-oct tarde | **watchTowr confirma**: 2 RCE reales; reproduce uno en laboratorio (CVE-2026-109618/109619 = etiquetas del leak, no del aviso oficial). PHP publica el pre-aviso: release el 21-oct 14:00 UTC, «2 críticas, CVSS v4.0 9.2», sin nombres ni detalles |

| 21-oct (pre-release) | **El leaker autocorrige**: la vía «cached-pointer» (el RCE universal) está **muerta** — el `Z_TRY_ADDREF` de `session.c:3213` deja el array vivo; no hay UAF ni RCE (**CVSS 0.0 para esa vía**). El bug real de su material = **UAF cross-request del estado de serialización**, ASAN-confirmado (`var.c:756`), **prefork-only**, memory-safety sin ejecución de código (**CVSS 5.3**) |

| 21-oct (pre-release) | **Auditoría independiente** (xuehuolll, PHP 8.5.4): los CVEs **sin registro en MITRE/NVD**; el UAF del array de progreso del bundle **no reproduce** (el mismo `Z_TRY_ADDREF`); Bug S (BG serialize orphan) = UAF 3/3 bajo ASAN **sin RCE**; Bug U (BG unserialize orphan) = arm confirmado, **kill/system no reproduce**; y un **PoC propio de RCE (10/10 local)** de otra familia: UAF en el dtor-walk de `var_destroy()` (sin `serialize_lock`) → `__destruct` → unserialize interno → closure falsa → `zif_system` — con precondiciones **app-side**: `unserialize()` de datos del atacante + clase con `__destruct` |

| 21-oct 14:00 UTC | **EL RELEASE**: 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 — los números EXACTOS del rumor. php.net confirma: **CVE-2026-109618 = «RCE via OOM corruption»** (GHSA-w8hw-w9fx-j79w); **CVE-2026-109619 = «RCE via stale global state»** (GHSA-6wmf-4rv5-p3rp); **riesgo MÁXIMO en mod_php, con exploit demostrado que dispara una petición no autenticada ANTES de cualquier código de aplicación** |

| 21-oct post-release | **Nuestro lab**: la primitiva del PoC del auditor **doble-verificada** (Docker stock 8.5.11 + el intérprete EXACTO de una nextcloud real: prefork + upload_progress=On) — SIGSEGV en el último salto (offsets por-build) |

1. **La primitiva de corrupción ×2**: `var_destroy` UAF → reclaim del bloque liberado (spray de punteros) → fake-zval resuelto vía `R:1500` hasta la invocación:

- Docker stock `php:8.5-cli` (8.5.11): `[ptr] buf=0x7fea71691018` + **exit=139**

- Interprete EXACTO de una nextcloud EN PROD (CLI desechable, sin tocar workers): `[ptr] buf=0x7fd155a92018` + **exit=139** — contenedor intacto, sin huella

2. **La forense de relocs (statics sin correr nada)**: `zend_ce_closure` global `@0x1ce4d40` (legible, su VALUE = la class-entry en heap) y `zif_system` `@0x60cc20` (docker) / `@0x60ca60` (nextcloud — misma familia binaria: mismo tamaño 30,176,584 bytes, mismos dynsym-VA, mismo thunk ICF `ba 01 00 00 00 e9 …`) — el truco: addend del string «system» → slot → +8

3. **El arranque completo con statics** (`[resolv]` en los receipts): base + zif + ce + cec, y la machinery del marker corriendo — el último salto (la call-machinery del closure → stub de `system()`) sigue **SIGSEGV**: el arma completa exige offsets del layout por-build — exactamente lo que documentaba el auditor («per-build offsets», 10/10 solo en su build)

- **Rela/dynsym forensics del binario** (nada se ejecuta): funciona — es la ruta para hornear offsets statics por build (tools/)

- **Scans de `/proc/self/mem` desde PHP puro**: patológico de lento en contenedores — 4 corridas muertas (2×~30 min de timeout global, 2×60 s). Lección: nada de scans generosos dentro del proceso; resuelve estático fuera, caza corto dentro

- **`timeout N docker run` mata el cliente, no el contenedor** (el shim sigue vivo agarrando el pipe: el `$(...)` del bash queda en espera eterna de EOF) — la regla: `docker stop ` ANTES de leer los resultados del run-killed

- **Autocorrecciones del leaker**: la vía «RCE universal desde PHP 5.4» no sobrevivió al escrutinio; lo que queda de la saga del leak = un UAF moderado + la confirmación oficial de los 2 RCE reales por otra mecánica (OOM + estado huérfano)

1. **Actualizar**: 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 — «no complete mitigations»: el parche = la única cura completa

2. `session.upload_progress.enabled=0` + **reiniciar todos los workers** (bloquea las vías de session confirmadas; nada de `ini_set()` ni `.user.ini`)

3. En PHP 8.5: `fatal_error_backtraces=0` + reinicio de workers (la pieza nueva; bloquea la vía del fatal-backtrace)

4. `memory_limit=-1` vía php_admin_value (insobrescribible) / `post_max_size` bajo (8M/32M) / límites en el proxy (tamaño decodificado, campos, partes multipart, cabeceras, profundidad — también sin Content-Length)

5. Frontera de disponibilidad vía cgroup/contenedor (matando solo el worker afectado) — **NUNCA RLIMIT_AS/RLIMIT_DATA** (provocan el fallo de asignación vulnerable)

6. EOL: backports oficiales para 7.4/8.0/8.1 (ramas de php-src); remirepo sin updates ese día; los vendors de distro recibieron los patches por adelantado

Loop automático: control vulnerable etiquetado (`php-ab-control-8511` = la 8.5.11) **ANTES** de que el pull lo sobrescriba; cuando docker-library publique la parcheada → el mismo PoC en las dos piernas; discriminador: `buf=…`+SIGSEGV en la parcheada = la primitiva sobrevive; salida limpia = el parche la mata. El receipt caerá a `evidence/`.

- poc/: PoC original del auditor (crédito arriba) + variantes de lab

- tools/: forensics de binario (relas/dynsym) y bakers de_offsets

- evidence/: receipts de las corridas (dígito-verificables con los exit-codes)

Extracted Entities

CWE Weaknesses (1)

Platforms (2)

Tools (1)