Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
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.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-25243 — CVE-2026-25243 — Redis RESTORE doble liberación en zipmap → ejecución remota de código (ASLR activado). | Kitploit
Herramientas/GitHubGitHub/dinosn/cve-2026-25243
Forensia de MemoriaAnálisis de VulnerabilidadesExplotaciónIngeniería InversaPruebas de PenetraciónHerramienta de Acceso RemotoDesarrollo de PayloadsExplotación de Binarios
GitHubdinosn/cve-2026-25243

CVE-2026-25243

CVE-2026-25243 — Redis RESTORE doble liberación en zipmap → ejecución remota de código (ASLR activado).

Ver Repositorio
134hace 2 mesesAú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

CVE-2026-25243 — Redis RESTORE zipmap doble liberación → ejecución remota de código

TL;DR. Un payload DUMP malformado pasado a RESTORE desencadena una doble liberación en el cargador de hash-zipmap heredado de Redis. Con jemalloc predeterminado, la doble liberación es silenciosa (el servidor sigue funcionando), lo que la convierte en una primitiva de confusión de tipos controlable. Este repositorio la encadena en ejecución remota de código con ASLR habilitado — el trabajador de Redis llama a system("<cadena del atacante>") y sigue sirviendo. No es una denegación de servicio.

root@kitploit:~
# default Redis (DEBUG disabled), ASLR on — the most self-contained exploit (NO libc offsets):
$ python3 exploits/poc_rce_aslr_pie_rop.py --cmd "id > /tmp/pwned_pie 2>&1"
[*] self-cal: blob_base=0x7f352d800009 blob_robj=0x7f353286b8d8 pie_base=0x557ea9149000  (NO libc)
[*] fake dictType F=0x7f352e013c36  g1=0x557ea93cca87 execve=0x557ea91cee80
$ cat /tmp/pwned_pie
uid=0(root) gid=0(root) groups=0(root),...    # <- execve("/bin/sh","-c",<cmd>) as the redis process

La filtración que derrota a ASLR no usa ningún DEBUG — lee la dirección de la clausura C de Lua redis.call (EVAL 'return tostring(redis.call)'), la misma técnica autónoma y sin DEBUG que nuestro exploit anterior de Redis. blob_base/blob_robj y la base de PIE se derivan en tiempo de ejecución a partir de la sobrelectura (sin offset fijo). El final PIE-ROP llama a execve@plt mediante un pivote de pila JOP, por lo que usa cero direcciones de libc — las únicas constantes específicas de la compilación son offsets de gadgets relativos a PIE leídos del binario redis-server, exactamente como la tabla de gadgets por compilación de nuestro exploit anterior de HLL. Verificado uid=0(root), ASLR activado, 8/8, en un servidor predeterminado con DEBUG desactivado.

Se proporcionan dos finales. poc_rce_aslr_pie_rop.py (arriba) es el más autónomo — sin libc, totalmente autocalibrado — pero execve reemplaza al trabajador (use un --cmd de shell inverso; mejor para un shell real). poc_rce_aslr_selfcal.py mantiene vivo al trabajador (system() crea un proceso hijo) a costa de dos offsets de versión de libc. Elija según si necesita que el servidor sobreviva.


El bug

RESTORE key 0 <DUMP-payload> deserializa un objeto serializado. Para el tipo heredado RDB_TYPE_HASH_ZIPMAP (0x09), el validador y el conversor no coinciden en cuántos bytes ocupa un campo de longitud:

  • zipmapValidateIntegrity() recorre con el tamaño real codificado (5 para el prefijo 0xFE demasiado largo);
  • zipmapNext() durante la conversión zipmap → listpack usa 1 byte para cualquier longitud decodificada < 254.

Una longitud pequeña escrita en la forma de 5 bytes demasiado larga pasa la validación pero hace que zipmapNext() se desvíe 4 bytes. Dos consecuencias fluyen de la misma desviación: una sobrelectura en el montón (zipmap.c) y, solo en Redis, una doble liberación en el cargador de hash-zipmap de rdb.c:

