Hoy en día los dispositivos conectados a redes locales y redes móviles conectan globalmente a otras redes, recursos y sistemas a dichos dispositivos. En el mercado global, todos estamos conectados. Incluso en redes que NO nos pertenecen o a las cuales NO nos han solicitado permiso de actuar o de conectarse a las mismas.

En esta práctica vamos a crear una aplicación en PYTHON para comprobar nuestra actividad de red local y ver qué dispositivos están conectados a la misma, para poder auditoría e identificar clientes en nuestras subredes.

Entenderás que es el tráfico a bajo nivel ARP y sabrás porqué el PING no es un método totalmente efectivo para conocer el estado de las máquina en red.

Para ésta práctica necesitarás:

● Un PC con Windows.
● Python instalado en tu máquina.
● Ganas de aprender.

Es importante conocer el sistema y su funcionamiento para saber prevenirlo. A continuación vamos a ir desgranando algunos conceptos necesarios para ésta practica.

ARP y Diferencia con PING.
La mayoría de los técnicos están acostumbrados a usar la herramienta nativa en Windows y Linux llamada PING para hacer un descubrimiento de la máquina en red (sea máquina servidor, máquina equipo o dispositivo de red), usando el comando de red siguiente:

ping google.es Haciendo ping a google.es [216.58.205.67]con 32 bytes de datos: Respuesta desde 216.58.205.67: bytes=32 tiempo=7ms TTL=120 Respuesta desde 216.58.205.67: bytes=32 tiempo=8ms TTL=120 Respuesta desde 216.58.205.67: bytes=32 tiempo=12ms TTL=120 Estadisticas de ping para 216.58.205.67: Paquetes: enviados: 4, recibidos: 4, perdidos: 0 (0% perdidos): tiempos aproximados de ida y vuelta en milisegundos: Minimo = 7ms, Máximo = 12ms, Media = 8ms Console

Esto te devuelve una respuesta de que el equipo está activo (en este caso es una dirección de Internet y un servidor que es habitual que esté activo y respondiendo al protocolo ICMP). Pero además, puedes ver equipos dentro de tu propia red si haces ping a la IP del equipo.

Pero ahora imagina que un usuario se conecta a tu red WIFI con un portátil con W11, y además, se conecta con un perfil de red de modo público o con un firewall estricto.

Lanzas un escaneo básico a tu red con PING y resulta que el ordenador conectado a la WIFI no aparece en la lista porque el firewall de Windows intercepta el paquete ICMP echo request y lo descarta directamente por regla de seguridad.

Por lo tanto si no detecta la máquina crees que una IP no existe o no está conectada a tu red.

Resolución ARP.

ARP es el protocolo de resolución de direcciones que asigna una dirección MAC a una dirección IP de un dispositivo, por lo que si un dispositivo se conecta en una red local, el dispositivo es reconocido a nivel de enlace por su MAC física y no únicamente por su IP de capa 3 que puede cambiar en cualquier momento.

La diferencia entre usar ping y usar ARP es que el protocolo ARP funciona en la capa 2 del modelo OSI (capa de enlace de datos). Para que cualquier equipo pueda enviar o recibir tramas dentro de la LAN, necesita resolver la dirección MAC física del destinatario.

En esta práctica vamos a construir un script con PYTHON que usará scapy, que es una librería que permite trabajar con tramas ARP. Con scapy podremos lanzar una petición ARP (a nivel de capa de enlace), que preguntará:

"¿Quién tiene la dirección IP específica?"

E interrogará a la red mediante la dirección de difusión Ethernet en formato FF:FF:FF:FF:FF:FF. Al consultar mediante ARP, el dispositivo que tenga asignada esa IP en la subred debe responder para establecer la comunicación local:

"¡Sí, soy yo!"

¿Por qué funciona así?
Esta trama física llega a la interfaz de red del equipo objetivo. Para que el dispositivo mantenga la conectividad en la red local con el router o con los demás equipos, la pila TCP/IP del sistema operativo necesita procesar la resolución ARP a nivel de tarjeta de red.

