Fichiers honeypot sur un serveur Linux : quatre fichiers canari qui trahissent un intrus
Un intrus qui est entré cherche en quelques minutes des clés, des mots de passe et des sauvegardes. Placez-les — faux — et laissez auditd signaler dès que quelqu'un y touche. Installation complète avec règles auditd, les exceptions pour updatedb et votre outil de sauvegarde, et un cron qui pousse vers votre téléphone. Zéro faux positif après le premier jour.
Sommaire
La détection périmétrique vous dit que quelqu'un est à la porte. Cet article traite du moment d'après : quelqu'un est entré, avec une clé volée, un mot de passe fuité ou via une application web vulnérable, et commence à regarder autour. Que fait cette personne dans les cinq premières minutes ? ls -la ~, cat ~/.bash_history, find / -name "*.pem", ls ~/.ssh, cat .env. C'est exactement là que vous placez des fichiers qu'aucun processus légitime ne touche jamais. Qui les lit est, par définition, en tort.
Étape 1 : les quatre fichiers
Un bon canari a l'air précieux, se trouve là où un attaquant regarde, et n'est utilisé par rien sur le serveur lui-même.
| Fichier | Pourquoi un attaquant l'ouvre |
|---|---|
/root/.ssh/id_rsa.monsys-backup | Une clé privée avec « backup » dans le nom : mouvement latéral en une étape |
/home/deploy/.aws/credentials | Les identifiants cloud sont la cible n° 1 après une intrusion |
/etc/backup/db-passwords.txt | Le nom suffit |
/var/www/.env.bak | Les intrus web regardent ici en premier, avant d'aller plus loin |
Créez-les avec un contenu crédible. Un fichier vide ou dummy trahit le piège.
sudo install -d -m 0700 /root/.ssh /etc/backup
sudo install -d -m 0700 -o deploy -g deploy /home/deploy/.aws
# 1. Une vraie clé privée (mais autorisée nulle part)
sudo ssh-keygen -q -t ed25519 -N '' -C 'backup@old-nas' -f /root/.ssh/id_rsa.monsys-backup
sudo rm /root/.ssh/id_rsa.monsys-backup.pub
# 2. Des identifiants AWS au bon format (cette clé n'existe pas)
sudo tee /home/deploy/.aws/credentials >/dev/null <<'EOF'
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
region = eu-west-1
EOF
sudo chown deploy:deploy /home/deploy/.aws/credentials; sudo chmod 0600 /home/deploy/.aws/credentials
# 3. Un fichier de mots de passe avec un passé
sudo tee /etc/backup/db-passwords.txt >/dev/null <<'EOF'
# migrated from wiki 2023-11 — TODO move to vault
prod-postgres postgres Pg!2023-rotate-me
prod-redis - r3d1s-Old-Pass
EOF
sudo chmod 0600 /etc/backup/db-passwords.txt
# 4. Une sauvegarde de .env
sudo tee /var/www/.env.bak >/dev/null <<'EOF'
APP_ENV=production
DB_PASSWORD=Sh0p-2024-legacy
STRIPE_SECRET=sk_live_51HxEXAMPLEEXAMPLEEXAMPLE
EOF
sudo chmod 0640 /var/www/.env.bak
Vieillissez les fichiers : sudo touch -d '2024-03-18 09:12' <chemin>. Un fichier d'aujourd'hui à côté de fichiers vieux de deux ans se remarque dans ls -la.
Étape 2 : auditd les surveille
auditd est le démon d'audit du noyau ; il voit chaque open() sur le fichier, quel que soit le programme, et journalise l'utilisateur, le processus, la session et l'IP source de la session SSH.
sudo apt install -y auditd
sudo tee /etc/audit/rules.d/50-canary.rules >/dev/null <<'EOF'
# -p r = lecture, w = écriture, a = changement d'attributs. Pas de 'x'.
# -k canary = clé pour la recherche.
-w /root/.ssh/id_rsa.monsys-backup -p rwa -k canary
-w /home/deploy/.aws/credentials -p rwa -k canary
-w /etc/backup/db-passwords.txt -p rwa -k canary
-w /var/www/.env.bak -p rwa -k canary
EOF
sudo augenrules --load
sudo auditctl -l | grep canary # règles actives ?
Test : sudo cat /etc/backup/db-passwords.txt puis :
sudo ausearch -k canary -ts recent -i
Vous verrez un enregistrement PATH avec le fichier, un enregistrement SYSCALL avec uid, auid (l'utilisateur d'origine, même après sudo), exe=/usr/bin/cat, ses= (l'id de session) et tty. Avec ausearch -k canary --format csv, vous obtenez quelque chose d'analysable.
L'IP source de la session SSH se récupère via l'id de session : journalctl _AUDIT_SESSION=<ses> -u ssh | grep Accepted. Ou l'utilisateur auid plus l'horodatage contre last -i.
Étape 3 : l'alerte
Toutes les cinq minutes, pousser les nouveaux événements canari, avec qui/quoi/où :
sudo tee /usr/local/sbin/canary-watch.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
NTFY="https://ntfy.example.be/security"
HOST=$(hostname -s)
# --checkpoint : ausearch se souvient jusqu'où il a lu — pas d'alertes en double
CHK=/var/lib/canary-watch.checkpoint
# Une ligne par événement : auid→nom, exe, fichier, session
EVENTS=$(ausearch -k canary --checkpoint "$CHK" -i 2>/dev/null \
| awk '/^type=SYSCALL/ { for(i=1;i<=NF;i++){ if($i~/^auid=/)a=$i; if($i~/^exe=/)e=$i; if($i~/^ses=/)s=$i } }
/^type=PATH/ && /name=/ { for(i=1;i<=NF;i++) if($i~/^name=/) f=$i; print a, e, f, s }' \
| sort -u)
if [ -n "$EVENTS" ]; then
{ echo "CANARY TOUCHED on $HOST"; echo "$EVENTS";
echo; echo "sessions:"; echo "$EVENTS" | grep -oE 'ses=[0-9]+' | sort -u | while read -r s; do
journalctl "_AUDIT_SESSION=${s#ses=}" --no-pager 2>/dev/null | grep -m1 -E 'Accepted (publickey|password)' ; done; } \
| curl -s -H "Title: HONEYPOT $HOST" -H "Priority: urgent" -H "Tags: rotating_light" --data-binary @- "$NTFY" >/dev/null
fi
EOF
sudo chmod 0755 /usr/local/sbin/canary-watch.sh
echo '*/5 * * * * root /usr/local/sbin/canary-watch.sh' | sudo tee /etc/cron.d/canary-watch
C'est une alerte de priorité urgente. Il n'y a aucune raison légitime pour qu'un canari soit lu ; chaque notification est soit une intrusion, soit une exception que vous auriez dû configurer à l'étape 4.
Étape 4 : les exceptions (sinon le premier jour est un désastre)
Trois types de logiciels lisent tous les fichiers et déclenchent vos canaris en 24 heures :
Les indexeurs de fichiers. updatedb (mlocate/plocate) tourne chaque jour et fait un stat de tout — mais ne lit pas, donc avec -p rwa (sans x et sans stat) c'est bon. Excluez quand même, par sécurité :
# /etc/updatedb.conf
PRUNEPATHS="/tmp /var/spool /media /var/lib/os-prober /var/lib/ceph /home/.ecryptfs /var/lib/schroot /root/.ssh /etc/backup /home/deploy/.aws"
Les outils de sauvegarde. restic, borg, rsync et les agents Veeam lisent chaque fichier. Excluez les canaris dans la config de sauvegarde — vous ne les voulez pas non plus dans votre sauvegarde, sinon vos faux identifiants se retrouvent dans une archive qui pourrait fuiter plus tard :
# restic
restic backup / --exclude-file=/etc/restic/excludes
# dans /etc/restic/excludes :
/root/.ssh/id_rsa.monsys-backup
/home/deploy/.aws/credentials
/etc/backup/db-passwords.txt
/var/www/.env.bak
Les scanners de malware et outils de conformité. ClamAV, Lynis, OpenSCAP et rkhunter lisent des fichiers. Si vous les faites tourner, donnez-leur leur propre exclusion ou acceptez qu'une notification avec exe=/usr/bin/clamscan à 03:00 soit attendue — et filtrez-la dans le script sur exe=.
Ensuite, tournez 48 heures sans une seule notification avant de considérer l'alerte comme « urgente ». Chaque notification pendant ces 48 heures est une exception que vous ne connaissiez pas encore.
Étape 5 : l'utilisateur du serveur web aussi
Le fichier .env.bak est délibérément lisible par www-data (mode 0640 avec le bon groupe). Un attaquant entré par une faille PHP tourne en www-data et n'a pas sudo ; vous voulez quand même le voir. Vérifiez qu'auditd journalise aussi ces lectures :
sudo chgrp www-data /var/www/.env.bak
sudo -u www-data cat /var/www/.env.bak >/dev/null
sudo ausearch -k canary -ts recent -i | grep -E 'uid=www-data'
Pièges
-p xsur un fichier. Exécuter un fichier texte échoue mais déclenche. Laissezxde côté, sinon vous aurez du bruit de la complétion par tabulation et des éditeurs qui vérifient les bits exécutables.- Tampon auditd plein. Sur des serveurs chargés, auditd perd des événements si
-b(backlog) est trop petit. Mettez-b 8192en tête de/etc/audit/rules.d/10-base.ruleset vérifiezauditctl -spourlost. - Un canari dans git.
/var/www/.env.bakdans un répertoire de déploiement nettoyé pargit clean -fdxdisparaît au prochain déploiement. Mettez-le dans.git/info/excludeou un répertoire plus haut. - Trop de canaris. Quatre fichiers bien placés attrapent plus que quarante. Chaque fichier supplémentaire est une exception de plus dans votre sauvegarde et votre indexeur.
- Jamais testé. Mettez un rappel trimestriel :
catun canari, vérifiez que le push arrive en cinq minutes. Une détection que vous ne testez jamais n'existe pas.
Ce qu'il vous manque encore
- La corrélation avec la voie d'entrée. L'alerte canari dit que quelqu'un a lu ; quelle connexion SSH ou quelle requête web l'a précédée, vous devez le reconstituer vous-même à partir de deux logs — sous pression, au milieu de la nuit.
- La vue de flotte. Le même
auidqui lit des canaris sur trois serveurs en dix minutes, c'est une seule intrusion. Trois messages ntfy séparés ne le montrent pas. - La preuve. Pour une notification d'incident NIS2 (alerte précoce sous 24 heures), vous voulez une chronologie que vous pouvez donner au CCB, signée, pas un dump
ausearch.
Comment monsys fait
L'agent monsys place et surveille lui-même les fichiers canari (lecture, écriture et suppression), sans configuration auditd sur l'hôte, et signale un honeypot_trip avec utilisateur, processus et session. Le hub le relie à la détection SSH : un déclenchement de honeypot plus une connexion SSH interne à ±5 minutes devient une détection de mouvement latéral avec la chaîne complète. Chaque détection atterrit dans la piste d'audit signée, de sorte que la chronologie pour une notification d'incident est déjà prête. Intervenir (tuer le processus, isoler l'hôte) reste une décision humaine via un Emergency Action Token.
FAQ
Les fichiers honeypot sont-ils légaux ?
Oui. Ce sont des fichiers sur votre propre serveur. Ils ne font rien vers l'extérieur, ne trompent personne en dehors de votre système et ne collectent que ce que le noyau journalise déjà. C'est fondamentalement différent d'un serveur honeypot actif qui attire les attaquants.
Cela attrape-t-il aussi un attaquant qui est root ?
Oui, tant qu'auditd tourne. Root peut arrêter auditd ou effacer les règles, mais c'est en soi un événement (auditctl -D est journalisé comme CONFIG_CHANGE). Quelqu'un d'aussi méthodique s'est généralement trahi bien avant.
Pourquoi pas inotify au lieu d'auditd ?
inotifywait fonctionne et est plus simple, mais il ne voit pas qui a lu le fichier — pas d'uid, pas de processus, pas de session. Pour une alerte sur laquelle vous devez agir à 03:00, « quelqu'un l'a lu » est trop peu.
Rédigé par l'équipe monsys — des sysadmins qui font cela tous les jours.
Fait à la main ? Laissez monsys s'en charger en continu.
Tout ce que contient ce guide tourne dans monsys comme contrôle permanent, avec historique, alertes et preuves d'audit. 5 serveurs gratuits, hébergés en Belgique, installés en 60 secondes.