04 enero 2010

Esteganografía visual

Ya expliqué en qué consistía la esteganografía en uno de mis artículos anteriores. En aquel caso exploramos el arte de ocultar información en el tráfico usual de una red, pero esta no es sino una modalidad muy reciente del arcano arte de ocultar información entre lo cotidiano. Hasta llegar a ese punto, la esteganografía se enfocó a ocultar sus mensajes a los ojos de los demás... burlar a sus oídos y ya no digo a sus sniffers vendría mucho después.
En uno de mis próximos artículos trataré la esteganografía sonora, pero en este nos enfocaremos en la visual.

Ejemplos artísticos de mensajes ocultos a la vista hay muchos. A veces se jugaba con la perspectiva, como en el cuadro de Holbein "Los embajadores" que visto de frente es un retrato habitual en el que sólo llama la atención una mancha bastante rara entre los protagonistas.


Mirando el cuadro en el ángulo correcto, aparece una calavera (aproximadamente desde abajo y a la izquierda ya que el cuadro estaba pensado para ponerse en la pared de una escalinata curva interior):


En este caso se usó una técnica de perspectiva denominada anamorfosis para ocultar el mensaje del artista de que por mucho que el hombre se ilustre y estudie su mundo (simbolizado ello en los instrumentos de la mesa), la muerte siempre está presente y se cobrará su tributo (la calavera).

El historiador griego Herodoto citaba un par de ejemplos tempranos de esteganografía utilizada por los griegos para ocultar mensajes en los que se describían los planes persas de invasión. Uno de esos ejemplos describía como un griego tatuó el mensaje secreto de alerta en la cabeza rapada de uno de sus esclavos, dejó que le volviese a crecer el pelo y lo envió de camino a Grecia para avisar. Teniendo en cuenta lo que tarda el pelo en volver a crecer lo suficiente y el tiempo que implicaba cualquier tipo de viaje en aquella época o bien el mensaje no era tan urgente o es sencillamente una patraña. Otro ejemplo, más verosimil, es el que relata como el espía grababa el mensaje en una tablilla de cera sin ella y luego tapaba el mensaje añadiendola. Luego podía escribir un mensaje inofensivo en la cera de la tablilla para engañar cualquier inspección. Para acceder al mensaje sólo era necesario derretir la cera.

En tiempos más modernos es bastante habitual ver películas de espías que dejan mensajes en espejos cubiertos de vaho. Al desaparecer este, el mensaje se vuelve invisible pero puede visualizarse de nuevo abriendo el grifo de agua caliente y dejando que el vaho cubra de nuevo el cristal.

Todos estos son ejemplos de esteganografía visual. Hay muchos más, tantos como técnicas inventadas por el hombre. Nosotros nos fijaremos en una muy utilizada en informática. Esta técnica explota paradójicamente una de las habilidades en las que los seres humanos son superiores a las máquinas: la capacidad de aproximación. El cerebro humano carece de la precisión de los ordenadores, pero sin embargo es capaz de extraer conclusiones a partir de aproximaciones en las que se conjugan los datos captados y la experiencia previa. Esto, que un niño de tres años ya hace inconscientemente, es desde hace años el campo de batalla diario de los estudiosos de la Inteligencia Artificial. Aplicado al campo de las imágenes esta habilidad nos permite distinguir objetos a pesar de que estos se encuentren deformados o borrosos. Un ejemplo son los habituales captchas que retan a los usuarios a leer unos carácteres intencionadamente d eteriorados con el fin de asegurarse de que el "usuario" es una persona y no un programa de ordenador.

Sin embargo, cuando se trata de detectar detalles esta capacidad de aproximación juega en nuestra contra a no ser que ya estemos alerta. Si no estamos avisados de antemano o especialmente entrenados, lo normal es que veamos una forma, la interpretemos y si deducimos lo que significa facilmente pasemos a otra cosa ignorando los detalles. Un ejemplo de este fenómeno lo tenemos diariamente en los periódicos en el juego de encontrar las 7 diferencias. A no ser que seamos aficionados a ese juego lo normal es que no encontremos ninguna diferencia en el primer vistazo. Sin embargo las diferencias están ahí y no son sino información oculta en una imagen.

