Escáner de red Python

El escaneo de puertos puede definirse como una técnica de vigilancia, que se utiliza para localizar los puertos abiertos disponibles en un host en particular. El administrador de red, el probador de penetración o un hacker pueden utilizar esta técnica. Podemos configurar el escáner de puertos de acuerdo con nuestros requisitos para obtener la máxima información del sistema de destino.

Ahora, considere la información que podemos obtener después de ejecutar el escaneo de puertos:

  • Información sobre puertos abiertos.

  • Información sobre los servicios que se ejecutan en cada puerto.

  • Información sobre el sistema operativo y la dirección MAC del host de destino.

El escaneo de puertos es como un ladrón que quiere entrar a una casa revisando cada puerta y ventana para ver cuáles están abiertas. Como se mencionó anteriormente, el conjunto de protocolos TCP / IP, que se utiliza para la comunicación a través de Internet, se compone de dos protocolos, a saber, TCP y UDP. Ambos protocolos tienen puertos de 0 a 65535. Como siempre es recomendable cerrar puertos innecesarios de nuestro sistema, por lo tanto, esencialmente, hay más de 65000 puertas (puertos) para bloquear. Estos puertos 65535 se pueden dividir en los siguientes tres rangos:

  • Puertos del sistema o conocidos: de 0 a 1023

  • Puertos de usuario o registrados: de 1024 a 49151

  • Puertos dinámicos o privados: todos> 49151

Escáner de puertos mediante socket

En nuestro capítulo anterior, discutimos qué es un socket. Ahora, construiremos un escáner de puertos simple usando socket. A continuación se muestra una secuencia de comandos de Python para el escáner de puertos que usa socket:

from socket import *
import time
startTime = time.time()

if __name__ == '__main__':
   target = input('Enter the host to be scanned: ')
   t_IP = gethostbyname(target)
   print ('Starting scan on host: ', t_IP)
   
   for i in range(50, 500):
      s = socket(AF_INET, SOCK_STREAM)
      
      conn = s.connect_ex((t_IP, i))
      if(conn == 0) :
         print ('Port %d: OPEN' % (i,))
      s.close()
print('Time taken:', time.time() - startTime)

Cuando ejecutamos el script anterior, le pedirá el nombre de host, puede proporcionar cualquier nombre de host, como el nombre de cualquier sitio web, pero tenga cuidado porque el escaneo de puertos puede verse o interpretarse como un delito. Nunca debemos ejecutar un escáner de puertos en ningún sitio web o dirección IP sin el permiso explícito y por escrito del propietario del servidor o computadora a la que se dirige. El escaneo de puertos es similar a ir a la casa de alguien y revisar sus puertas y ventanas. Por eso es recomendable utilizar un escáner de puertos en localhost o en su propio sitio web (si lo hubiera).

Salida

El script anterior genera la siguiente salida:

Enter the host to be scanned: localhost
Starting scan on host: 127.0.0.1
Port 135: OPEN
Port 445: OPEN
Time taken: 452.3990001678467

El resultado muestra que en el rango de 50 a 500 (como se proporciona en el script), este escáner de puertos encontró dos puertos: el puerto 135 y el 445, abiertos. Podemos cambiar este rango y podemos buscar otros puertos.

Port Scanner usando ICMP (hosts en vivo en una red)

ICMP no es un escaneo de puertos, pero se usa para hacer ping al host remoto para verificar si el host está activo. Este escaneo es útil cuando tenemos que verificar varios hosts en vivo en una red. Implica enviar una solicitud ICMP ECHO a un host y, si ese host está activo, devolverá una respuesta ICMP ECHO.

El proceso anterior de envío de solicitudes ICMP también se denomina escaneo de ping, que se proporciona mediante el comando ping del sistema operativo.

Concepto de barrido de ping

En realidad, en uno u otro sentido, el barrido de ping también se conoce como barrido de ping. La única diferencia es que el barrido de ping es el procedimiento para encontrar la disponibilidad de más de una máquina en un rango de red específico. Por ejemplo, supongamos que queremos probar una lista completa de direcciones IP y luego, utilizando el escaneo ping, es decir, el comando ping del sistema operativo, sería muy lento escanear las direcciones IP una por una. Es por eso que necesitamos usar un script de barrido de ping. A continuación se muestra un script de Python para encontrar hosts en vivo mediante el barrido de ping:

import os
import platform

from datetime import datetime
net = input("Enter the Network Address: ")
net1= net.split('.')
a = '.'

net2 = net1[0] + a + net1[1] + a + net1[2] + a
st1 = int(input("Enter the Starting Number: "))
en1 = int(input("Enter the Last Number: "))
en1 = en1 + 1
oper = platform.system()

if (oper == "Windows"):
   ping1 = "ping -n 1 "
elif (oper == "Linux"):
   ping1 = "ping -c 1 "
else :
   ping1 = "ping -c 1 "
t1 = datetime.now()
print ("Scanning in Progress:")

for ip in range(st1,en1):
   addr = net2 + str(ip)
   comm = ping1 + addr
   response = os.popen(comm)
   
   for line in response.readlines():
      if(line.count("TTL")):
         break
      if (line.count("TTL")):
         print (addr, "--> Live")
         
t2 = datetime.now()
total = t2 - t1
print ("Scanning completed in: ",total)

El script anterior funciona en tres partes. Primero selecciona el rango de direcciones IP para hacer ping al escaneo de barrido dividiéndolo en partes. A esto le sigue el uso de la función, que seleccionará el comando para el barrido de ping de acuerdo con el sistema operativo y, por último, dará la respuesta sobre el host y el tiempo necesario para completar el proceso de análisis.

Salida

El script anterior genera la siguiente salida:

Enter the Network Address: 127.0.0.1
Enter the Starting Number: 1
Enter the Last Number: 100

