domingo, 18 de noviembre de 2007

Escaneo de puertos con hping/scapy

Voy a postear un resumen de mi conversación (o casi entrevista, por el nivel de mis preguntas) con Pci, sobre un problemilla que tenia yo de esos de ninja-tcp/ip con un puerto abierto tras un firewall.

El caso es que hay un puerto 443 abierto al que si le lanzo un hping con el flag de syn activado no me devuelve el syn-ack, en cambio si se usa scapy o un simple telnet responde correctamente.

He tratado de copiar los parametros que lanza scapy con el hping, para reproducir el problema:

hping2 -S -s 20 -p 443 192.168.1.2 -c 1 -w 8192 -M 0

HPING 192.168.1.2 (eth1 192.168.1.2): S set, 40 headers + 0 data bytes

--- 192.168.1.2 hping statistic ---
1 packets tramitted, 0 packets received, 100% packet loss


Pero el puerto sigue dandome como cerrado (sin respuesta syn/ack).
En cambio con scapy:

# scapy
NFO: did not find python gnuplot wrapper . Won't be able to plot
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump()
Welcome to Scapy (v1.1.1 / f88d99910220)
>>> p=IP(dst="192.168.1.2")/TCP(dport=443, flags="S")
>>> sr(p)
Begin emission:
........Finished to send 1 packets.
..........*
Received 19 packets, got 1 answers, remaining 0 packets
(, )
>>> sr(p)
Begin emission:
.Finished to send 1 packets.
....*
Received 1 packets, got 1 answers, remaining 0 packets
(, )


Tras lanzar varios paquetes y hacer varias pruebas, no conseguí detectar el problema, ya que yo con mi packetyzer/wireshark veia los paquetes iguales.

Le pasé la captura a pablo y viendo el paquete en hexadecimal notó que en el SYN del hping, el flag del ACK venia con basura y por eso, el firewall lo rechazaba al no cumplir con el RFC.

# tcpdump -S -nn -vv -S -r test.pcap
reading from file test.pcap, link-type EN10MB (Ethernet)
13:29:07.860840 IP (tos 0x0, ttl 64, id 52124, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: S, cksum 0x8702 (correct), 0:0(0) win 8192
13:29:13.161027 IP (tos 0x0, ttl 64, id 36260, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: S, cksum 0xa474 (correct), 0:0(0) win 8192
13:29:16.469161 IP (tos 0x0, ttl 64, id 45487, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: S, cksum 0x23e0 (correct), 0:0(0) win 8192
13:29:30.178422 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: S, cksum 0x1483 (correct), 0:0(0) win 8192
13:29:30.225455 IP (tos 0x0, ttl 54, id 0, offset 0, flags [DF], proto: TCP (6), length: 44) 192.168.1.2.443 > 91.121.84.156.20: S, cksum 0x8176 (correct), 1896551268:1896551268(0) ack 1 win 5840
13:29:30.225484 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: R, cksum 0x3480 (correct), 1:1(0) win 0
13:29:36.065275 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: S, cksum 0x1483 (correct), 0:0(0) win 8192
13:29:36.111614 IP (tos 0x0, ttl 54, id 0, offset 0, flags [DF], proto: TCP (6), length: 44) 192.168.1.2.443 > 91.121.84.156.20: S, cksum 0xb201 (correct), 1902436991:1902436991(0) ack 1 win 5840
13:29:36.111636 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: R, cksum 0x3480 (correct), 1:1(0) win 0
13:29:40.329581 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: S, cksum 0x1483 (correct), 0:0(0) win 8192
13:29:40.376197 IP (tos 0x0, ttl 54, id 0, offset 0, flags [DF], proto: TCP (6), length: 44) 192.168.1.2.443 > 91.121.84.156.20: S, cksum 0xa04f (correct), 1906701296:1906701296(0) ack 1 win 5840
13:29:40.376226 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: TCP (6), length: 40) 91.121.84.156.20 > 192.168.1.2.443: R, cksum 0x3480 (correct), 1:1(0) win 0
13:29:45.807752 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: ICMP (1), length: 84) 91.121.84.156 > 192.168.1.2: ICMP echo request, id 59697, seq 1, length 64
13:29:45.848978 IP (tos 0x0, ttl 54, id 56093, offset 0, flags [none], proto: ICMP (1), length: 84)

En esta captura se pueden ver: 3 paquetes syn lanzados con hping, 3 lanzados con scapy y los syn-ack y rst que devuelve el puerto abierto y unos pings lanzados para no tener problemas con el buffer de tcpdump.

La siguiente es la captura en hex del hping

13:29:16.469161 IP (tos 0x0, ttl 64, id 45487, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156
.20 > 192.168.1.2.443: S, cksum 0x23e0 (correct), 0:0(0) win 8192
0x0000: 4500 0028 b1af 0000 4006 4f90 5b79 549c E..(....@.O.[yT.
0x0010: aaaa aaaa 0014 01bb 0000 0000 5f0c 9196 ............_...
0x0020: 5002 2000 23e0 0000 P...#...
13:29:30.178422 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20


Y está es la captura del paquete de scapy:

13:29:30.178422 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto: TCP (6), length: 40) 91.121.84.156.20
> 192.168.1.2.443: S, cksum 0x1483 (correct), 0:0(0) win 8192
0x0000: 4500 0028 0001 0000 4006 013f 5b79 549c E..(....@..?[yT.
0x0010: aaaa aaaa 0014 01bb 0000 0000 0000 0000 ................
0x0020: 5002 2000 1483 0000 P.......

Como se pude ver, hping rellena el flag no-ACK con: 5f0c 9196, no valido según el RFC causando que el firewall deniege el paquete y el puerto aparezca como cerrado.

La razón es esta linea en el código fuente (de sendtcp.c:59):
tcp->th_ack = (set_ack) ? htonl(tcp_ack) : htonl(rand());

Por alguna razon misteriosa, se decide rellenar mediante rand() ....

Para solucionar el problema, se puede lanzar ping con la siguiente sintaxis:
hping2 -S -s 20 -p 443 192.168.1.2 -c 1 -w 8192 -M 0 -L 0

Y el problema quedaría resuelto.