Nosotros explotaremos esto jugando con los colores de una imagen. Mientras que los ordenadores son capaces de distinguir con precisión un color de otro parecido en una paleta de miles de colores, lo cierto es que los seres humanos frecuentemente no somos capaces de distinguir dicha dife rencia sobre todo si la superficie de cada uno de los colores es muy reducida. ¿Seríamos capaces de distinguir si un pixel morado es exactamente igual de morado que el pixel que tiene a su lado?, la respuesta es que no, sobre todo si la diferencia es pequeña.

Los ordenadores actuales pueden mostrar en pantalla paletas de miles de colores. Para mostrar cada color, el ordenador le asigna un número identificativo de manera que los programas sólo tengan que usar ese número para decirle a la tarjeta gráfica que muestre ese color. Los colores similares tienen números correlativos así que si los visualizásemos consecutivamente veríamos gradientes de color en vez de cambios bruscos. Pongamos, por ejemplo, que una tarjeta gráfica pudiese mostrar imágenes en color verdadero lo que supondría que sería capaz de poner 16.777.216 colores diferentes en pantalla. Para ello cada color debería tener un número identificativo de 24 bits (2^24=16.777.216). Si jugásemos con el bit menos significativo (el de más a la derecha) del número identificativo para codificar información el usuario sería incapaz de notarlo ya que los colores resultantes serían tan parecidos que sería muy difícil distinguirlos entre si.

Así que eso será lo que hagamos, cogeremos una imagen y la recorreremos manipulando el bit menos significativo d e cada pixel de manera que ese bit corresponda a un bit del mensaje que queremos ocultar en la imagen.

Para ilustrarlo he escripto un pequeño programa en Python capaz de esconder un texto en una imagen que tenga formato BMP o PNG. El programa se puede descargar de google code y para ejecutarlo hace falta tener instalada la Python Imaging Library (PIL). En Ubuntu se puede instalar PIL mediante un sencillo comando:

$ sudo aptitude install python-imaging

Hecho lo anterior ya podemos ejecutar el programa desde la carpeta donde lo hayamos descomprimido. En dicha carpeta contamos con una imagen que hará de anfitrión de los datos a ocultar (lena_std.png) y el texto a ocultar (texto_a_ocultar.txt ;-) ). Se puede usar cualquier imagen PNG y cualquier texto pero hay que tener en cuenta que se tienen que cumplir determinadas relacio nes entre el tamaño de la imagen y el texto a ocultar, tal y como veremos al estudiar el código del programa. Para no complicarse la vida en la primera prueba lo mejor es usar los archivos de ejemplo que vienen junto al programa. Para ver los parámetros que acepta el programa no hay más que teclear su nombre sin ninguna opción:

$ ./stegimage.py Stegimage =========== Programmed by: Dante Signal31 Written for experimental purpuses. This program hides data in image files. Format ./stegimage.py -i ----------> image file to use for hiding. -d -----------> Data file to hide in image file -o ---------> Output image file with data file hidden inside. -x ------------> Extract data file (set with -d) from steg file. -s ------------> S ets how many bits we should hide in each selected pixel (DEFAULT=1) -h | --help --------------> Print this text. Examples: Hiding a file:./stegimage.py -i image_file.bmp -d hidden.txt -o image_steg_file.bmp Extracting a file:./stegimage.py -x image_steg_file.bmp -d hidden.txt


Siguiendo las indicaciones de la ayuda teclearemos lo siguiente para ocultar el texto de ejemplo (que dicho sea de apaso es un copy-paste de la excelente obra sobre el cifrado en la Segunda Guerra Mundial que Ramón Ceano publicó en Kriptópolis):

$ ./stegimage.py -i lena_std.png -d texto_a_ocultar.txt -o lena_steg.png


Como podemos comprobar se ha generado una nueva imagen (lena_steg.png) que es la que oculta el texto secreto. Visualmente las dos son idénticas (para un humano), la primera es la imagen original y la segunda la que contiene el mensaje:




