Security & detectiegevorderd5 min lezen

Honeypot-bestanden op een Linux-server: vier canary files die een inbreker verraden

Een inbreker die binnen is, zoekt binnen minuten naar sleutels, wachtwoorden en backups. Leg die neer — nep — en laat auditd melden zodra iemand ze aanraakt. Complete setup met auditd-regels, de uitzonderingen voor updatedb en je backup-tool, en een cron dat naar je telefoon pusht. Nul false positives na dag één.

Inhoud
  1. Stap 1: de vier bestanden
  2. Stap 2: auditd laat ze bewaken
  3. Stap 3: de alert
  4. Stap 4: de uitzonderingen (anders is dag één een ramp)
  5. Stap 5: ook op de webserver-gebruiker
  6. Valkuilen
  7. Wat je hiermee nog niet hebt
  8. Zo doet monsys het
  9. FAQ

Perimeter-detectie vertelt je dat iemand aan de deur staat. Dit artikel gaat over het moment daarna: iemand is binnen, met een gestolen key, een gelekt wachtwoord of via een kwetsbare webapp, en begint rond te kijken. Wat doet zo iemand in de eerste vijf minuten? ls -la ~, cat ~/.bash_history, find / -name "*.pem", ls ~/.ssh, cat .env. Precies daar leg je bestanden neer die geen enkel legitiem proces ooit aanraakt. Wie ze leest, is per definitie fout.

Stap 1: de vier bestanden

Een goede canary ziet er waardevol uit, staat waar een aanvaller kijkt, en wordt door niets op de server zelf gebruikt.

BestandWaarom een aanvaller het opent
/root/.ssh/id_rsa.monsys-backupEen private key met "backup" in de naam: lateral movement in één stap
/home/deploy/.aws/credentialsCloud-credentials zijn het hoogste doel na een inbraak
/etc/backup/db-passwords.txtDe naam alleen al
/var/www/.env.bakWebapp-inbrekers kijken hier als eerste, vóór ze verder komen

Maak ze aan met geloofwaardige inhoud. Een lege file of dummy verraadt de val.

sudo install -d -m 0700 /root/.ssh /etc/backup
sudo install -d -m 0700 -o deploy -g deploy /home/deploy/.aws

# 1. Een echte (maar nergens geautoriseerde) private key
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. AWS-credentials in het juiste formaat (deze key bestaat niet)
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. Een wachtwoordbestand met een verleden
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. Een .env-backup
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

Zet de bestanden oud: sudo touch -d '2024-03-18 09:12' <pad>. Een file van vandaag naast bestanden van twee jaar geleden valt op in ls -la.

Stap 2: auditd laat ze bewaken

auditd is de kernel-audit-daemon; hij ziet elke open() op het bestand, ongeacht welk programma het doet, en logt de gebruiker, het proces, de sessie en het bron-IP van de SSH-sessie.

sudo apt install -y auditd
sudo tee /etc/audit/rules.d/50-canary.rules >/dev/null <<'EOF'
# -p r = read, w = write, a = attribute change. Geen 'x'.
# -k canary = sleutel om op te zoeken.
-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        # regels actief?

Test: sudo cat /etc/backup/db-passwords.txt en dan:

sudo ausearch -k canary -ts recent -i

Je ziet een PATH-record met het bestand, een SYSCALL-record met uid, auid (de oorspronkelijke gebruiker, ook na sudo), exe=/usr/bin/cat, ses= (de sessie-id) en tty. Met ausearch -k canary --format csv krijg je iets dat je kunt parsen.

Het bron-IP van de SSH-sessie haal je erbij via de sessie-id: journalctl _AUDIT_SESSION=<ses> -u ssh | grep Accepted. Of gebruiker auid plus tijdstip tegen last -i.

Stap 3: de alert

Elke vijf minuten de nieuwe canary-events pushen, met wie/wat/waar:

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 onthoudt zelf tot waar het gelezen heeft — geen dubbele meldingen
CHK=/var/lib/canary-watch.checkpoint

# Eén regel per event: auid→naam, exe, bestand, sessie
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

Dit is een alert met prioriteit urgent. Er is geen legitieme reden waarom een canary wordt gelezen; iedere melding is óf een inbraak, óf een uitzondering die je in stap 4 had moeten configureren.

Stap 4: de uitzonderingen (anders is dag één een ramp)

Drie soorten software lezen alle bestanden en triggeren je canary's binnen 24 uur:

Bestandsindexers. updatedb (mlocate/plocate) draait dagelijks en stat't alles — maar leest niet, dus met -p rwa (zonder x en zonder stat) is dat oké. Toch uitsluiten, voor de zekerheid:

# /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"