El sistema operativo responde con un ARP Reply:

"La IP 192.168.1.50 es mía y mi MAC es AA:BB:CC:DD:EE:FF"

Resultado: Capturamos la MAC y la IP activa en el segmento de red local, sorteando los bloqueos habituales de paquetes ICMP del Firewall de Windows.

Funcionamiento de ARP

Funcionamiento básico del protocolo ARP.

Escaner de red con SCAPY.

Vamos a empezar con la construcción del código de nuestro escaner local. Para ello vamos a utilizar una función escanear_red(), en donde, como parámetros pondremos el rango de red local que queremos escanear. Copia el código y pégalo en un proyecto nuevo en tu editor favorito. Yo utilizaré Visual Studio Code.

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Escáner de Red ARP Este script utiliza Scapy para descubrir dispositivos en una red local mediante peticiones ARP. """ # Importación de librerías necesarias from scapy.all import ARP, Ether, srp def escanear_red(ip_rango): """ Escanea la red local en busca de dispositivos activos. Args: ip_rango (str): Rango de IP a escanear (ej: "192.168.1.0/24") Returns: list: Lista de diccionarios con 'ip' y 'mac' de dispositivos encontrados """ # 1. Crear la petición ARP para consultar quién tiene las IPs del rango solicitud_arp = ARP(pdst=ip_rango) # 2. Crear la trama Ethernet de difusión (Broadcast) trama_ether = Ether(dst="ff:ff:ff:ff:ff:ff") # 3. Combinar trama Ethernet y paquete ARP paquete_completo = trama_ether / solicitud_arp # 4. Enviar paquete en Capa 2 y recibir respuestas (timeout de 2 segundos) respuestas, _ = srp(paquete_completo, timeout=2, verbose=False) # 5. Procesar y estructurar los resultados dispositivos_detectados = [] for enviado, recibido in respuestas: dispositivos_detectados.append({ "ip": recibido.psrc, "mac": recibido.hwsrc }) return dispositivos_detectados # Ejemplo de uso if __name__ == "__main__": # Configurar el rango de IP según tu red mi_red = "192.168.1.0/24" print(f"Escaneando red: {mi_red}") print("Espera un momento...\n") # Ejecutar el escaneo dispositivos = escanear_red(mi_red) # Mostrar resultados if dispositivos: print("Dispositivos encontrados:") for i, dispositivo in enumerate(dispositivos, 1): print(f"{i}. IP: {dispositivo['ip']} - MAC: {dispositivo['mac']}") else: print("No se encontraron dispositivos.") Python
Modulo de librería scapy

Pip list te muestra las librerías descargadas en tu máquina.

Recuerda que si no tienes el módulo de scapy deberás descargarlo con pip:

pip install scapy
Modulo de librería scapy descargado

Pip install scapy te descarga la librería.

NOTA: También necesitarás descargarte el programa npcap. Scapy necesita npcap para poder trabajar en la capa 2 en Windows. Es un driver de captura de paquetes, así que visita la página oficial de NPCAP para descargarlo. Durante el proceso de instalación en Windows, te recomiendo marcar las siguientes casillas:

[x] Install Npcap in WinPcap API-compatible Mode (OBLIGATORIO).
(Opcional pero recomendado): [x] Support raw 802.11 traffic (and monitor mode) for wireless adapters.

Luego finaliza el proceso de instalación de forma habitual.

Instalación del programa npcap para trabajar en capa 2

Instalación de npcap para trabajar en capa2.

La instalación no requiere que reinicies el PC, pero sí es necesario que ejecutes tu script de Python como administrador. Si quieres verificar que scapy detecta npcap correctamente, ejecuta esta instrucción en tu consola de comandos:

python -c "from scapy.all import conf; print(conf.use_pcap)" Console

Si te devuelve True, significa que scapy detecta npcap y está listo para usarse.

Explicación del código anterior.
Empezando por la importación de librerías:

# Importación de librerías necesarias from scapy.all import ARP, Ether, srp Python

● ARP: Clase para construir la Petición/Respuesta de resolución de direcciones IP a MAC (Capa 3 a Capa 2).
● Ether: Clase para forjar la trama Ethernet de Capa 2 del modelo OSI.
● srp: Nombre que viene de Send and Receive Packets at Layer 2 (Enviar y Recibir paquetes en Capa 2). Es la función clave que nos permite enviar la trama a nivel de enlace y escuchar las respuestas.

A continuación creamos la instancia para generar el paquete ARP:

# 1. Crear la petición ARP para consultar quién tiene las IPs del rango solicitud_arp = ARP(pdst=ip_rango) Python

Siendo:

pdst (Protocol Destination)

Establece la IP o el rango de red objetivo (por ejemplo, 192.168.1.0/24). ARP enviará la consulta al rango para resolver las direcciones físicas presentes.

El siguiente punto encapsula la consulta ARP sobre la trama Ethernet. Ten en cuenta que ARP relaciona direcciones IP con direcciones MAC físicas dentro de la arquitectura de la red local:

# 2. Crear la trama Ethernet de difusión (Broadcast) trama_ether = Ether(dst="ff:ff:ff:ff:ff:ff") '''dst="ff:ff:ff:ff:ff:ff": Es la dirección MAC de difusión o broadcast. Indica a los switches y puntos de acceso que deben entregar este paquete a todos los dispositivos de la red local.''' # 3. Combinar trama Ethernet y paquete ARP paquete_completo = trama_ether / solicitud_arp '''En Scapy, el operador / sirve para apilar capas de red. Aquí metemos la Petición ARP dentro de la trama Ethernet (Capa 2).''' # 4. Enviar paquete en Capa 2 y recibir respuestas (timeout de 2 segundos) respuestas, _ = srp(paquete_completo, timeout=2, verbose=False) Python

Para el envío y recepción del tráfico, los parámetros significan:

● srp(...): Envía el paquete por la tarjeta de red y escucha respuestas en Capa 2.
● timeout=2: Establece un tiempo de espera de 2 segundos para recolectar respuestas.
● verbose=False: Oculta la salida por defecto de Scapy en la terminal.
● respuestas, _: `srp` devuelve dos listas: paquetes respondidos y no respondidos. Ignoramos los no respondidos (`_`) y procesamos los recibidos.

Por último, procesamos los datos mediante el bucle `for`:

for enviado, recibido in respuestas: dispositivos_detectados.append({ "ip": recibido.psrc, "mac": recibido.hwsrc }) return dispositivos_detectados Python

● recibido.psrc (Protocol Source): Es la dirección IP del equipo que respondió.
● recibido.hwsrc (Hardware Source): Es la dirección MAC física de la interfaz del dispositivo detectado.

Ya estamos listos para realizar pruebas con el script que hemos generado.

Pruebas y testing.

Ejecutamos el script con privilegios de administrador para permitir a la tarjeta de red forjar tramas en Capa 2. Obtendremos el listado de dispositivos activos:

Prueba de escaner scapy

El script te devuelve los dispositivos que están conectados a tu red.

Como ves en la captura, el script nos indica los dispositivos detectados en la subred. Abrimos la consola de comandos e inspeccionamos nuestro direccionamiento local:

Conexión de mi dispositivo de red e IP local

Ipconfig me devuelve mis dispositivos de red y mis IP.

En este ejemplo, la máquina local tiene la IP 192.168.1.17 y el router (puerta de enlace) es la 192.168.1.1. Sin embargo, al escanear dispositivos móviles (como smartphones), es común que algunos no aparezcan a la primera en la consulta ARP Broadcast, ¿por qué ocurre esto?

Los sistemas operativos móviles (Android/iOS) implementan políticas de ahorro de energía y filtrado de tramas broadcast cuando la pantalla está apagada. Para reducir el consumo de la antena Wi-Fi, descartan peticiones de difusión general a menos que se fuerce una comunicación directa previa (por ejemplo, enviando un paquete unicast ICMP/Ping directo a su IP).

Modificaremos el script anterior para que detecte el móvil cuando está activo y navegando por nuestra red.

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Escáner de Red ARP e ICMP Este script utiliza Scapy para descubrir dispositivos en una red local mediante un pre-ping ICMP (para despertar dispositivos móviles) y peticiones ARP. """ # Importación de librerías necesarias import ipaddress import platform import subprocess from concurrent.futures import ThreadPoolExecutor from scapy.all import ARP, Ether, srp def _hacer_ping(ip_str): """Lanza un ping rápido e inaudito a una IP concreta.""" param = "-n 1 -w 200" if platform.system().lower() == "windows" else "-c 1 -W 1" subprocess.run( f"ping {param} {ip_str}", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) def despertar_red(ip_rango): """ Realiza un barrido Ping ICMP multi-hilo en el rango indicado para forzar la actualización de las tablas ARP de los dispositivos (móviles). """ try: red = ipaddress.ip_network(ip_rango, strict=False) # Limitamos el pre-ping a subredes /24 para no saturar memoria/hilos ips = [str(ip) for ip in red.hosts()] if red.prefixlen >= 24 else [] except ValueError: return # Usamos hilos en paralelo para hacer el barrido en < 1 segundo with ThreadPoolExecutor(max_workers=50) as executor: executor.map(_hacer_ping, ips) def escanear_red(ip_rango): """ Escanea la red local en busca de dispositivos activos. Args: ip_rango (str): Rango de IP a escanear (ej: "192.168.1.0/24") Returns: list: Lista de diccionarios con 'ip' y 'mac' de dispositivos encontrados """ # 1. 'Despertar' a los dispositivos móviles mediante ICMP en paralelo despertar_red(ip_rango) # 2. Crear la petición ARP para consultar quién tiene las IPs del rango solicitud_arp = ARP(pdst=ip_rango) # 3. Crear la trama Ethernet de difusión (Broadcast) trama_ether = Ether(dst="ff:ff:ff:ff:ff:ff") # 4. Combinar trama Ethernet y paquete ARP paquete_completo = trama_ether / solicitud_arp # 5. Enviar paquete en Capa 2 y recibir respuestas (timeout de 2 segundos) respuestas, _ = srp(paquete_completo, timeout=2, verbose=False) # 6. Procesar y estructurar los resultados dispositivos_detectados = [] for enviado, recibido in respuestas: dispositivos_detectados.append( {"ip": recibido.psrc, "mac": recibido.hwsrc} ) return dispositivos_detectados # Ejemplo de uso if __name__ == "__main__": # Configurar el rango de IP según tu red mi_red = "192.168.1.0/24" print(f"Escaneando red: {mi_red}") print("Espera un momento...\n") # Ejecutar el escaneo dispositivos = escanear_red(mi_red) # Mostrar resultados if dispositivos: print("Dispositivos encontrados:") for i, dispositivo in enumerate(dispositivos, 1): print( f"{i}. IP: {dispositivo['ip']} - MAC: {dispositivo['mac']}" ) else: print("No se encontraron dispositivos.") Python

Si interactúas con el dispositivo móvil o realizas un refresco previo a su IP, el sistema operativo responderá actualizando la tabla ARP local y aparecerá reflejado en el escaneo.

Dispositivos encontrados con el script

El script te devuelve los dispositivos que están conectados a tu red.

RESUMEN.

En esta práctica hemos construido una herramienta en Python para auditar la red local mediante peticiones ARP de Capa 2. Hemos utilizado la librería Scapy para interactuar directamente con la capa de enlace del modelo OSI y asociar direcciones IP con direcciones MAC físicas. También analizamos el comportamiento de los dispositivos móviles frente a las tramas de difusión (*broadcast*) y la importancia del manejo de caché ARP.

Comparte este conocimiento en redes sociales