Para extraer el mensaje oculto no tenemos más que hacer lo siguiente:

$ ./stegimage.py -d texto_extraido.txt -x lena_steg.png

Ahora estudiaremos el código del programa para entender bien cómo funciona esta técnica de ocultación. Haré un repaso puntual del código, pero habrá fragmentos de este que no plasmaré aquí porque no tienen mayor complicación así que recomiendo que el lector repase el código en su totalidad por su cuenta (no debería resultarle difícil porque he procurado comentarlo bastante y es bastante corto).

La función que se encarga de esconder los datos en la imagen es hideFile a la que se le pasan como parámetro dichos datos (en nuestro ejemplo el texto a esconder):

def hideFile(self, data_file_name):
        """ This function encodes data file into image host file."""
        self.data_file_size = (os.stat(data_file_name))[stat.ST_SIZE]
        self.calculateSeparation(self.getDataFileSize())
        self.data_file = open(data_file_name, 'rb')
        if (self.getSeparation() < 0): #This means that data file is too big.
            return ERROR
        else:
            self.encodeHeader()
            self.byte=self.data_file.read(1)
            self.bytes_written = 0
            while (self.byte):
                self.byte_in_bits = libmymath.int2bin(n=ord(self.byte), count=8)
                self.encodeBits(self.byte_in_bits)
                self.byte = self.data_file.read(1)
                self.bytes_written = self.bytes_written + 1
                self.percentage_done = /
int((float(self.bytes_written) / float(self.data_file_size)) *  100)
                print str(self.percentage_done) + "% : " + str(self.byte_in_bits)
            self.hostFileImage.save(self.hostFileName)
            self.data_file.close()
            return OK

Como se puede ver, esta función averigua el tamaño de los datos que queremos ocultar y posteriormente en la llamada a encodeHeader usará los primeros píxeles de la imagen para codificar en ellos el tamaño de los datos ocultados. En principio mi script cuenta con una constante HEADER_SIZE que fija 32 bits para codificar el tamaño de los datos ocultados por lo que los primeros 32 pixels consecutivos de la imagen tendrán sus bits menos significativos modificados (siempre y cuando STEP=1, como se explicará seguidamente). El número de bits que se modifican por pixels lo fija la constante STEP del fichero stegimage.py aunque el usuario la puede modificar usando el parámetro "-s" en la llamada al programa. En principio STEP está fijado a 1 de manera que sólo se modifica 1 bit por pixel tocado, esto significa que si queremos ocultar un byte de datos (8 bits) tendremos que modificar el valor del bit menos significativo de hasta 8 pixels para que dicho bit corresponda con el respectivo del byte a ocultar. Para recomponer el byte ocultado tendremos que mirar el bit menos significativo de cada uno de los 8 pixels e ir recomponiendo el byte original. Esto tiene una limitación y es que con un STEP=1 sólo podremos ocultar ficheros cuyo tamaño en bits no supere al número de pixel de la imagen tras restar los 32 pixels que consume el codificado de la cabecera. Para superar esta limitación, y ocultar textos o ficheros más extensos, se puede aumentar el valor de STEP para ocultar más bits del mensaje en cada pixel de la imagen pero en ese caso hay que tener en cuenta que la variación de color entre el pixel modificado y sus vecinos es más brusca y la anomalía será más fácilmente detectable, como se puede ver en la imagen de ejemplo siguiente en la que se ocultó el mismo texto que antes con un STEP=16 (fíjese como ahora los pixel modificados sí son claramente detectables en la forma de esas líneas verticales de "ruido"):



Como también se puede ver en la imagen anterior, los bits modificados están equiespaciados para dificultar su detección al dispersar la anomalía generada. La separación entre pixels modificados se calcula con la llamada a calculateSeparation de hideFile en función del tamaño del mensaje a ocultar, el tamaño en pixels de la imagen contenedora y el STEP que hayamos fijado. Hay que tener en cuenta que si se ha usado un STEP diferente de 1 (el de por defecto) habrá que decírselo a stegimage.py a la hora de extraer el mensaje. Si no se hace así, el programa no sabrá en qué pixels fijarse para reconstruir el mensaje (o mejor dicho, usará un STEP=1 y mirará los pixels equivocados). Por ejemplo, si al codificar hubiésemos usado un STEP de 8, la orden de extracción sería la siguiente:

