CS! : Aprenda a escribir un escáner de puertos en Python usando sockets, comenzando con un escáner de puertos simple y luego profundizando en una versión enhebrada de un escáner de puertos que sea confiable para su uso.
El escaneo de puertos es un método de escaneo para determinar qué puertos en un dispositivo de red están abiertos, ya sea un servidor, un enrutador o una máquina normal. Un escáner de puertos es solo un script o un programa diseñado para probar un host en busca de puertos abiertos.
En este tutorial, podrá crear su propio escáner de puertos en Python utilizando la biblioteca de sockets . La idea básica detrás de este simple escáner de puertos es intentar conectarse a un host específico (sitio web, servidor o cualquier dispositivo conectado a Internet / red) a través de una lista de puertos, si se ha establecido una conexión exitosa, eso significa que el puerto está abierto .
Por ejemplo, cuando cargó esta página web, hizo una conexión a este sitio web en el puerto 80 , de manera similar, este script intentará conectarse a un host pero en varios puertos. Este tipo de herramientas son útiles para piratas informáticos y probadores de penetración, así que no use esta herramienta para un host que no tenga permiso para probar.
Opcionalmente, debe instalar el módulo colorama para una impresión elegante:
pip3 install colorama
Escáner de puerto simple
En esta sección, escribiremos un escáner de puerto simple, solo para ensuciarse las manos, comencemos importando el módulo de socket :
import socket # for connecting
from colorama import init, Fore
# some colors
init()
GREEN = Fore.GREEN
RESET = Fore.RESET
GRAY = Fore.LIGHTBLACK_EX
Nota: el módulo de socket ya está instalado en su máquina, está integrado en el módulo de la biblioteca estándar de Python , por lo que no tiene que instalar nada.
El módulo de socket nos proporciona operaciones de socket, funciones para tareas relacionadas con la red, etc. Son muy utilizados en Internet, ya que están detrás de cualquier conexión a cualquier red. Cualquier comunicación de red pasa por un socket, más detalles en la documentación oficial de Python .
Usaremos colorama aquí solo para imprimir en colores verdes cuando un puerto está abierto y gris cuando está cerrado.
Definamos la función que se encarga de determinar si un puerto está abierto:
def is_port_open(host, port):
"""
determine whether `host` has the `port` open
"""
# creates a new socket
s = socket.socket()
try:
# tries to connect to host using that port
s.connect((host, port))
# make timeout if you want it a little faster ( less accuracy )
# s.settimeout(0.2)
except:
# cannot connect, port is closed
# return false
return False
else:
# the connection was established, port is open!
return True
s.connect((host, port))La función intenta conectar el socket a una dirección remota (host,port), generará una excepción cuando no se conecte a ese host, es por eso que hemos envuelto esa línea de código en un bloque try-except , por lo que siempre que se genera una excepción, eso es una indicación para nosotros de que el puerto está realmente cerrado; de lo contrario, está abierto.
Ahora usemos la función anterior e iteremos sobre un rango de puertos:
# get the host from the user
host = input("Enter the host:")
# iterate over ports, from 1 to 1024
for port in range(1, 1025):
if is_port_open(host, port):
print(f"{GREEN}[+] {host}:{port} is open {RESET}")
else:
print(f"{GRAY}[!] {host}:{port} is closed {RESET}", end="\r")
El código anterior escaneará puertos que van desde 1 hasta 1024, puede cambiar el rango a 65535 si lo desea, pero tardará más en finalizar.
Cuando intente ejecutarlo, inmediatamente notará que el script es bastante lento, bueno, podemos salirse con la suya si establecemos un tiempo de espera de 200 milisegundos más o menos (usando el settimeout(0.2)método). Sin embargo, esto en realidad puede reducir la precisión del reconocimiento, especialmente cuando su latencia es bastante alta. Como resultado, necesitamos una mejor manera de acelerar esto.
Escáner de puerto rápido
Ahora llevemos nuestro simple escáner de puertos a un nivel superior. En esta sección, escribiremos un escáner de puertos con subprocesos que puede escanear 200 o más puertos simultáneamente.
El siguiente código es en realidad la misma función que vimos anteriormente, que es responsable de escanear un solo puerto. Como estamos usando subprocesos , necesitamos usar un candado para que solo se pueda imprimir un subproceso a la vez; de lo contrario, la salida se estropeará y no leeremos nada:
import argparse
import socket # for connecting
from colorama import init, Fore
from threading import Thread, Lock
from queue import Queue
# some colors
init()
GREEN = Fore.GREEN
RESET = Fore.RESET
GRAY = Fore.LIGHTBLACK_EX
# number of threads, feel free to tune this parameter as you wish
N_THREADS = 200
# thread queue
q = Queue()
print_lock = Lock()
def port_scan(port):
"""
Scan a port on the global variable `host`
"""
try:
s = socket.socket()
s.connect((host, port))
except:
with print_lock:
print(f"{GRAY}{host:15}:{port:5} is closed {RESET}", end='\r')
else:
with print_lock:
print(f"{GREEN}{host:15}:{port:5} is open {RESET}")
finally:
s.close()
Entonces, esta vez la función no devuelve nada, solo queremos imprimir si el puerto está abierto (aunque siéntase libre de cambiarlo).
Usamos la Queue()clase del módulo de cola incorporado que nos ayudará a consumir puertos, las dos funciones siguientes son para producir y llenar la cola con números de puerto y usar subprocesos para consumirlos:
def scan_thread():
global q
while True:
# get the port number from the queue
worker = q.get()
# scan that port number
port_scan(worker)
# tells the queue that the scanning for that port
# is done
q.task_done()
def main(host, ports):
global q
for t in range(N_THREADS):
# for each thread, start it
t = Thread(target=scan_thread)
# when we set daemon to true, that thread will end when the main thread ends
t.daemon = True
# start the daemon thread
t.start()
for worker in ports:
# for each port, put that port into the queue
# to start scanning
q.put(worker)
# wait the threads ( port scanners ) to finish
q.join()
El trabajo de la scan_thread()función es obtener números de puerto de la cola y escanearlo, y luego agregarlo a las tareas realizadas, mientras que la main()función es responsable de llenar la cola con los números de puerto y generar N_THREADSsubprocesos para consumirlos.
Tenga en cuenta que q.get()se bloqueará hasta que haya un solo elemento disponible en la cola. q.put()pone un solo elemento en la cola y q.join()espera a que terminen todos los hilos (despejar la cola).
Finalmente, hagamos un analizador de argumentos simple para que podamos pasar el rango de números de puerto y host desde la línea de comando:
if __name__ == "__main__":
# parse some parameters passed
parser = argparse.ArgumentParser(description="Simple port scanner")
parser.add_argument("host", help="Host to scan.")
parser.add_argument("--ports", "-p", dest="port_range", default="1-65535", help="Port range to scan, default is 1-65535 (all ports)")
args = parser.parse_args()
host, port_range = args.host, args.port_range
start_port, end_port = port_range.split("-")
start_port, end_port = int(start_port), int(end_port)
ports = [ p for p in range(start_port, end_port)]
main(host, ports)
Aquí hay una captura de pantalla cuando intenté escanear mi enrutador:
Conclusión
¡Increíble! ¡Terminó de escanear 5000 puertos en menos de 2 segundos! Puede utilizar el rango predeterminado ( 1 a 65535 ) y tardará unos segundos en finalizar.
Si ve que su escáner se está congelando en un solo puerto, eso es una señal de que necesita disminuir su número de subprocesos, si el servidor que está probando tiene un ping alto, debe reducirlo N_THREADS a 100 , 50 o incluso menos, intente Experimente con este parámetro.
El escaneo de puertos demuestra ser útil en muchos casos, un probador de penetración autorizado puede usar esta herramienta para ver qué puertos están abiertos y revelar la presencia de dispositivos de seguridad potenciales como firewalls, así como probar la seguridad de la red y la fuerza de un dispositivo.
También es una herramienta de reconocimiento popular para los piratas informáticos que buscan puntos débiles para obtener acceso a la máquina objetivo.
Consulte la versión completa de ambos scripts aquí .
🔥AlfonzCS Feliz Escaneo🔥