On a attaqué notre propre infra, et on a trouvé deux trous
Phase de validation : reprendre la matrice de flux et vérifier ligne par ligne que la réalité correspond au document. Les deux écarts trouvés ne venaient pas du pare-feu.
Dernière phase de la mission, et de loin celle que j'ai préférée : reprendre le tableau écrit au début et vérifier que l'infra se comportait vraiment comme prévu.
Ça porte un nom en entreprise, validation de contrôles. Et ça a une vertu que je n'avais pas anticipée : ça transforme un document en preuve.
Une hypothèse par ligne
Chaque case de la matrice est une affirmation qu'on peut tester.
Case bleue « LAN → SRV : 443 » : depuis un poste du LAN, le port 443 d'un serveur SRV doit répondre. Case rouge « LAN → MGMT : refusé » : depuis ce même poste, aucun port de MGMT ne doit répondre.
On se place dans le VLAN source, on scanne la destination, on compare. Conforme, ou écart à expliquer.
# Depuis un poste du VLAN LAN, vers le VLAN d'administration
nmap -sS -Pn -p- --open 10.99.0.0/24
# Attendu : aucun hôte, aucun port ouvert
Le -Pn est indispensable et j'ai failli l'oublier. Sans lui, Nmap tente d'abord un ping, ne reçoit rien puisque l'ICMP est bloqué, en conclut que l'hôte est éteint, et ne scanne jamais les ports. On obtient un résultat vide qui ne prouve rien du tout.
C'est une nuance que je n'aurais pas soupçonnée avant de faire l'exercice : un test mal construit produit exactement le résultat qu'on espère. En sécurité, c'est le pire cas possible.
Écart n°1 : le DNS trop serviable
Le serveur Technitium était joignable depuis le LAN sur le port 53. Voulu, documenté, conforme.
Ce qui ne l'était pas : il acceptait des requêtes de résolution récursive pour n'importe quel domaine, y compris externe.
Le problème n'est pas anodin. Un résolveur ouvert peut servir à de l'amplification DNS : l'attaquant envoie de petites requêtes en usurpant l'adresse de sa victime, et le serveur répond à la victime avec des réponses bien plus volumineuses. L'infra devient participante à une attaque contre quelqu'un d'autre, sans que personne s'en rende compte.
Correction : récursion restreinte aux plages internes, et le service ramené à sa fonction réelle, résoudre les noms de l'entreprise.
Écart n°2 : l'interface qui traînait
Le second est plus banal, et sûrement plus fréquent en vrai. Un conteneur exposait une interface d'administration sur un port haut, accessible depuis le LAN.
Elle n'apparaissait nulle part dans notre doc. Personne ne l'avait ouverte : elle était publiée par défaut dans le docker-compose.yml qu'on avait repris, et on n'avait pas relu cette partie du fichier au moment de l'intégrer.
# Ce qui traînait dans le fichier d'origine
ports:
- "9000:9000" # publie sur toutes les interfaces de l'hôte
# Ce qu'il fallait
expose:
- "9000" # visible uniquement des conteneurs du même réseau
La leçon dépasse largement ces deux lignes. On raisonnait sur les règles du pare-feu en supposant qu'elles décrivaient tous les flux possibles. Sauf que Docker publie ses ports en écrivant directement dans les règles de filtrage de l'hôte, ce qui court-circuite une partie du raisonnement qu'on croit tenir au niveau du pare-feu périmétrique.
Une politique réseau pensée uniquement au niveau du pare-feu peut donc être percée silencieusement par une ligne dans un fichier de composition. Personne ne nous l'avait dit.
Trois choses que je garde
Une configuration n'est pas un contrôle. Tant qu'on ne l'a pas testée depuis la position de l'attaquant, on a un fichier, pas une garantie. Les deux écarts trouvés n'étaient pas des erreurs de config du pare-feu : ils venaient de comportements par défaut de briques qu'on avait intégrées sans les auditer.
L'angle change ce qu'on voit. En construisant, on demande « est-ce que ça marche ? » et on s'arrête dès que c'est oui. En attaquant, on demande « qu'est-ce qui répond ? » et on trouve des choses dont on ignorait l'existence. Même réseau, deux inventaires différents.
Le document doit venir avant le test. Sans la matrice écrite en début de mission, cette phase n'aurait produit qu'une liste de ports ouverts, sans moyen de dire lesquels étaient légitimes. C'est la comparaison à une intention documentée qui transforme un scan en résultat exploitable.
Le rapport avec mes CTF
Je fais du Hack The Box régulièrement, et j'y ai pris des réflexes d'énumération : balayer, lister, chercher la version vulnérable.
Cette phase m'a montré ce qui manque à cette pratique quand on la transpose en entreprise. Sur une machine de CTF, on cherche un chemin vers le drapeau, et n'importe lequel fait l'affaire. Sur une infra réelle, on cherche l'écart entre ce qui est et ce qui devrait être, ce qui suppose de savoir ce qui devrait être.
C'est la différence entre une liste de ports ouverts et un rapport d'audit. Je ne l'avais pas vue venir.