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