Skip to content

php2shell v1.9.1: ASLR Scope and Patch-State Corrections

Latest

Choose a tag to compare

@JoshRob297 JoshRob297 released this 31 Oct 14:14
· 2 commits to main since this release

v1.9.1 — ASLR scope and patch-state corrections

Corrective release. Three published statements were contradicted either by the lab evidence or by
the upstream repositories, and the nine-bie replication counts now have per-run transcripts in the
repository instead of an aggregate note.

Corrected

  • ASLR scope. "The leak does not pin libphp" was written as a property of the channel. It is a
    property of the read size. At 4000 B the over-read carries 525-841 bytes out of band and bounds
    libphp to ~481 pages; with a forged zend_string of len=0xC8000 the same cookie returns
    ~800 KB and stage 2 resolves the base. The channel is not closed; the 4000-byte read alone does
    not close it.
  • Two historical libphp figures reconciled. 1.51 MB / 387 pages is the 10-run measurement to
    the libphp base (page aligned, delta % 0x1000 == 0); 1.88 MB / 481 pages is the 20-run
    measurement to the php_session_reset_id breakpoint (fixed 0xc00 symbol offset). Same page
    index, different reference point.
  • Patch state. "PHP 5.x-8.1 ... without an official fix" was wrong for 7.4, 8.0 and 8.1, which
    have minimal official backports in the php-src branches
    PHP-7.4/8.0/8.1-CVE-2026-109618-109619. Only 5.4-7.3 depend on third-party backports. The
    same sentence was corrected in the published v1.8.0 release notes.
  • Persistent-worker row. The "Chain D" label pointed at the stale-EG variant, which is not
    supported. The row now names the variant that was demonstrated: forged HashTable ->
    zif_system.
  • FPM ASLR window. The checker and the private PoC notes described a remote sweep bounded to
    387 pages (1.51 MB). What was measured is the inherited fork layout under one master; FPM
    exposes no in-band oracle, so the sweep is local with calibrated offsets.

Evidence added

File Backs
raw/9bie-aslr-on-8run.txt 9bie chain, container restarted before each run: 8/8 uid=33, 8 distinct chunk and libphp bases
raw/9bie-aslr-off-5run.txt setarch x86_64 -R, 5 runs: 5/5 uid=33, one chunk base and one libphp base across all runs
raw/9bie-display-off-3run.txt Same lab profile with display_errors=Off: 0/3, every run stops at stage 1 (HEAP_LEAK_FAILED)

The author's 10/10 stock profile (php.ini-production, 128M, 150 workers) was not reproduced here,
and the documents state that explicitly. Our sweeps use the lab profile: single worker,
memory_limit=8M, display_errors=On.

Verification

cd lab && python3 -m pytest tests/ exploit/tests/ -q
# 147 passed, 4 skipped

0 broken relative links. Bilingual parity maintained in every modified document.


v1.9.1 — Correcciones de alcance ASLR y estado de parches

Versión correctiva. Tres afirmaciones publicadas quedaron contradichas por la evidencia del
laboratorio o por los repositorios upstream, y los conteos de replicación de la cadena 9bie ahora
tienen transcripciones por corrida en el repositorio en lugar de una nota agregada.

Corregido

  • Alcance de ASLR. "La fuga no fija libphp" estaba escrito como propiedad del canal. Es una
    propiedad del tamaño de lectura. Con 4000 B la sobrelectura transporta 525-841 bytes fuera de
    banda y acota libphp a ~481 páginas; con un zend_string forjado de len=0xC8000 la misma
    cookie devuelve ~800 KB y la etapa 2 resuelve la base. El canal no está cerrado; lo que no basta
    es la lectura de 4000 B.
  • Reconciliación de las dos cifras históricas. 1.51 MB / 387 páginas es la medición de 10
    corridas a la base de libphp (alineada a página, delta % 0x1000 == 0); 1.88 MB / 481 páginas
    es la medición de 20 corridas al breakpoint php_session_reset_id (offset fijo 0xc00). Mismo
    índice de página, distinto punto de referencia.
  • Estado de parches. "PHP 5.x-8.1 ... sin corrección oficial" era falso para 7.4, 8.0 y 8.1,
    que tienen backports oficiales mínimos en las ramas de php-src
    PHP-7.4/8.0/8.1-CVE-2026-109618-109619. Solo 5.4-7.3 dependen de backports de terceros. La
    misma frase se corrigió en las notas publicadas de la versión v1.8.0.
  • Fila de workers persistentes. La etiqueta "Cadena D" apuntaba a la variante de EG colgante,
    que no está soportada. La fila ahora nombra la variante demostrada: HashTable forjada ->
    zif_system.
  • Ventana ASLR en FPM. El checker y las notas privadas de la PoC describían un barrido remoto
    acotado a 387 páginas (1.51 MB). Lo medido es el layout heredado por fork() bajo un master; FPM
    no expone oráculo in-band, así que el barrido es local con offsets calibrados.

Evidencia añadida

Archivo Respalda
raw/9bie-aslr-on-8run.txt Cadena 9bie, contenedor reiniciado antes de cada corrida: 8/8 uid=33, 8 bases de chunk y de libphp distintas
raw/9bie-aslr-off-5run.txt setarch x86_64 -R, 5 corridas: 5/5 uid=33, una sola base de chunk y de libphp en todas
raw/9bie-display-off-3run.txt Mismo perfil de laboratorio con display_errors=Off: 0/3, todas las corridas se detienen en la etapa 1 (HEAP_LEAK_FAILED)

El perfil stock del autor (10/10, php.ini-production, 128M, 150 workers) no se reprodujo aquí y
los documentos lo dicen explícitamente. Nuestros barridos usan el perfil de laboratorio: worker
único, memory_limit=8M, display_errors=On.

Verificación

cd lab && python3 -m pytest tests/ exploit/tests/ -q
# 147 passed, 4 skipped

0 enlaces relativos rotos. Paridad bilingüe mantenida en cada documento modificado.