Backup-tools. restic, borg, rsync en Veeam-agents lezen elk bestand. Sluit de canary's uit in de backup-config — je wilt ze ook niet in je backup, want dan liggen je nep-credentials in een archief dat later misschien gelekt wordt:

# restic
restic backup / --exclude-file=/etc/restic/excludes
# in /etc/restic/excludes:
/root/.ssh/id_rsa.monsys-backup
/home/deploy/.aws/credentials
/etc/backup/db-passwords.txt
/var/www/.env.bak

Malware-scanners en compliance-tools. ClamAV, Lynis, OpenSCAP en rkhunter lezen bestanden. Als je die draait, geef ze een eigen uitsluiting of accepteer dat een melding met exe=/usr/bin/clamscan om 03:00 verwacht is — en filter die in het script op exe=.

Draai daarna 48 uur zonder een enkele melding vóór je de alert als "urgent" beschouwt. Elke melding in die 48 uur is een uitzondering die je nog niet kende.

Stap 5: ook op de webserver-gebruiker

Het .env.bak-bestand is bewust leesbaar voor www-data (mode 0640 met de juiste groep). Een aanvaller die via een PHP-lek binnenkomt, draait als www-data en heeft geen sudo; toch wil je hem zien. Controleer dat auditd ook die reads logt:

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'

Valkuilen

  • -p x op een bestand. Executeren van een tekstbestand faalt maar triggert. Laat x weg, anders krijg je ruis van tab-completion en editors die executable-bits checken.
  • auditd-buffer vol. Op drukke servers verliest auditd events als -b (backlog) te klein is. Zet -b 8192 bovenaan /etc/audit/rules.d/10-base.rules en controleer auditctl -s op lost.
  • Een canary in git. /var/www/.env.bak in een deploy-map die via git clean -fdx wordt opgeschoond, verdwijnt bij de volgende deploy. Zet hem in .git/info/exclude of één map hoger.
  • Te veel canary's. Vier goed geplaatste bestanden vangen meer dan veertig. Elke extra file is een extra uitzondering in je backup en je indexer.
  • Nooit getest. Zet een kwartaal-reminder: cat één canary, controleer dat de push binnen vijf minuten komt. Detectie die je nooit test, bestaat niet.

Wat je hiermee nog niet hebt

  • Correlatie met de toegangsweg. De canary-melding zegt dat iemand las; welke SSH-login of welke webrequest daaraan voorafging, moet je zelf uit twee logs bij elkaar zoeken — en onder druk, midden in de nacht.
  • Fleet-zicht. Dezelfde auid die op drie servers binnen tien minuten canary's leest, is één inbraak. Drie losse ntfy-berichten laten dat niet zien.
  • Bewijs. Voor een NIS2-incidentmelding (24 uur early warning) wil je een tijdlijn die je aan de CCB kunt geven, ondertekend, niet een ausearch-dump.

Zo doet monsys het

De monsys-agent plaatst en bewaakt de canary-bestanden zelf (read, write én delete), zonder auditd-configuratie op de host, en meldt een honeypot_trip met gebruiker, proces en sessie. De hub koppelt dat aan de SSH-detectie: een honeypot-trip plus een interne SSH-login binnen ±5 minuten wordt een lateral movement-detectie met de volledige keten. Elke detectie landt in de ondertekende audit-trail, zodat de tijdlijn voor een incidentmelding al klaarligt. Ingrijpen (proces killen, host isoleren) blijft een menselijke beslissing via een Emergency Action Token.

FAQ

Zijn honeypot-bestanden legaal?

Ja. Het zijn bestanden op je eigen server. Ze doen niets naar buiten, misleiden niemand buiten je systeem en verzamelen alleen wat de kernel al logt. Dit is fundamenteel anders dan een actieve honeypot-server die aanvallers aantrekt.

Vangt dit ook een aanvaller die root is?

Ja, zolang auditd draait. Root kan auditd stoppen of de regels wissen, maar dat is zelf een event (auditctl -D wordt gelogd als CONFIG_CHANGE). Wie zo grondig te werk gaat, heeft je meestal al lang eerder verraden.

Waarom geen inotify in plaats van auditd?

inotifywait werkt en is simpeler, maar het ziet niet wie het bestand las — geen uid, geen proces, geen sessie. Voor een alert waar je om 03:00 op moet handelen, is "iemand las het" te weinig.

Geschreven door het monsys-team — sysadmins die dit dagelijks doen.

Zelf gedaan? Laat monsys het bijhouden.

Alles uit deze how-to draait in monsys als doorlopende check, met historie, alerts en audit-bewijs. 5 servers gratis, EU-gehost in België, geïnstalleerd in 60 seconden.