root@kitploit:~
sds field = sdstrynewlen(fstr, flen);
if (!field || dictAdd(dupSearchDict, field, NULL) != DICT_OK || !lpSafeToAdd(lp, flen + vlen)) {
    dictRelease(dupSearchDict);   // (1) dictAdd tomó posesión de `field` -> liberado aquí
    sdsfree(field);               // (2) liberado DE NUEVO -> doble liberación

Valkey protege esto (if (!field_added) sdsfree(field)); Redis upstream no lo hacía, por lo que la doble liberación es solo de Redis. La corrección rechaza la longitud pequeña codificada en forma demasiado larga y reordena las comprobaciones en tiempo de carga.

La cadena de explotación (Redis 8.6.2, x86-64, jemalloc, PIE/NX/partial-RELRO)

root@kitploit:~
silent double-free  ->  type-confusion overlap  ->  arbitrary pointer-forge
   ->  forge a hashtable hash's  dict->type  to a fake dictType
   ->  HGET hd "<field>"   ==   dictFind -> type->hashFunction(field)
      libc path  (selfcal): hashFunction = &system            -> system("<cmd>")   (worker survives)
      PIE path   (pie_rop): hashFunction = JOP-pivot g1, field = ROP chain
                            -> leave;ret pivots rsp onto the field
                            -> execve("/bin/sh","-c","<cmd>")  via execve@plt        (no libc, no DEBUG)

El dictType falso se coloca dentro de una cadena de 16 MB (SETRANGE) en el único offset cuyos bytes bajos de dirección coinciden con el encabezado sds de la cadena del atacante. ASLR se derrota completamente en tiempo de ejecución:

  • system — una sola fuga de puntero al montón. La ruta recomendada es sin DEBUG: la dirección de la clausura C de Lua redis.call (EVAL 'return tostring(redis.call)') — la misma fuga autónoma que usa nuestro exploit anterior de Redis. Los arenas de jemalloc están a un offset constante de libc, por lo que system = leaked_robj + Δlibc + system_off. (DEBUG OBJECT es solo una conveniencia de laboratorio cuando la creación de scripts está deshabilitada pero DEBUG está habilitado — la configuración más rara.)
  • la dirección del blob de 16 MB (un mmap aleatorizado de forma independiente) — se lee con la propia lectura arbitraria del bug: forje el dict de un SET para que su miembro sea un sds de 107 KB SDS_TYPE_32, SMEMBERS sobrelee el montón adyacente, y el robj.ptr del blob se lee en su offset conocido.

Vea WRITEUP.md para el análisis primitiva por primitiva completo y los detalles difíciles de jemalloc / Redis-8.x (límite de clase-64, etiquetado de entradas de dict, mstr de campos hash, pre-crecimiento del espacio de claves).

Laboratorio

root@kitploit:~
docker build -t cve-2026-25243 .
# demo stock (jemalloc) — ¿DoS o no? muestra la confusión de tipos (sin herramientas):
docker run --rm -p 6379:6379 cve-2026-25243

# cadena completa — configuración PREDETERMINADA (DEBUG desactivado), el exploit recomendado:
sysctl -w kernel.randomize_va_space=2            # ASLR ACTIVADO
redis-server &                                   # DEBUG está desactivado por defecto
python3 exploits/poc_rce_aslr_selfcal.py --host 127.0.0.1 --port 6379 --cmd "id > /tmp/pwned 2>&1"

La filtración que derrota a ASLR (sin DEBUG)

La fuga de arranque de puntero al montón sigue el mismo enfoque que nuestro exploit anterior de Redis: filtrar la dirección de la clausura C de Lua redis.call con EVAL 'return tostring(redis.call)'. La creación de scripts Lua está activada por defecto; DEBUG está desactivado por defecto (enable-debug-command no) — por lo que la fuga Lua es la primaria realista, y DEBUG OBJECT (poc_rce_aslr.py) es solo una conveniencia de laboratorio. poc_rce_aslr_selfcal.py luego deriva blob_base y blob_robj en tiempo de ejecución a partir de la sobrelectura (busca la firma del robj del blob de 16 MB), por lo que DLUA/DFOBJ solo necesitan ser aproximados.

Para el final con system, la sobrelectura del montón pequeño no contiene punteros a libc, por lo que libc no puede autoderivarse — poc_rce_aslr_selfcal.py mantiene dos offsets de versión de libc (DLIBC, SYSTEM_OFF). El final poc_rce_aslr_pie_rop.py elimina esa dependencia por completo: la misma sobrelectura sí lleva punteros PIE (un dictType compartido aparece repetidamente), por lo que la base de PIE se autocalibra como valor-PIE-más-común − DICTTYPE_OFF, y la cadena termina en execve@plt mediante un pivote de pila JOP (mov rbp,rdi; call *0x8(rax) → leave;ret pivotea rsp sobre el campo de HGET controlado por el atacante, que es la cadena ROP de execve("/bin/sh","-c",<cmd>)). Las únicas constantes específicas de la compilación son los offsets de gadgets relativos a PIE leídos de — extráigalos por objetivo con /, exactamente como nuestro exploit anterior de HLL usa una tabla de gadgets por ID de compilación ELF. No se utiliza ninguna dirección de libc.

Capturas de pantalla

screenshots/05-pie-rop-libc-free.png (la autocalibración NO libc + uid=0, la ejecución más autónoma), 01-rce-aslr-on.png (la captura clave de uid=0), 02-reliability.png (5/5), 03-exploit-chain.png (el código), y 04-debug-free-selfcal.png (la ejecución de system sin DEBUG y autocalibrada en un Redis predeterminado).

Impacto y versiones afectadas

  • Remoto, sin privilegios especiales. RESTORE es un comando ordinario — en un Redis sin autenticar o expuesto (sin requirepass), cualquier cliente conectado puede ejecutarlo; en una instancia autenticada, cualquier usuario sin una denegación de ACL -restore. Mismo perfil de acceso que los comandos de estructura de datos usados por otros RCE de Redis.
  • Confirmado: doble liberación silenciosa en el montón, confusión de tipos, lectura arbitraria de la memoria del proceso (fuga de información que extrae claves / secretos / punteros), y ejecución remota de código (este repositorio).
  • Afectado: Redis < {6.2.22, 7.2.14, 7.4.9, 8.2.6, 8.4.3, 8.6.3} — es decir, 6.2.x hasta 8.x actual; Valkey solo sufre DoS/sobrelectura (su protección field_added bloquea la doble liberación).

Mitigación

Actualice a una versión corregida. Si no puede: restrinja RESTORE (ACL … -restore), nunca exponga Redis sin autenticar, y deshabilite DEBUG.


Investigación de seguridad autorizada, publicada para concienciación de los defensores. No ejecute contra sistemas que no posea o para los que no tenga permiso explícito para probar.

Descargar herramienta
archivoqué demuestra
★ exploits/poc_rce_aslr_pie_rop.pyel más autónomo — RCE en un Redis predeterminado (DEBUG desactivado), SIN offsets de libc; autocalibra blob_base/blob_robj/pie_base; execve@plt mediante pivote JOP (el trabajador es reemplazado). 8/8.
★ exploits/poc_rce_aslr_selfcal.pysupervivencia del trabajador — misma cadena pero hashFunction=&system (crea un proceso hijo); cuesta dos offsets de versión de libc (DLIBC/SYSTEM_OFF). Fuga de clausura Lua, autocalibración de blob_base/blob_robj.
exploits/poc_rce_aslr_nodebug.pySin DEBUG (fuga Lua), pero con offsets fijos (calibrados con DEBUG activado)
exploits/poc_rce_aslr.pyvariante de conveniencia de laboratorio: fuga de arranque con DEBUG OBJECT (necesita DEBUG habilitado)
exploits/poc_rce_aslr_off.pyRCE con ASLR desactivado (direcciones calibradas)
exploits/poc_typeconfusion.pydoble liberación → dos claves comparten un búfer del montón (sin herramientas)
exploits/poc_doublefree.pyla doble liberación (ASan: use-after-free en montón en sdsfree)
exploits/poc_dos_overread.pyel fallo por sobrelectura (ASan)
redis-server
ROPgadget
objdump