En mis archivos de registro de Apache encuentro muchas entradas que contienen "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400
u otro tipo de basura similar. Provienen de conexiones no RFC2616 (HTTP/1.1 sin nombre de host).
No quiero que mis archivos de registro se llenen de estos mensajes. Por lo tanto, quiero rechazar esas conexiones utilizando iptables. Por lo tanto, quiero buscar la cadena "HTTP/1.1" seguida de dos CR/LF subsiguientes (CR/LF/CR/LF) (lo que da en total la cadena hexadecimal 485454502f312e310d0d0a0d0a
) en la carga de los paquetes.
Pero es absurdo desperdiciar ciclos de CPU buscando esta cadena en todos los paquetes TCP cuando sé que está en el primer paquete. Incluso sería incorrecto porque "HTTP/1.1" seguido de dos CR/LF subsiguientes podría ser una parte legal de la transmisión dentro de la carga útil de las solicitudes http.
Aquí hay una solución para este problema, pero no entiendo la parte que identifica el primer paquete de una conexión TCP establecida: http://spamcleaner.org/es/misc/w00tw00t.html
Lo que no entiendo es por qué los 3 paquetes del Handshake TCP inicial (SYN, ACK+SYN, ACK) se pueden ver en la cadena INPUT o una cadena a la que solo se puede acceder desde INPUT. Hasta donde entendí iptables y sus cadenas, el segundo paquete (ACK+SYN) nunca pasa por INPUT. Creo que pasa por OUTPUT porque soy yo (es decir, el servidor) quien lo envía.
Este es el script de spamcleaner.org, solo cambié algunos comentarios en la primera parte del script pero dejé todos los comandos sin cambios:
#!/bin/bash
# permitir loopback
iptables -A INPUT -i lo -j ACCEPT
# BLOQUEAR cualquier IP que esté en la lista negra "w00tlist" y establecer el tiempo de espera de la lista negra en 6 horas
iptables -A INPUT -p tcp -m recent --name w00tlist --update --seconds 21600 -j DROP
# crear la cadena "w00tchain"
iptables -N w00tchain
# esta cadena agregará la IP a la lista negra "w00tlist"
# y restablecerá la conexión:
iptables -A w00tchain -m recent --set --name w00tlist -p tcp \
-j REJECT --reject-with tcp-reset
# crear otra cadena llamada "w00t". Su propósito es identificar el primer paquete
# de una conexión TCP recién establecida y buscar una cadena en ella:
iptables -N w00t
# redirigir todos los paquetes TCP entrantes (no salientes) a la cadena "w00t":
iptables -A INPUT -p tcp -j w00t
# todas las reglas restantes son parte de la cadena "w00t"
#---------------------------------------------------------------
# todos los siguientes comentarios en minúsculas son sin cambios de spamcleaner.org
# LOS COMENTARIOS EN MAYÚSCULAS SON MÍOS
#---------------------------------------------------------------
# buscar el paquete SYN y crear la lista:
iptables -A w00t -m recent -p tcp --syn --dport 80 --set
# buscar el paquete SYN,ACK y actualizar la lista:
iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK SYN,ACK --sport 80 --update
#---------------------------------------------------------------------------------
# ESTO ES LO QUE NO ENTIENDO:
# LA CADENA w00t SOLO SE PUEDE ALCANZAR DESDE LA CADENA INPUT. ASÍ QUE AQUÍ ESTAMOS LIDIANDO
# CON PAQUETES QUE EL CLIENTE ESTÁ ENVIANDO Y QUE EL SERVIDOR ESTÁ RECIBIENDO. PERO EN
# EL PASO 2 DEL HANDSHAKE TCP, ES EL SERVIDOR QUIEN ESTÁ ENVIANDO Y EL CLIENTE QUIEN ESTÁ
# RECIBIENDO. ASÍ QUE EL PAQUETE CON SYN Y ACK ESTABLECIDOS Y CON sport 80 PASA POR LA
# CADENA "OUTPUT", NO "INPUT". ¿CÓMO PUEDE SER DETECTADO EN LA CADENA w00t?
#---------------------------------------------------------------------------------
# buscar el paquete ACK y actualizar la lista:
iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK ACK --dport 80 --update
# buscar la cadena hexadecimal en el primer PSH+ACK.
# Si se encuentra, redirigir a w00tchain para poner la IP en la lista negra y
# cerrar la conexión.
# Eliminar nuestra lista, no queremos filtrar más paquetes de esa conexión:
iptables -A w00t -m recent -p tcp --tcp-flags PSH,ACK PSH,ACK --dport 80 --remove \
-m string --to 80 --algo bm --hex-string '|485454502f312e310d0d0a0d0a|' -j w00tchain
Y hay una segunda cosa que no entiendo:
La última regla está buscando la cadena hexadecimal en un paquete que tiene sus banderas PSH y ACK establecidas. Pero, ¿cómo puedo estar seguro de que PSH está configurado para mi paquete? No estoy seguro, pero creo que es posible y legal enviar paquetes TCP que tengan la flag PSH desactivada.
EDITAR: Hay una tercera pregunta: ¿Qué sucede si el servidor recibe dos o más solicitudes HTTP sobre TCP de la misma dirección IP al mismo tiempo (cada solicitud con su propio número de puerto)?