Detectando NICs en Modo Promiscuo

tdred

Buenas noches.

De todos los que nos solemos “encontrar” por Twitter son conocidos los #Ciberretos de @CiberpoliES.

El domingo pasado a las 12 de la mañana, que ninguno de los dos teníamos mucho que hacer por lo visto, recibí un mensaje directo de @CiberpoliES diciéndome que llevaba un rato enredando intentando descubrir tarjetas de red en modo monitor y que estaría bien que me currase un script que las detectara… Para ser exactos, el mensaje fue “A ver si se te ocurre algún script para detectar la presencia de tarjetas de red en modo monitor

Como las noches las solemos aprovechar para “investigar” a parte de leer vuestros mensajes de twitter, empecé a hacer pruebas para ver si se podía detectar con un script una tarjeta en modo promiscuo, más que nada porque una vez que alguien nos espeta algo como eso, no podemos dormir hasta que encontramos solución, y como yo creo que el resto de vosotros (también me preguntó un lector que para qué servía “enviar archivos mediante ping“… en fin)

Así que ni corto ni perezoso, raspberry por un lado y portátil con windows 10 y kali virtualizado por otro, manos a la obra a ver si podemos dar gusto a @CiberpoliES.

A las 4 de la madrugada del Lunes, ya tenía un script funcionando pero me faltaba que @CiberpoliES lo probase también, por aquello de comprobar que no sólo funciona en nuestro “laboratorio” y en “condiciones ideales” (y os aseguro que el entorno de @CiberpoliES no es el entorno ideal después de que tuviese que probar con 2 portátiles, la raspberry y no sé cuantas antenas porque a cada uno le falla algo jejejeje ;-D) Una vez probado y visto que funciona, aquí os lo presento (teniendo en cuenta los falsos positivos que comento en la nota informativa más adelante)

Pero… vayamos por partes. ¿Cómo se puede detectar una tarjeta en modo promiscuo en nuestra red? Primero veamos algo de teoría…

Las tarjetas de red en modo “normal” responden a 3 tipos de mensajes. El primer tipo son los mensajes que van dirigidos expresamente para ella (con su dirección mac), el segundo tipo son mensajes multicast para todos los dispositivos de la red o para el grupo de la tarjeta de red y el tercer tipo son los mensajes de Broadcast como por ejemplo ARP para solicitar la dirección mac de un equipo del que no se conoce (dirección FF:FF:FF:FF:FF:FF en la capa Ethernet y 00:00:00:00:00:00 en la capa ARP).

Es decir, la tarjeta de red en modo normal, sólo pasa paquetes al sistema operativo que cumplan una de esas tres condiciones: que sea para ella (su mac) o que sea multicast o broadcast y cumpla la condición del paquete (como tener su dirección ip en un paquete ARP solicitando su mac).

Por otra parte, analizando los distintos sistemas operativos y buscando información sobre el comportamiento de dichos sistemas ante este tipo de paquetes sabemos lo siguiente (es decir, cómo responde el sistema operativo al paquete, y no la tarjeta de red):

1.- La dirección multicast de todos los equipos de la red (01:00:5E:00:00:01) pasa la tarjeta de red en modo normal y promiscuo y es respondida por el sistema operativo tanto en Windows como en Linux.

2.- La direccion 0 multicast (01:00:5E:00:00:00) sólo pasa la tarjeta de red en modo promiscuo y sólo es respondida por Linux, no por Windows.

3.- La dirección multicast sólo con el bit de grupo activado (01:00:00:00:00:00) sólo pasa la tarjeta de red en modo promiscuo y sólo es respondida por Linux, no por Windows.

4.- La dirección de “falso” broadcast de 8 bits (FF:00:00:00:00:00) sólo pasa la tarjeta de red en modo promiscuo y es respondida por el sistema operativo en Windows 9X/ME y Linux.

5.- La direccion de “falso” broadcast de 16 bits (FF:FF:00:00:00:00) sólo pasa la tarjeta de red en modo promiscuo y es respondida por todos las versiones de Windows y Linux.

6.- La dirección de “falso” broadcast FF:FF:FF:FF:FF:FE sólo pasa la tarjeta de red en modo promiscuo y es respondida también por todas las versiones de Windows y Linux.

7.- La dirección de broadcast (verdadero broadcast) FF:FF:FF:FF:FF:FF pasa la tarjeta de red tanto en modo normal como modo promiscuo y es respondida por todos los sistemas operativos tanto Windows como Linux.

Es decir, tenemos que encontrar un paquete que enviado a los equipos sólo nos responda cuando esté en modo promiscuo, y que me permita aplicarlo a la mayoría de sistemas operativos.