$ ./stegimage.py -d texto_extraido.txt -x lena_steg.png -s 8


Una vez calculada la separación mediante calculateSeparation y grabada la cabecera en los primeros pixels mediante encodeHeader, la función hideFile comienza un bucle en el que va leyendo byte a byte el mensaje a ocultar y va grabando esos bytes en los pixels de la imagen mediante la función encodeBits:

 def encodeBits(self, bit_string,  position=0):
        """ This function deals with writing of long bit strings."""
        if (position == 0):
            self.current_position = self.last_position
        else:
            self.current_position = position
#        self.x = 0
        for bit in bit_string:
            self.setBit(self.current_position, bit,  self.x)
            if (self.x < self.step-1):#We store up to STEP data bit in every selected pixel.
                self.x = self.x + 1
            else:
                self.x = 0
                self.current_position = self.current_position + self.separation
        self.last_position = self.current_position
La clave de la función anterior, la que realmente modifica el pixel es setBit:
 def setBit(self, startPosition, value_string,  offset=0):
        """ To put a bit in a position. """
        self.pos_y = int(libmymath.myround((startPosition / self.width),  libmymath.DOWN))
        self.pos_x = (startPosition % self.width)
        self.original_value = self.pixmap[self.pos_x,  self.pos_y]
        self.binary_original_value_string = self.color2binary(self.original_value)
        if (offset == 0):
            self.binary_modified_value_string = /
self.binary_original_value_string[:-(offset+1)] + value_string
        else:
            self.binary_modified_value_string = /
self.binary_original_value_string[:-(offset+1)] + value_string + /
self.binary_original_value_string[-offset:]
        self.modified_value = self.binary2color(self.binary_modified_value_string)
        self.pixmap[self.pos_x,  self.pos_y] = self.modified_value

Una vez codificados todos los bytes del mensaje a ocultar en los pixels de la imagen, hideFunction guarda la imagen modificada en el fichero de salida que fijamos al llamar al programa mediante la función hostFileImage.Save.

Con esto queda explicado el esqueleto del proceso de ocultación de un mensaje en una imagen, el proceso de extracción para obtener de vuelta el mensaje es exactamente igual pero a la inversa. Para más detalle lo mejor es una lectura detenida del código fuente de stegimage.py y de sus librerías adjuntas. Creo que el código está lo suficientemente conciso y comentado como para asegurar una fácil comprensión.

Así damos fin a este artículo, en el que hemos repasado brevemente la historia y las bases del extensísimo campo de la esteganografía visual. Este campo está en constante movimiento, no sólo por su utilidad en el campo de la Inteligencia (con I mayúscula) sino también en el comercial, concretamente en el de la protección de derechos de autor ya que la esteganografía es un recurso excelente para firmar determinadas fotografías de manera que se puede controlar su difusión comercial.

21 marzo 2009

Evitando las escuchas en redes conmutadas

En un artículo que publiqué en Diciembre hablé sobre distintas técnicas para realizar escuchas en redes conmutadas. Me quedó pendiente desarrollar qué opciones tenemos frente a este tipo de ataques.

Las ataques de ARP Spoofing, también llamados envenenamiento ARP, se basan en introducir información falsa en las tablas de ARP de uno (o ambos) de los de los extremos de una comunicación con el fin de que este utilice inadvertidamente al atacante como intermediario a la hora de trasnmitir y recibir información. Esto permite al atacante no sólo espiar la información intercambiada por el atacado, sino también modificarla a su antojo.

Para combatir con eficacia este tipo de amenazas, un ingeniero de seguridad debe ser consciente de las técnicas de prevención, detección y reacción que puede emplear contra ellas.

