Construire un scanner de ports avec Python

PythonPythonBeginner
Pratiquer maintenant

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce projet, nous allons développer un scanner de ports serveur en utilisant Python pour détecter les ports ouverts sur un serveur cible. Cet outil est crucial pour les administrateurs de systèmes, qui l'utilisent pour vérifier les politiques de sécurité, et pour les potentiels attaquants, qui l'utilisent pour identifier les services de réseau fonctionnels sur un hôte. Notre parcours couvrira les aspects essentiels du balayage de ports, y compris sa méthodologie et ses implications. Nous plongerons dans la création d'un scanner de ports simple mais efficace en exploitant les capacités de Python, en mettant l'accent sur une approche multithreadée pour améliorer l'efficacité et les performances.

Le balayage de ports est le processus consistant à envoyer des requêtes à une plage de ports de serveur pour déterminer lesquels sont ouverts. Cette étape est cruciale pour maintenir la sécurité et pour que les attaquants trouvent des services vulnérables. Nous commencerons par explorer les bases du balayage de ports et ses implications.

Concepts clés :

  • Les scanners de ports aident à détecter les ports ouverts sur un serveur ou un hôte.
  • Ils sont utilisés pour les évaluations de sécurité et par les attaquants pour identifier les services vulnérables.
  • La forme la plus simple de balayage de ports consiste à tenter des connexions TCP à une plage de ports.

👀 Aperçu

Voici un avant-goût de l'outil de balayage de ports que nous allons construire :

python port_scanner.py 127.0.0.1 5000-9000

Sortie :

Port ouvert : 8081
Balayage terminé.

🎯 Tâches

Dans ce projet, vous allez apprendre :

  • Comment utiliser les capacités de programmation socket de Python pour interagir avec les ports réseau.
  • Comment implémenter une approche multithreadée en Python pour améliorer l'efficacité des tâches de balayage de réseau.
  • Comment développer un outil de ligne de commande en Python qui prend des entrées utilisateur pour un balayage de ports flexible.

🏆 Réalisations

