Recientemente he tenido que jugar con la biblioteca Scapy para Python. Ésta permite crear cualquier tipo de paquete de red con un par de simples comandos, incluso para protocolos no existentes mediante paquetes RAW.
En este caso pondré de ejemplo la necesidad de tener que enviar paquetes TCP a un puerto determinando usando cualquier combinación de flags TCP, con el objetivo de evaluar el comportamiento de la pila TCP al recibir cualquier combinación de flags.
Hay que tener en cuenta que no estamos hablando de permutaciones, puesto que es lo mismo enviar un paquete con el flags Syn y Ack que enviar un paquete con los flags Ack y Syn. Sí, seguramente habrán recordado la frase “el orden de los factores no altera el producto“. Por tanto es necesario generar cualquier combinación teniendo en cuenta que el orden no afecta y que no se desea enviar más paquetes de los estrictamente necesarios.
Con está idea cogí un folio y lo rellene con un par de combinaciones para crear un algoritmo que resolviera el problema dando como resultado “algo”, por concederle un nombre, bastante lento y que requería mucha lógica, teniendo en cuenta que no he considerado los flags de congestión y priorización de tráfico. El resultado fue el siguiente:
#!/usr/bin/python # -*- encoding: utf-8 -*- from scapy.all import * import sys ip = str(sys.argv[1]) port = int(sys.argv[2]) flags = ['S','A','F','R','P'] send(IP(dst=ip)/TCP(dport=port, flags="")) for i in range(len(flags)): send(IP(dst=ip)/TCP(dport=port, flags=str(flags[i]))) vueltag = 2 # Bloque mayor while(len(flags) >= vueltag): vueltap = vueltag inib = 0 while (vueltap < = len(flags)): bloque = "" aux = inib cont = 0 while (cont < vueltag - 1): bloque = bloque + flags[aux] aux = aux + 1 cont = cont + 1 finb = inib + cont while(len(flags) > finb): bandera = (bloque + flags[finb]) send(IP(dst=ip)/TCP(dport=port, flags=bandera)) finb = finb + 1 inib = inib + 1 vueltap = vueltap + 1 vueltag = vueltag + 1
Si se desea ejecutar el programa, se debe indicar como primer argumento la IP del servidor a auditar y como segundo argumento el puerto. Debe disponerse de Python y de Scapy, ambas incluidas por defecto en las distribuciones como BackTrack. Por ejemplo, para auditar el puerto 80 de la ip 127.0.0.1 se debe introducir lo siguiente:
# ./programa.py 127.0.0.1 80
Al ejecutarlo contra el puerto 80 de mi máquina local, cuya IP local era 127.0.0.1, pude registrar con la herramienta de auditoría de red Tcpdump que se generaba correctamente el resultado esperado, tal como se muestra en la siguiente imagen:
Pero si se tiene en cuenta cómo funciona el protocolo TCP/IP y que Scapy permite introducir datos en crudo con valores hexadecimales o binarios, se podría resumir el código anterior con algo tan simple como lo siguiente:
#!/usr/bin/python # -*- encoding: utf-8 -*- from scapy.all import * import sys ip = str(sys.argv[1]) port = int(sys.argv[2]) num = 0b000000 while(num < 0b1000000): send(IP(dst=ip)/TCP(dport=port, flags=num)) num = num + 0b1
Donde si quisiera ampliar el algoritmo para que comprobara los flags de congestión de tráfico únicamente debería modificar la condición while por lo siguiente:
num = 0b00000000 while(num < 0b100000000): send(IP(dst=ip)/TCP(dport=port, flags=num)) num = num + 0b1
Como se aprecia, de forma sencilla podriamos crear un script en Python que permitiera auditar las pilas TCP/IP de muchos dispositivos, añadiendo otras opciones como:
- Enviar a puerto “0”, a valores de puertos con valor máximo o utilizando el mismo puerto origen que destino.
- Versión TCP distinta a 4 y 6.
- Número de sesión y de acuse de recibo con valores idénticos, valores máximos o valor “0”.
- Enviar múltiples paquetes con mismo valor de sesión pero ip origen distinta.
- Misma dirección IP origen que destino o IP reservadas como origen.
- Fragmentación simple y con superposición.
- Tamaño, campos de tamaño, checksum inválido o no múltiplo de 32 bits.
- Opciones extra TCP no válidas.
Para finalizar recomiendo que en caso de programar las opciones anteriores, se tenga especial cuidado con lo que envía y con que velocidad lo hace, puesto que las centralitas telefónicas, entornos SCADA o impresoras suelen comportarse de forma distinta a lo esperado ante estos casos.
Muy interesante. Grande ir a nivel de bit, vaya como se simplifican las cosas ;)
Gracias!
Cero interesante explicarlo mejor que algunos somos tontos.