La principal técnica de prevención es un buen diseño de la red. Muchos ingenieros no se dan cuenta, pero poner PCs de usuario en redes de paso supone un verdadero riesgo ya que si alguno decidiese utilizar herramientas de ARP Spoofing podría interceptar no sólo el tráfico destinado y originado hacia/desde su segmento sino todo aquel que lo utilice como red de tránsito. Un diseño correcto puede limitar a un único segmento de red el daño que un atacante puede realizar mediante ARP Spoofing. La manera de evitar esto es mantener las redes intermedias de tránsito vacías de PCs de usuarios, concentrando a estos en segmentos localizados en las "hojas" de nuestra red.



A la izquierda de la figura anterior (no se por qué pero Blogger la saca muy borrosa, si quiere ver el original, mucho más definido, pulse sobre la imagen) se puede ver una red mal diseñada al permitir que la red de paso (B) contenga PCs de usuario. Cualquiera de estos PCs de usuario puede lanzar un ataque de ARP Spoofing para desviar el tráfico cursado entre el router interior y el exterior con el resultado de que podría espiar todo el tráfico saliente de la red A.
A la derecha de la figura anterior se encuentra un diseño correcto. En él, la red B se ha vaciado de PCs de usuario. Los PCs que antes estaban en B han pasado a una red "hoja", C. Gracias a este diseño, un atacante de la red C sólo podría escuchar el tráfico de su red pero no de la B.

Este buen diseño sobre el papel debe desplegarse en la práctica de manera correcta. Si a pesar de haber vaciado de PCs las redes de tránsito, un intruso puede pinchar un portátil a una de estas redes seremos igual de vulnerables que antes. Para evitarlo hay que tomar medidas preventivas en los niveles de la capa OSI 2 y 1 (enlace y físico):
  • En la capa 2 hay que segmentar los conmutadores que dan servicio a las distintas redes en VLANs separadas asignando a cada VLAN única y exclusivamente los puertos dedicados a cada uno de los equipos residentes en ellas. Muchos administradores dejan puertos libres en cada VLAN por si un día se necesita pinchar urgentemente un equipo a ellas sin tener que esperar a que el administrador lo configure en el conmutador; esa comodidad tiene su contrapartida negativa y es que se deja abierta una puerta a nuestra red, puerta que puede aprovechar un atacante para pinchar su equipo a nuestra red si consigue acceso físico al conmutador (cosa no demasiado difícil en algunas organizaciones). Además, los puertos en uso de las redes de tránsito deben protegerse de alguna manera para evitar que máquinas no autorizadas se conecten a ellas. Lo ideal sería desplegar una solución del tipo NAC o 801.1X, pero la mayor parte de las redes actuales carece por ahora de la infraestructura necesaria para algo tan complejo. Al menos, lo que sí se puede hacer es limitar el uso de esos puertos concretos del conmutador a las MACs concretas de los equipos legítimos. No es una solución definitiva porque es muy fácil falsificar la MAC de un equipo, pero al menos servirá para retrasar al atacante y, con suerte, generará algún log de error en el equipo que servirá para alertar a los administradores si estos cuentan con una infraestructura de correlación de logs adecuada (del tipo Cisco Mars, Bitácora, logICA, etc). Por último, habrá que configurar los conmutadores correctamente para evitar que se utilicen contra ellos algunas de las VLAN Hopping existentes para acceder a una VLAN desde un puerto perteneciente a otra diferente.
  • En la capa 1 las medidas de seguridad son evidentes y se corresponden, al fin y al cabo, con las medidas de seguridad habitualmente recomendadas para las instalaciones de comunicaciones y tratamiento de datos. Básicamente se trata de impedir que una persona no autorizada pueda interactuar físicamente con alguno de nuestros conmutadores, por ejemplo pinchando su portátil a una VLAN no autorizada, apagando el conmutador para forzar una redirección del tráfico, o accediendo al puerto de consola del conmutador para reconfigurarlo. Para ello, el equipamiento de comunicaciones debe situarse en armarios cerrados con llave y preferiblemente vigilados con un circuito cerrado de cámaras, en salas de acceso restringido y con un soporte eléctrico y climático controlado y a prueba de fallos.