Après avoir terminé ce projet, vous serez capable de :

  • Utiliser la bibliothèque socket de Python pour créer des connexions réseau, tester la disponibilité des ports et gérer les exceptions réseau.
  • Comprendre et appliquer le multithreading en Python pour effectuer des tâches simultanées, améliorant considérablement les performances des opérations intensives sur le réseau.
  • Construire un outil pratique de balayage de ports de ligne de commande, améliorant vos compétences en script Python et votre compréhension de l'analyse d'arguments de ligne de commande.

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python(("Python")) -.-> python/NetworkingGroup(["Networking"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ModulesandPackagesGroup(["Modules and Packages"]) python(("Python")) -.-> python/FileHandlingGroup(["File Handling"]) python/FunctionsGroup -.-> python/function_definition("Function Definition") python/FunctionsGroup -.-> python/arguments_return("Arguments and Return Values") python/FunctionsGroup -.-> python/build_in_functions("Build-in Functions") python/ModulesandPackagesGroup -.-> python/standard_libraries("Common Standard Libraries") python/FileHandlingGroup -.-> python/with_statement("Using with Statement") python/AdvancedTopicsGroup -.-> python/threading_multiprocessing("Multithreading and Multiprocessing") python/NetworkingGroup -.-> python/socket_programming("Socket Programming") subgraph Lab Skills python/function_definition -.-> lab-415965{{"Construire un scanner de ports avec Python"}} python/arguments_return -.-> lab-415965{{"Construire un scanner de ports avec Python"}} python/build_in_functions -.-> lab-415965{{"Construire un scanner de ports avec Python"}} python/standard_libraries -.-> lab-415965{{"Construire un scanner de ports avec Python"}} python/with_statement -.-> lab-415965{{"Construire un scanner de ports avec Python"}} python/threading_multiprocessing -.-> lab-415965{{"Construire un scanner de ports avec Python"}} python/socket_programming -.-> lab-415965{{"Construire un scanner de ports avec Python"}} end

Établissement de tests de connexion TCP

Notre première étape consiste à écrire une fonction pour tester si un port TCP est ouvert sur l'IP cible. Cette fonction tentera de se connecter à un port spécifié et déterminera son statut.

Ouvrez le fichier nommé port_scanner.py dans le répertoire /home/labex/project et ajoutez la fonction Python suivante :

import argparse
from queue import Queue
from socket import AF_INET, gethostbyname, socket, SOCK_STREAM
import threading

def tcp_test(port: int, target_ip: str) -> None:
    with socket(AF_INET, SOCK_STREAM) as sock:
        sock.settimeout(1)
        result = sock.connect_ex((target_ip, port))
        if result == 0:
            print(f"Port ouvert : {port}")

Ce code définit une fonction, tcp_test, qui essaie d'établir une connexion TCP à un port spécifié sur l'adresse IP cible. Il définit un délai d'attente pour éviter les longs attentes sur chaque port et utilise connect_ex pour tenter la connexion.

Si connect_ex renvoie 0, cela indique que la connexion a réussi, ce qui signifie que le port est ouvert, et la fonction affiche un message indiquant le port ouvert.

✨ Vérifier la solution et pratiquer

Configuration des vérifications concurrentes de ports

Ensuite, nous allons créer une fonction worker qui sera utilisée par chaque thread pour traiter les ports provenant d'une file d'attente et utiliser la fonction tcp_test pour vérifier le statut de chaque port.

Ajoutez le code suivant à votre port_scanner.py :

def worker(target_ip: str, queue: Queue) -> None:
    while not queue.empty():
        port = queue.get()
        tcp_test(port, target_ip)
        queue.task_done()

La fonction worker est conçue pour être exécutée par plusieurs threads. Elle récupère continuellement des numéros de port d'une file d'attente et utilise la fonction tcp_test précédemment définie pour vérifier si ces ports sont ouverts sur l'IP cible.

Après avoir testé un port, elle marque la tâche comme terminée dans la file d'attente. Cette fonction permet un balayage concurrent de ports, accélérant considérablement le processus.

✨ Vérifier la solution et pratiquer

Orchestration du processus de balayage

La fonction main orchestrera le processus de balayage en configurant la file d'attente, en initialisant les threads de travail et en gérant l'opération de balayage sur la plage de ports spécifiée.

Continuez en ajoutant la fonction main à votre port_scanner.py :

def main(host: str, start_port: int, end_port: int) -> None:
    target_ip = gethostbyname(host)
    queue = Queue()
    for port in range(start_port, end_port + 1):
        queue.put(port)
    for _ in range(100):  ## Ajustez le nombre de threads si nécessaire
        t = threading.Thread(target=worker, args=(target_ip, queue,))
        t.daemon = True
        t.start()
    queue.join()
    print("Balayage terminé.")

La fonction main orchestrera l'ensemble du processus de balayage de ports.

Elle résout d'abord le nom d'hôte cible en une adresse IP, puis crée une file d'attente pour les numéros de ports à balayer. Elle remplit la file d'attente avec tous les ports de la plage spécifiée et lance plusieurs threads de travail (100 dans cet exemple) qui traitent la file d'attente de manière concurrente en vérifiant chaque port. La fonction attend que tous les ports aient été traités (queue.join()) puis affiche un message indiquant que le balayage est terminé.

✨ Vérifier la solution et pratiquer

Exécution du scanner de ports

Enfin, il est temps d'exécuter notre scanner de ports. Nous allons balayer une plage de ports sur l'ordinateur local pour tester notre outil.

Ajoutez les lignes suivantes à la fin de votre port_scanner.py pour rendre le script exécutable :

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Scanner de ports TCP')
    parser.add_argument('host', help='Hôte à balayer')
    parser.add_argument('ports', help='Plage de ports à balayer, au format début-fin')
    args = parser.parse_args()

    start_port, end_port = map(int, args.ports.split('-'))
    main(args.host, start_port, end_port)

Ce code utilise l'analyse d'arguments de ligne de commande pour le script de scanner de ports, le rendant plus polyvalent et convivial pour l'utilisateur.

En utilisant la bibliothèque argparse, il définit deux arguments requis : host et ports.

  • L'argument host est utilisé pour spécifier l'adresse ou le nom d'hôte de l'hôte cible que vous souhaitez balayer.
  • L'argument ports attend une chaîne de caractères qui définit la plage de ports à balayer, au format "début-fin" (par exemple, "5000-8000"), que le script divise en start_port et end_port en utilisant le délimiteur - puis les convertit en entiers. Cela permet aux utilisateurs de spécifier facilement la cible et la plage de ports lorsqu'ils exécutent le script à partir de la ligne de commande.

Maintenant, exécutez le scanner en exécutant la commande suivante dans le terminal :

python port_scanner.py 127.0.0.1 5000-9000

Sortie :

Port ouvert : 8081
Balayage terminé.

Maintenant que vous avez identifié un port ouvert (8081) à l'aide du scanner de ports et qu'un serveur web est en cours d'exécution dessus, vous pouvez explorer ce qui est hébergé là.

Pour ce faire, cliquez d'abord sur le bouton d'ajout et sélectionnez l'option "Service web".

Sélectionner l'option Service web

Ensuite, entrez le port 8081 et cliquez sur le bouton "Accéder".

Entrer le port et accéder au serveur web

Vous trouverez le serveur web en cours d'exécution dans votre système, en écoute sur le port 8081.

Serveur web en cours d'exécution sur le port 8081
✨ Vérifier la solution et pratiquer

Sommaire

Dans ce projet, nous avons construit un scanner de ports de base avec Python, en commençant par la fonction fondamentale tcp_test jusqu'à une approche de balayage multi-thread. Nous avons divisé le processus en étapes gérées, aboutissant à un outil fonctionnel capable d'identifier les ports ouverts sur un serveur cible. Grâce à cette expérience pratique, nous avons non seulement approfondi notre compréhension de la sécurité réseau, mais également affiné nos compétences en programmation Python et en gestion de la concurrence.