Aller au contenu

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.

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.

/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.pid

Depuis 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.

Cowrie est en Python pur, mais ses dépendances (cryptography, cffi, bcrypt) compilent des extensions natives.

Fenêtre de terminal
sudo apt update
sudo apt install -y python3-venv python3-dev build-essential \
libssl-dev libffi-dev authbind

Vérification :

Fenêtre de terminal
grep PRETTY_NAME /etc/os-release # Debian GNU/Linux 13 (trixie)
python3 --version # Python 3.13.x

Cowrie refuse de démarrer en root.

Fenêtre de terminal
sudo adduser --disabled-password --gecos "" cowrie
sudo su - cowrie

Tout le reste se fait en tant qu’utilisateur cowrie.

Fenêtre de terminal
mkdir ~/my-honeypot && cd ~/my-honeypot
python3 -m venv cowrie-env
source cowrie-env/bin/activate
python -m pip install --upgrade pip
python -m pip install cowrie
pip show cowrie | head -2

Résultat au moment du test : cowrie 3.0.13.

Fenêtre de terminal
cowrie init
Wrote etc/cowrie.cfg
Created var/log/cowrie, var/lib/cowrie, var/lib/cowrie/downloads, var/lib/cowrie/tty, var/run

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 = true
listen_endpoints = tcp:2222:interface=0.0.0.0
[telnet]
enabled = true
listen_endpoints = tcp:2223:interface=0.0.0.0
[output_jsonlog]
enabled = true
logfile = ${honeypot:log_path}/cowrie.json

Le 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 :

  1. défauts embarqués dans le paquet
  2. /etc/cowrie/cowrie.cfg
  3. ./etc/cowrie.cfg
  4. ./cowrie.cfg

Sans etc/userdb.txt, Cowrie utilise une base d’exemple qui accepte quasiment tout. En production on la remplace.

Fenêtre de terminal
cat > etc/userdb.txt <<'EOF'
root:x:!root
root:x:Trixie2026
admin:x:*
*:x:!*
EOF

Lecture 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 Trixie2026
root
$ 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 = AuthRandom
auth_class_parameters = 2, 5, 10
Fenêtre de terminal
cd ~/my-honeypot
source cowrie-env/bin/activate
cowrie start
cowrie status

Sortie 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 connections

Commandes 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.

Pour un démarrage automatique, en root :

/etc/systemd/system/cowrie.service
[Unit]
Description=Cowrie SSH/Telnet Honeypot
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=cowrie
Group=cowrie
WorkingDirectory=/home/cowrie/my-honeypot
ExecStart=/home/cowrie/my-honeypot/cowrie-env/bin/cowrie start -n
Restart=on-failure
RestartSec=10
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=false
ReadWritePaths=/home/cowrie/my-honeypot
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictSUIDSGID=true
[Install]
WantedBy=multi-user.target
Fenêtre de terminal
sudo systemctl daemon-reload
sudo systemctl enable --now cowrie
sudo systemctl status cowrie

Le -n maintient Cowrie au premier plan, ce qu’attend Type=simple. Sans lui, systemd considère le service comme terminé aussitôt.

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 62222
Fenêtre de terminal
sudo systemctl restart ssh
# ouvrir une NOUVELLE session sur 62222 avant de fermer la courante

Option A, redirection nftables (recommandé sur Debian 13)

Section intitulée « Option A, redirection nftables (recommandé sur Debian 13) »
Fenêtre de terminal
sudo nft add table ip nat
sudo nft add chain ip nat prerouting '{ type nat hook prerouting priority -100 ; }'
sudo nft add rule ip nat prerouting tcp dport 22 redirect to :2222
sudo nft add rule ip nat prerouting tcp dport 23 redirect to :2223
sudo nft list ruleset

Persistance :

Fenêtre de terminal
sudo apt install -y nftables
sudo sh -c 'nft list ruleset > /etc/nftables.conf'
sudo systemctl enable --now nftables

Équivalent iptables si vous restez sur l’ancienne pile :

Fenêtre de terminal
sudo iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222

Cowrie écoute directement sur 22 tout en restant non privilégié.

Fenêtre de terminal
sudo touch /etc/authbind/byport/22
sudo chown cowrie:cowrie /etc/authbind/byport/22
sudo chmod 770 /etc/authbind/byport/22
[ssh]
listen_endpoints = tcp:22:interface=0.0.0.0
Fenêtre de terminal
AUTHBIND_ENABLED=yes cowrie start
Fenêtre de terminal
sudo setcap cap_net_bind_service=+ep /usr/bin/python3

Déconseillé : la capacité est accordée à l’interpréteur Python du système entier, pas au seul honeypot.

Simuler une attaque depuis une autre machine :

Fenêtre de terminal
ssh -p 2222 root@IP_DU_HONEYPOT
# puis dans le faux shell :
uname -a; id; ls /; wget http://example.com/x.sh
Fenêtre de terminal
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.connect
cowrie.client.version
cowrie.client.kex
cowrie.login.success root / P@ssw0rd
cowrie.command.input uname -a; id; ls /; wget http://example.com/x.sh
cowrie.session.file_download
cowrie.session.closed

Quelques extractions utiles :

Fenêtre de terminal
# top 20 des mots de passe testes
jq -r 'select(.eventid|startswith("cowrie.login")) | .password' var/log/cowrie/cowrie.json \
| sort | uniq -c | sort -rn | head -20
# top des IP sources
jq -r '.src_ip' var/log/cowrie/cowrie.json | sort | uniq -c | sort -rn | head
# toutes les commandes saisies
jq -r 'select(.eventid=="cowrie.command.input") | .input' var/log/cowrie/cowrie.json

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.

Fenêtre de terminal
ls -l var/lib/cowrie/downloads/
file var/lib/cowrie/downloads/*

Le nom du fichier est directement l’IOC à soumettre à VirusTotal ou à votre MISP.

Fenêtre de terminal
source cowrie-env/bin/activate
playlog 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.

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.

Un honeypot détecté en trois commandes ne collecte rien d’intéressant. Points à traiter :

  • hostname et 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
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
Fenêtre de terminal
source cowrie-env/bin/activate
pip install --upgrade cowrie
cowrie restart

Rotation 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.