También está la opción de desplegar infraestructuras especializadas en combatir este tipo de ataques. Tal es el caso de algunas propuestas de código abierto enfocadas a integrar en la red un servidor dedicado a responder a las peticiones ARP a partir de una tabla centralizada con todas las correspondencias IP-MAC de la red, de manera que los conmutadores bloquearían todas las respuestas ARP (incluidas las utilizadas por el atacante para envenenar las tablas de ARP) excepto los originadas desde el puerto de este servidor. El problema de esta opción es la complejidad al no existir herramientas ya desarrolladas que implementen estos mecanismos y depender de las soluciones artesanales que se programe cada uno.

Para seguir el resto de las explicaciones le recomiendo que descargue y experimente con la maqueta de Netkit que he utilizado para escribir este artículo, es similar a la que se usó de ejemplo en los artículos "Creación de laboratorios virtuales con Netkit" I y II (lea estos artículos si no sabe como utlizar una maqueta realizada con Netkit) pero le he añadido una red de gestión, de manera que tenga una puerta trasera para acceder a los equipos por SSH sin mezclarse con el tráfico de la red de pruebas.

En el escenario de ejemplo, Alice quiere navegar por internet a través de un conmutador y un enrutador que le sirve de puerta de enlace; y PC-Sniffer quiere espiar el tráfico que Alice intercambia con Internet.

Teniendo en cuenta lo anterior y a partir de ahora, el esquema de la red de pruebas que vamos a utilizar en este artículo es el siguiente:




En lo que se refiere a las técnicas de detección, la vigilancia de los paquetes intercambiados en la red y de las tablas de ARP de los equipos clave serán nuestras principales armas.

Vigilando el tráfico de red se pueden detectar anomalías que nos alerten del trascurso de un ataque de ARP Spoofing. Examinando con Wireshark capturas del tráfico cursado a través del Switch de la maqueta podemos ver las siguientes anomalías:
  • En la captura del ataque con Ettercap podemos ver (paquetes 1 a 4) como el PC Sniffer (192.168.0.3) pregunta a la red por la MAC del Router (192.168.0.1) y por la de Alice (192.168.0.2). En los paquetes 5 y 6 ya aparecen las primeras señales de alerta; aparentemente el Router y Alice se lanzan pings entre sí, pero si examinamos la MAC de origen de ambos ping podemos ver que ¡en realidad se trata la MAC del PC-Sniffer!. Inmediatamente después, y sin esperar respuesta a los ping, el PC Sniffer manda actualizaciones de ARP para "envenenar" las tablas de Alice y el Router (paquetes 7 y 9). El resultado es que las respuestas a los pings le llegan al PC-Sniffer, lo que le permite saber que su ataque ha tenido éxito. En los paquetes 15 y 16 se puede ver como las respuestas a los pings se reenvían a sus legítimos destinarios, tal y como se hará con el resto del tráfico una vez que el PC-Sniffer lo haya visualizado. A partir de ahí (paquetes 19 a 26) se puede ver como el PC-Sniffer insiste machaconamente en enviar paquetes de actualización ARP para mantener las tablas de Alice y del Router "correctamente envenenadas". Si todo lo anterior ya debería inquietarnos, es cuando Alice comienza a navegar cuando vemos que algo va definitivamente mal. Porque a partir del paquete 43 vemos que todo el tráfico parece duplicado. Esto se debe a que el tráfico tiene que atravesar el Switch una vez, de camino al PC-Sniffer, y otra, de camino a su destinatario, en vez de atravesar el Switch una única vez (que sería lo lógico). De hecho, al mismo Wireshark le parece rara la situación y a partir del paquete 48 comienza a colorear de negro los paquetes repetidos para alertar de que algo no va nada bien.
  • Por su parte, en la captura del ataque realizado con Arppoison (incluido en la carpeta /root/scripts del PC-Sniffer de la maqueta), se pueden observar comportamientos anómalos. Arpoison es una herramienta programada con fines didácticos, así que su funcionamiento es algo más primitivo que el de Ettercap. Para empezar no hace un ping previo para comprobar que el envenenamiento se ha realizado con éxito y luego produce las mismas anomalías en los paquetes intercambiados e incluso alguna más. Y es que, cuando se usa Arpoison, se puede ver como en las capturas realizadas en el Switch aparece paquetes de ICMP Redirect (el primero aparece en el paquete 12), tan raros en las redes modernas que el Wireshark lo colorea de negro para señalarlo como anomalía. Esto se debe a que Arpoison utiliza Scapy para manejar paquetes y este a su vez Libpcap para realizar las escuchas. el problema es que Libpcap saca copias de los paquetes recibidos y se las entrega a las aplicaciones de usuario, pero no impide que los paquetes originales sigan siendo procesados por el kernel del PC. El kernel del PC-Sniffer no sabe nada de las aviesas intenciones de su dueño por lo que reacciona automáticamente cuando recibe un paquete que no está dirigido a su dirección IP enviando un paquete de ICMP Redirect alertando al remitente de que esos paquetes no le corresponden. Esta anomalía es tan evidente que cualquier IDS/IPS, por malo que fuese, lo habría detectado; para evitarla el dueño del PC-Sniffer podría haber activado su cortafuegos local para bloquear con él todos los paquetes ICMP salientes (si su cortafuegos le permite afinar bastaría con bloquear los paquetes ICMP Redirect salientes).

