Challenge Lab 01 - Port Scanner
⚠️ Avertissement légal & éthique : exécutez ces exercices uniquement sur vos propres machines/VMs ou sur des environnements dédiés au lab avec autorisation explicite. Le port‑scanning et la collecte d’informations sur des systèmes tiers sans accord sont illégaux.
Exercice 1 — Premiers pas avec socket
Objectif : créer une connexion TCP simple en Python.
Énoncé : Écrivez une fonction tcp_connect(host, port) qui tente d’ouvrir une connexion TCP vers host:port et retourne True si la connexion réussit, False sinon. Ne le faites que vers 127.0.0.1 ou une VM que vous contrôlez (Metasploitable).
Indices : socket.socket(AF_INET, SOCK_STREAM), settimeout(1.0), connect_ex.
Exercice 2 — Valider une adresse IPv4
Objectif : utiliser le module standard ipaddress.
Énoncé : Écrivez is_valid_ipv4(text: str) -> bool qui renvoie True si text est une IPv4 valide.
Indices : ipaddress.ip_address(text) lève ValueError si invalide.
Exercice 3 — Parser une chaîne de ports
Objectif : convertir une chaîne du type "22,80,8000-8005" en liste triée d’entiers uniques.
Énoncé : Implémentez parse_ports(s: str) -> list[int] gérant des nombres et des plages a-b.
Indices : itérer sur s.split(','), détecter '-', range(start, end+1).
Exercice 4 — Scanner quelques ports en séquentiel
Objectif : réutiliser E1 & E3 pour l’hôte 127.0.0.1.
Énoncé : Créez scan_ports(host, ports) qui renvoie la liste des ports ouverts.
Indices : appelez tcp_connect(host, p) pour chaque p ; respecter un timeout raisonnable.
Exercice 5 — Lecture d’une bannière (banner grabbing)
Objectif : lire quelques octets après connexion.
Énoncé : Écrivez grab_banner(host, port) qui se connecte, lit jusqu’à 1024 octets, et renvoie une chaîne (ou None si rien). (Technique de banner grabbing.)
Indices : sock.recv(1024) ; décodage utf-8 avec errors='replace'.
Exercice 6 — Fallback HTTP minimal
Objectif : provoquer une réponse HTTP si aucune bannière passive n’est reçue.
Énoncé : Modifiez grab_banner pour, en cas de réception vide, envoyer b"HEAD / HTTP/1.0\r\n\r\n" puis relire.
Indices : sock.send(...), puis recv(...) avec un léger timeout (p.ex. 2.0).
Exercice 7 — Reverse DNS (étiquette humaine)
Objectif : résoudre éventuellement un nom d’hôte depuis une IP.
Énoncé : Créez reverse_dns(ip: str) -> str|None qui tente socket.gethostbyaddr(ip) et renvoie le nom, sinon None.
Indices : capturer socket.herror/socket.gaierror.
Exercice 8 — Sauvegarder en JSON
Objectif : sérialiser des résultats de scan.
Énoncé : Écrivez save_results(path, data) qui enregistre un dictionnaire Python dans un fichier JSON indenté.
Indices : json.dump(obj, f, indent=2).
Exercice 9 — Arguments en ligne de commande
Objectif : créer une interface simple.
Énoncé : Avec argparse, acceptez targets (texte) et ports (texte) puis affichez ce qui a été compris par vos fonctions parse_targets et parse_ports.
Indices : ArgumentParser, add_argument, parser.parse_args().
Exercice 10 — Limiter le rythme (éthique & sécurité)
Objectif : éviter d’inonder le réseau lors d’un scan séquentiel.
Énoncé : Ajoutez un paramètre delay (en secondes) à scan_ports qui insère time.sleep(delay) entre deux tentatives.
Indices : time.sleep(0.05) ; maintenir un délai court mais non nul.
Exercice 11 — Mapper port → service probable
Objectif : afficher un libellé quand aucune bannière n’est reçue.
Énoncé : Créez un dict COMMON = {22:'SSH', 80:'HTTP', 443:'HTTPS', 3306:'MySQL'}. Écrivez guess_service(port, banner) qui renvoie banner si présente, sinon COMMON.get(port, 'inconnu').
Indices : simple condition ternaire.
Exercice 12 — Rapport texte lisible
Objectif : formater une sortie conviviale.
Énoncé : À partir d’un résultat {ip: [{port, banner}], ...}, affichez pour chaque IP les ports ouverts avec service = guess_service(...) et, si possible, le reverse_dns.
Indices : f-strings ; tronquer les bannières trop longues.
By Wahid Hamdi