Como podemos observar, el paquete idóneo es con la dirección de falso broadcast “FF:FF:FF:FF:FF:FE”, ya que si la tarjeta está en modo normal, será rechazado por no ser multicast, no ser broadcast “puro” ni ser la mac de la tarjeta, pero que si está en modo monitor será pasado al sistema operativo y nos responderá tanto Windows como Linux.

Manos a la obra. Os muestro 2 scripts.

El primero es la versión “rápida” de demostración. Sólo envío el paquete a toda la red con Scapy y pinto la mac e ip de los equipos que responden.

El segundo, es la versión completa. Permite elegir la interface de red a utilizar y detecta la red para hacer el bucle automáticamente a todos los equipos de dicha red, la puerta de enlace para descartar el router (ahora explico por qué), añadiendo el parámetro “-v” nos permite ver el paquete que va a enviar Scapy, etc…

Nota informativa: los script ejecutados en red cableada funcionan 100%, ya que todos los equipos que detectan están en modo monitor y el router es descartado por el script (ya que el “linux” que tiene dentro contesta también a ese tipo de paquetes dando un falso positivo). Si los ejecutamos en una red inalámbrica, aparecerán falsos positivos, como los teléfonos android que también contestan a todos los paquetes con el linux que llevan dentro…

Todavía no he encontrado una solución “fácil” para descartar los teléfonos android (ya he pensado en fabricante por la mac, fingerprints de so con p0f (igual que lo hace nmap), etc…) así que se aceptan sugerencias, teniendo en cuenta que no me gustaría usar más “aplicaciones de terceros” y no me gustaría salirme de módulos de python a poder ser…

Y dicho ésto, aquí están los script. No seáis malos con mi python, que ya sabéis que soy principiante en dicho lenguaje.

Sois libres de copiar, usar, modificar, distribuir… sólo me gustaría ir sabiendo las mejoras que le vais introduciendo al script.

Un saludo y hasta la próxima.

rapido.py

import sys
from scapy.all import *

conf.verb=0
ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:fe")/ARP(pdst="192.168.1.0/24"),timeout=2)

for snd,rcv in ans:
	print rcv.sprintf(r"%Ether.src% & %ARP.psrc%\\")

completo.py

import sys
from scapy.all import *

def get_mac_address(interf):
	my_macs = [get_if_hwaddr(interf)]
	for mac in my_macs:
		if(mac != "00:00:00:00:00:00"):
			return mac

def get_ip_address(interf):
	my_ips = [get_if_addr(interf)]
	for ip in my_ips:
		if(ip != "0.0.0.0"):
			return ip

def get_def_route(interf):
	data = os.popen("/sbin/route -n ").readlines()
	for line in data:
		if line.startswith("0.0.0.0") and (interf in line):
			return line.split()[1]

Timeout=2

if len(sys.argv)<2 or len(sys.argv)>3:
	print "Uso: prueba.py interface [-v]"
	sys.exit(1)
elif len(sys.argv)==3 and sys.argv[2]!="-v":
	print "Uso: prueba.py interface [-v]"
	sys.exit(1)
else:
	print "Interface seleccionado: " + sys.argv[1]
	my_mac = get_mac_address(sys.argv[1])
	my_ip = get_ip_address(sys.argv[1])
	octetos = my_ip.split(".")
	my_net = octetos[0] + "." + octetos[1] + "." + octetos[2] + ".0/24"
	my_gw = get_def_route(sys.argv[1])

if not my_mac:
	print "Error obteniendo MAC"
	sys.exit(1)
else:
	print "MAC Interface " + sys.argv[1] + ": " + my_mac

if not my_ip:
	print "Error obteniendo IP"
	sys.exit(1)
else:
	print "IP Interface " + sys.argv[1] + ": " + my_ip
	print "Red a Escanear: " + my_net
	print "Default Gateway para interface " + sys.argv[1] + ": " + my_gw

conf.verb=0

packet = Ether(dst="FF:FF:FF:FF:FF:FE",src=my_mac)/ARP(op=1,hwdst="00:00:00:00:00:00",hwsrc=my_mac,psrc=my_ip,pdst=my_net)

if len(sys.argv)==3 and sys.argv[2]=="-v":
	print "Mostrando Composicion del Paquete:"
	packet.show()

ans,unans=srp(packet,timeout=2)

print ""
print "Mostrando POSIBLES Modo Monitor en la Red:"
print ""

for snd,rcv in ans:
	if rcv.psrc!=my_gw:
		print rcv.sprintf(r"%Ether.src% & %ARP.psrc%")

2 opiniones en “Detectando NICs en Modo Promiscuo”

Deja un comentario