Skip to content
reverseshell

Pourquoi les reverse shells échouent presque toujours pour des raisons banales

Routage, filtrage sortant, listener, quoting, runtime absent : une méthode propre pour diagnostiquer un reverse shell qui ne revient pas.

Publié le 3 min de lecture

Quand un reverse shell ne revient pas, le réflexe courant consiste à changer de payload. Mauvais réflexe, la plupart du temps. Le callback doit traverser DNS, routage, NAT, filtrage sortant, pare-feu local, exécution du processus, quoting et parfois un agent de sécurité qui tue l'action sans explication lisible.

Si vous changez trois paramètres en même temps, vous ne déboguez pas. Vous brassez de l'air.

Le listener n'écoute pas où vous pensez

Première erreur : lancer le listener au mauvais endroit ou sur la mauvaise interface. nc -lvnp 4444 écoute généralement sur toutes les interfaces, mais ce n'est pas une loi physique. Certains wrappers se bindent sur localhost. Certains conteneurs écoutent bien en interne mais n'exposent aucun port vers l'hôte.

Vérifiez :

ss -lntp | grep 4444

Dans Docker, 0.0.0.0:4444 à l'intérieur du conteneur ne suffit pas. Il faut publier le port, autoriser le trafic côté hôte, et s'assurer que la cible possède une route vers cette adresse. Kubernetes ajoute encore de la friction : IP de pod, service, node port, ingress, network policy. Un reverse shell raté révèle souvent que votre représentation du réseau est fausse.

Le filtrage sortant fait son travail

Beaucoup d'environnements bloquent les connexions TCP sortantes arbitraires. Ils autorisent parfois 80 et 443 via un proxy, inspectent TLS, refusent les connexions directes vers des IP, ou appliquent des règles différentes selon le segment réseau. Un lab qui ne teste que LHOST=10.0.0.5 sur le port 4444 ne ressemble pas à la production.

Regardez les paquets avant d'accuser la commande :

tcpdump -ni any host TARGET_IP and port 4444

Rien ne sort ? L'exécution ne se produit peut-être pas, ou la politique locale bloque. Le trafic sort mais n'arrive jamais ? Le chemin réseau est cassé. Il arrive puis reset ? Le listener, le pare-feu local ou la variante de netcat devient suspect.

Les runtimes et le quoting cassent sans bruit

Payload Python sur une machine sans Python. Syntaxe Bash exécutée par /bin/sh. PowerShell en langage contraint. PHP avec disable_functions qui bloque l'exécution de processus. Ce ne sont pas des cas rares. Ce sont des cas normaux.

Le quoting est encore plus traître. Une commande peut passer par un formulaire web, un champ JSON, un runner YAML, une variable CI, un wrapper shell puis seulement atteindre le processus cible. Chaque couche peut manger un guillemet ou interpréter un caractère spécial.

Réduisez le problème. Testez un callback inoffensif dans le même chemin d'exécution. Capturez stderr quand le lab vous le permet. Regardez la télémétrie de création de processus si elle existe. Savoir si aucun processus n'a démarré ou si un processus a démarré puis quitté change complètement l'enquête.

Une connexion n'est pas une session

Parfois le socket s'ouvre puis meurt immédiatement. Cela peut venir de stdin fermé, d'un module manquant, d'un shell qui quitte, d'un binaire absent ou d'un contrôle de sécurité qui termine les processus enfants.

Un reverse shell est fragile parce qu'il compacte trop d'hypothèses dans une ligne. Un bon générateur rend ces hypothèses visibles. Un bon opérateur vérifie le réseau, le listener, le runtime et le contexte d'exécution avant de changer de payload.

Articles liés

Un workflow concret pour générer des reverse shells en environnement autorisé, préparer le listener et diagnostiquer les échecs.
La détection des reverse shells demande du contexte processus, réseau et workload. Les signatures seules ratent trop de cas réels.
Comment choisir un listener pour des tests reverse shell autorisés, entre netcat, ncat et socat, sans complexifier le lab.