A nivel local, las inconsistencias en las tablas de ARP son síntomas muy serios de un posible ataque. Generalmente, es muy difícil que un PC y el enrutador que hace de puerta de enlace de la red tengan la misma MAC por lo que cuando esto ocurra deberían encenderse nuestras alarmas. Otra anomalía que debería ponernos en alerta es el cambio de la MAC conocida de equipos clave de la red, como por ejemplo los enrutadores que hacen de puerta de enlace.

En estado normal, la tabla de ARP de Alice tiene el siguiente aspecto:

PC-Alice:~# arp -i eth0 -a ? (192.168.0.1) at EA:0E:85:D7:58:04 [ether] on eth0

Si el atacante (PC-Sniffer) iniciase un ataque con Ettercap:

PC-Sniffer:~# ettercap -M arp:remote -T /192.168.0.1/ /192.168.0.2/ ettercap NG-0.7.3 copyright 2001-2004 ALoR & NaGA Listening on eth0... (Ethernet) eth0 -> CA:88:E3:51:83:57 192.168.0.3 255.255.255.0 SSL dissection needs a valid 'redir_command_on' script in the etter.conf file Privileges dropped to UID 65534 GID 65534... 28 plugins 39 protocol dissectors 53 ports monitored 7587 mac vendor fingerprint 1698 tcp OS fingerprint 2183 known services Scanning for merged targets (2 hosts)... * |==================================================>| 100.00 % 2 hosts added to the hosts list... ARP poisoning victims: GROUP 1 : 192.168.0.1 EA:0E:85:D7:58:04 GROUP 2 : 192.168.0.2 BA:4E:E3:B8:96:91 Starting Unified sniffing... Text only Interface activated... Hit 'h' for inline help Sat Mar 14 10:59:44 2009 TCP 192.168.10.1:49581 --> 192.168.0.2:22 | AP ...`..........I.S.4S..o^...D./~.....u.i....K...gaK5J


El resultado sobre la tabla de ARP de Alice sería el siguiente:

PC-Alice:~# arp -i eth0 -a ? (192.168.0.1) at CA:88:E3:51:83:57 [ether] on eth0 ? (192.168.0.3) at CA:88:E3:51:83:57 [ether] on eth0

Como se puede ver, desde el punto de vista de Alice, no sólo ha cambiado la MAC del enrutador (192.168.0.1) sino que además ahora parece coincidir con la MAC de un PC (192.168.0.3), lo que es señal inequívoca de que se está produciendo un ataque de ARP Spoofing que intenta desviar el tráfico de Alice destinado al enrutador hacia un PC intruso. Cuando este PC finaliza Ettercap, este se encarga de restablecer las tablas de ARP a su estado correcto. Lo que deja a Alice de la siguiente manera:

PC-Alice:~# arp -i eth0 -a ? (192.168.0.1) at EA:0E:85:D7:58:04 [ether] on eth0 ? (192.168.0.3) at CA:88:E3:51:83:57 [ether] on eth0

Como se puede ver, el ataque deja huellas tanto durante su transcurso como durante un corto tiempo tras él (hasta la expiración de la entrada en la tabla de ARP). Esto se debe a que el intruso debe interactuar con sus víctimas, antes de iniciar el ataque, para recopilar las MACs de dichos equipos con el fin de reparar las tablas de ARP tras él. Se puede estudiar la estructura interna de un programa similar a Ettercap en el mencionado artículo sobre escuchas en redes conmutadas. En ese programa, el Arpoison mencionado antes, la función que deja la huella "incriminatoria" en las tablas de ARP es la función gatherData(), ejecutada antes del ataque mismo. Como esta función debe preguntar a Alice y al Router por sus MAC mediante una llamada de ARP (representada en el código fuente del artículo por la llamada a la función scapy.getmacbyip() dentro de gatherData()), es el momento en el que el atacante PC-Sniffer "toca" directamente a sus víctimas dejando las huellas mencionadas. Se podría plantear la pregunta de si el atacante podría renunciar a ejecutar esta función para minimizar su huella, pero lo cierto es que no, porque si no averigua las MACs originales de los equipos a espiar no podrá lanzar el ataque ni reconstruir las tablas de ARP tras él.

Visto lo anterior, es evidente que son necesarias herramientas automatizadas que nos permitan defender las tablas de ARP de los equipos críticos que queramos salvaguardar de este tipo de ataques.

Una de las herramientas clásicas a este respecto es Arpwatch. Esta herramienta monitoriza la tabla de ARP y alerta por correo electrónico al administrador cuando se produce el cambio de una correspondencia IP-MAC. Lo ideal es instalar dicha herramienta en todas las estaciones de trabajo Linux de la red. En redes con direccionamiento estático, si se tiene la certeza de que no se ha producido el recambio de la tarjeta de red de ningún ordenador, la llegada de un correo de Arpwatch suele ser alerta inequívoca de que se está produciendo un ataque de ARP Spoofing. En redes con direccionamiento dinámico (DHCP), los pares IP-MAC cambian con cierta frecuencia, por lo que puede ser complicado monitorizar todos los cambios, aunque lo que sí se puede vigilar es el registro IP-MAC de la puerta de enlace por defecto de cada red, la cual debería permanecer inalterable en las tablas de ARP de todas las estaciones de trabajo.

Otra opción, algo más compleja pero con más posibilidades es ArpON. A diferencia de Arpwatch, ArpON no se limita a alertar al administrador sino que reacciona para bloquear el ataque. ArpON tiene dos modos de funcionamiento, estático y dinámico. En modo estático (SARPI), ArpON toma nota al arrancar de las entradas de la tabla de ARP, guardando esta información en una caché alternativa. A partir de ahí, ArpON sólo permite que se tramiten las peticiones y respuestas ARP de pares IP-MAC que no entren en contradicción con la información previa de su caché. El modo dinámico (DARPI) es similar, pero permite que la caché de ArpON vaya incorporando nuevos pares IP-MAC desconocidos en el momento de su arranque.

En redes con DHCP se puede optar también por activar un sistema de DHCP Snooping. Aparte de evitar que aparezcan servidores DHCP "furtivos", este sistema mantiene un registro de las MACs asociadas a las IPs concedidas y los puertos de los conmutadores donde se encuentran estas MACs. Con esta información, el sistema monitoriza los intercambios de ARP que se producen en sus puertos y si detecta un paquete ARP cuyo origen a nivel IP no se corresponde con la MAC registrada lo bloquea para impedir el envenenamiento. Esta opción se encuentra ampliamente disponible, por ejemplo en los equipos de Cisco donde recibe el nombre de Dynamic ARP Inspection.