Scanning in Progress:
Scanning completed in: 0:00:02.711155

La salida anterior no muestra puertos en vivo porque el firewall está activado y la configuración de entrada ICMP también está deshabilitada. Después de cambiar esta configuración, podemos obtener la lista de puertos en vivo en el rango de 1 a 100 proporcionada en la salida.

Escáner de puertos mediante escaneo TCP

Para establecer una conexión TCP, el host debe realizar un protocolo de enlace de tres vías. Siga estos pasos para realizar la acción:

Step 1 − Packet with SYN flag set

En este paso, el sistema que está intentando iniciar una conexión comienza con un paquete que tiene el indicador SYN configurado.

Step 2 − Packet with SYN-ACK flag set

En este paso, el sistema de destino devuelve un paquete con conjuntos de indicadores SYN y ACK.

Step 3 − Packet with ACK flag set

Por fin, el sistema de inicio devolverá un paquete al sistema de destino original con la bandera ACK activada.

Sin embargo, la pregunta que surge aquí es si podemos hacer un escaneo de puertos usando el método de solicitud y respuesta de eco ICMP (escáner de barrido de ping), entonces ¿por qué necesitamos el escaneo TCP? La razón principal detrás de esto es que supongamos que si desactivamos la función de respuesta ICMP ECHO o usamos un firewall para paquetes ICMP, el escáner de barrido de ping no funcionará y necesitamos un escaneo TCP.

import socket
from datetime import datetime
net = input("Enter the IP address: ")
net1 = net.split('.')
a = '.'

net2 = net1[0] + a + net1[1] + a + net1[2] + a
st1 = int(input("Enter the Starting Number: "))
en1 = int(input("Enter the Last Number: "))
en1 = en1 + 1
t1 = datetime.now()

def scan(addr):
   s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   socket.setdefaulttimeout(1)
   result = s.connect_ex((addr,135))
   if result == 0:
      return 1
   else :
      return 0

def run1():
   for ip in range(st1,en1):
      addr = net2 + str(ip)
      if (scan(addr)):
         print (addr , "is live")
         
run1()
t2 = datetime.now()
total = t2 - t1
print ("Scanning completed in: " , total)

El script anterior funciona en tres partes. Selecciona el rango de direcciones IP para hacer ping al escaneo de barrido dividiéndolo en partes. A esto le sigue el uso de una función para escanear la dirección, que además usa el socket. Más tarde, da la respuesta sobre el host y el tiempo necesario para completar el proceso de escaneo. El resultado = s. La sentencia connect_ex ((addr, 135)) devuelve un indicador de error. El indicador de error es 0 si la operación se realiza correctamente; de ​​lo contrario, es el valor de la variable errno. Aquí, usamos el puerto 135; este escáner funciona para el sistema Windows. Otro puerto que funcionará aquí es 445 (Microsoft-DSActive Directory) y generalmente está abierto.

Salida

El script anterior genera la siguiente salida:

Enter the IP address: 127.0.0.1
Enter the Starting Number: 1
Enter the Last Number: 10

127.0.0.1 is live
127.0.0.2 is live
127.0.0.3 is live
127.0.0.4 is live
127.0.0.5 is live
127.0.0.6 is live
127.0.0.7 is live
127.0.0.8 is live
127.0.0.9 is live
127.0.0.10 is live
Scanning completed in: 0:00:00.230025

Escáner de puertos roscados para aumentar la eficiencia

Como hemos visto en los casos anteriores, el escaneo de puertos puede ser muy lento. Por ejemplo, puede ver que el tiempo necesario para escanear puertos de 50 a 500, mientras usa el escáner de puertos de socket, es 452.3990001678467. Para mejorar la velocidad podemos utilizar el enhebrado. A continuación se muestra un ejemplo de un escáner de puertos que usa subprocesos:

import socket
import time
import threading

from queue import Queue
socket.setdefaulttimeout(0.25)
print_lock = threading.Lock()

target = input('Enter the host to be scanned: ')
t_IP = socket.gethostbyname(target)
print ('Starting scan on host: ', t_IP)

def portscan(port):
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   try:
      con = s.connect((t_IP, port))
      with print_lock:
         print(port, 'is open')
      con.close()
   except:
      pass

def threader():
   while True:
      worker = q.get()
      portscan(worker)
      q.task_done()
      
q = Queue()
   startTime = time.time()
   
for x in range(100):
   t = threading.Thread(target = threader)
   t.daemon = True
   t.start()
   
for worker in range(1, 500):
   q.put(worker)
   
q.join()
print('Time taken:', time.time() - startTime)

En el script anterior, necesitamos importar el módulo de subprocesos, que está incorporado en el paquete Python. Estamos utilizando el concepto de bloqueo de roscas,thread_lock = threading.Lock()para evitar múltiples modificaciones a la vez. Básicamente, threading.Lock () permitirá que un solo hilo acceda a la variable a la vez. Por tanto, no se produce una doble modificación.

Más tarde, definimos una función de subprocesamiento () que buscará el trabajo (puerto) del trabajador para el bucle. Luego, se llama al método portscan () para conectarse al puerto e imprimir el resultado. El número de puerto se pasa como parámetro. Una vez que se completa la tarea, se llama al método q.task_done ().

Ahora, después de ejecutar el script anterior, podemos ver la diferencia de velocidad para escanear de 50 a 500 puertos. Solo tomó 1.3589999675750732 segundos, que es muy inferior a 452.3990001678467, tiempo que toma el escáner de puerto de socket para escanear la misma cantidad de puertos de localhost.

Salida

El script anterior genera la siguiente salida:

Enter the host to be scanned: localhost
Starting scan on host: 127.0.0.1
135 is open
445 is open
Time taken: 1.3589999675750732