· · 11 min leestijd Intermediate

CTF en forensics skills die je een betere DevOps engineer maken

Hoe Hack The Box, CTF challenges en forensics skills direct vertalen naar dagelijks DevOps, platform engineering en Linux admin werk. Met praktische command voorbeelden.

Zij picket een slot op een beige server terwijl een spook in een hoodie hints op een floppy aangeeft

TL;DR Ik zit ’s avonds op Hack The Box en daar word ik beter van in m’n dagelijkse werk, en dat is platform engineering, geen pentesting. De eerste tien minuten op een CTF -box en de eerste tien minuten op een kapotte productieserver zijn dezelfde loop, met “flag” in plaats van “incident”. Hieronder de toolkit waar die loop op draait, van één host tot in een Kubernetes-pod, per commando met het CTF-gebruik en het werkgebruik naast elkaar.

Een productieserver doet raar. Je SSH’t naar binnen. En nu?

De mensen die hier rustig blijven kennen de volgende tien commando’s al, omdat ze precies deze loop al honderd keer gedraaid hebben. In hun eigen tijd, met het woord “flag” waar nu “incident” staat.

M’n avonden gaan op aan Hack The Box en zo nu en dan een CTF-competitie. Pentester worden staat niet op de planning. Ik zit prima in platform engineering en daar blijf ik. Dat ik toch doorga met die challenges komt doordat de skills rechtstreeks doorwerken in het dagwerk, en dat is meer dan ik dacht toen ik begon.

Een webapp pwnen lijkt in niks op een Kubernetes-cluster draaien. De eerste tien minuten zijn wél hetzelfde. Je zit in een systeem dat je niet helemaal snapt en je moet snel uitvinden wat het aan het doen is. Dat is begrijpen boven vertrouwen, het ding dat ik het belangrijkst vind als er iets stukgaat, en met een CTF oefen je dat terwijl het enige dat op het spel staat je avond is.

Hier is wat er doorwerkt, van één host tot in een pod.

Dezelfde vier vragen

Beland in een CTF-box en de eerste vragen zijn altijd dezelfde:

  • Wat draait er?
  • Wat is kwetsbaar?
  • Waar kan ik bij?
  • Hoe hangt het aan elkaar?

Vervang “kwetsbaar” door “kapot” en je hebt incident response. Dezelfde vragen als je SSH’t naar een server die raar doet of een pod die blijft crashen, en dezelfde vragen als je uitzoekt wat een aanvaller heeft aangeraakt.

Het verschil is herhaling. Een CTF-speler doet dit elke week, dus de enumeratie is geen checklist meer maar een reflex. En zodra het een reflex is, stop je met gokken onder druk en begin je met verzamelen. De rest van deze post is de toolkit waar die reflex op draait, van het bestandssysteem tot in de container.

Bestandssysteem

Recent gewijzigde bestanden

Op een CTF-box vind je hiermee de geplaatste backdoor of de config die een aanvaller heeft aangepast. Op het werk vind je ermee wat er veranderde vlak voordat het systeem kapotging, en meestal is dat gewoon config drift.

# Bestanden gewijzigd in de laatste 24 uur
find / -type f -mtime -1 2>/dev/null

# Bestanden gewijzigd in de laatste 10 minuten
find / -type f -mmin -10 2>/dev/null

# Bestanden veranderd na een specifieke datum
find / -type f -newermt "2026-02-01" 2>/dev/null

# Bestanden op grootte vinden (handig voor log bombs of grote dumps)
find / -type f -size +100M 2>/dev/null

Een deployment faalt en de app start niet. Welke config is er veranderd? find /etc -type f -mmin -30 laat zien dat iemand 15 minuten geleden het verkeerde bestand heeft bewerkt.

Bestanden op inhoud

Op een box grep je naar wachtwoorden, sleutels en flags die in bestanden verstopt zitten. Op het werk grep je naar waar een configwaarde gezet wordt, of naar de hardcoded credential die er niet hoort te staan.

# Bestanden vinden die een string bevatten
grep -r "password" /etc 2>/dev/null
grep -r "API_KEY" /app 2>/dev/null

# Bestanden vinden met een patroon (zoals IP adressen)
grep -rE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" /etc 2>/dev/null

# Bestanden met specifieke permissies (world-writable)
find / -perm -002 -type f 2>/dev/null

# SUID binaries vinden (privilege escalation, maar ook config issues)
find / -perm -4000 -type f 2>/dev/null

“Waar wordt die environment variable gezet?” grep -r "DATABASE_URL" /etc /app ~/.* 2>/dev/null vindt ’m op drie plekken, met drie verschillende waardes.

Metadata van bestanden

In een CTF is de metadata waar je het verborgen bestand vindt, en het bestand waar iemand aan gezeten heeft. Op het werk verklaren dezelfde commando’s het permissieprobleem waar je anders op zit te staren.

# Extended attributen
lsattr /etc/passwd
getfacl /var/log/secure

# Bestandstype en magic bytes
file /usr/bin/mystery-binary
file /var/log/weird.log

# Gedetailleerde stat info
stat /etc/shadow

# Immutable bestanden (kunnen niet gewijzigd worden, zelfs niet door root)
lsattr -a /etc/ | grep "\-i\-"

“Waarom kan ik dit bestand niet weggooien, zelfs niet als root?” lsattr laat zien dat de immutable flag aanstaat.

Processen

Wat draait er en waarom

Op een box zoek je het malafide proces, de reverse shell, het ding dat de CPU opeet. Op het werk zoek je het proces dat op hol is geslagen, en wat de applicatie nou écht aan het doen is.

# Gedetailleerde proces tree
ps auxf
pstree -p

# Wat gebruikt nu de meeste CPU/memory
top -bn1 | head -20
ps aux --sort=-%mem | head -10
ps aux --sort=-%cpu | head -10

# Proces op naam met volledige command line
ps aux | grep -E "[n]ginx|[a]pache"

# Welk proces gebruikt een specifieke poort
lsof -i :8080
ss -tlnp | grep 8080
netstat -tlnp | grep 8080

# Welke bestanden heeft een proces open
lsof -p <pid>
ls -la /proc/<pid>/fd/

# Proces environment variables
cat /proc/<pid>/environ | tr '\0' '\n'

# Proces working directory
ls -la /proc/<pid>/cwd

Een Java-app eet 100% CPU. ps aux --sort=-%cpu geeft je de PID. /proc/<pid>/fd/ laat 50.000 open file handles zien, dus het is een connection leak.

Traceren wat een proces doet

In een CTF trace je een binary om te leren wat ‘ie doet en waar de verborgen functionaliteit zit. Op het werk trace je de app die zegt dat hij niet kan connecten, om te zien welke syscall faalt en waarop.

# System calls gemaakt door een proces
strace -p <pid>
strace -f -e trace=network <command>  # alleen netwerk calls
strace -f -e trace=file <command>     # alleen file operaties

# Library calls
ltrace -p <pid>

# Trace een specifiek commando
strace -o output.txt -f ./mystery-app

# Bekijk wat een proces doet in real-time
watch -n 1 "cat /proc/<pid>/io"

De app zegt “connection refused” maar de service draait. strace -e connect laat zien dat hij naar het verkeerde IP connect, omdat een environment variable verkeerd staat.

Netwerk

Connecties

Op een box jaag je op C2 -connecties en exfiltratiekanalen, en zoek je een plek om naartoe te pivoten. Op het werk debug je waarom twee services elkaar niet kunnen bereiken, en af en toe vind je een connectie die er helemaal niet hoort te zijn.

# Alle netwerk connecties
ss -tunapl
netstat -tunapl

# Alleen established connecties
ss -tnp state established

# Connecties per proces
ss -tnp | grep <pid>

# Luisterende services
ss -tlnp
netstat -tlnp

# Connecties naar een specifieke host
ss -tn dst 10.0.0.50

# DNS resolution trace
dig +trace example.com
host -v example.com
nslookup -debug example.com

De applicatie krijgt een timeout op de database. ss -tn laat zien dat de connectie vastzit in SYN_SENT, en dat wijst op een firewall of een verkeerde route.

Packet capture

In een CTF capture je verkeer voor credentials en voor data die in een protocol verstopt zit. Op het werk capture je het om te zien wat er over de lijn gaat als de logs van de applicatie het niet zeggen, en om te checken dat TLS doet wat je denkt dat het doet.

# Capture traffic op een interface
tcpdump -i eth0 -w capture.pcap

# Specifiek traffic capturen
tcpdump -i eth0 port 443
tcpdump -i eth0 host 10.0.0.50
tcpdump -i eth0 'port 80 and host 10.0.0.50'

# Capture lezen met volledige packet content
tcpdump -r capture.pcap -A
tcpdump -r capture.pcap -X

# Snelle HTTP debugging
tcpdump -i eth0 -A port 80 | grep -E "GET|POST|Host:"

# TLS handshake checken
openssl s_client -connect example.com:443 -servername example.com

HTTPS werkt vanaf de ene server en faalt vanaf de andere. openssl s_client laat zien dat de falende server de CA niet vertrouwt, omdat het root-cert ontbreekt.

Logs

Het patroon vinden

Aanvalssporen, en die ene afwijking in een week aan ruis. Dat is de CTF-kant. Op het werk is het hetzelfde werk met een andere vraag, namelijk waarom dit kapotging en wanneer het begon.

# Logs volgen in real-time
tail -f /var/log/syslog
journalctl -f -u myservice

# Logs sinds specifieke tijd
journalctl --since "2026-02-01 10:00:00"
journalctl --since "1 hour ago"

# Logs voor specifieke service
journalctl -u nginx -n 100

# Filter op priority
journalctl -p err  # alleen errors
journalctl -p warning..err  # warnings en errors

# Tel voorkomens van patronen
grep -c "error" /var/log/app.log
awk '/error/ {count++} END {print count}' /var/log/app.log

# Timestamps extracten en groeperen per minuut
awk '{print $1, $2, $3}' /var/log/app.log | cut -d: -f1,2 | uniq -c | sort -rn

# Errors vinden met context
grep -B5 -A5 "FATAL" /var/log/app.log

Af en toe een 500. grep -c "500" access.log per uur laat elk uur een piek om :00 zien, en dat is een cronjob.

Correleren over services heen

Op een box bouw je de tijdlijn van de aanvaller opnieuw op en volg je z’n laterale beweging. Op het werk bouw je de tijdlijn van het incident op over services heen, en oorzaak en gevolg zitten zelden in hetzelfde logbestand.

# Auth failures
grep "Failed password" /var/log/auth.log | awk '{print $1,$2,$3,$9,$11}' | sort | uniq -c

# Commands uitgevoerd door gebruikers (als auditd is ingeschakeld)
ausearch -k commands -i

# Correleer op timestamp over bestanden heen
grep "2026-02-27T10:15" /var/log/*.log

# Gestructureerde logs parsen (JSON)
cat app.log | jq 'select(.level == "ERROR")'
cat app.log | jq -r '[.timestamp, .message] | @tsv'

Gebruikers en authenticatie

In een CTF is het gecompromitteerde account de ingang, dus je brengt in kaart wie wat mag. Op het werk is diezelfde kaart de toegangsaudit, de permissiebug en de security review.

# Gebruikers met login shells
cat /etc/passwd | grep -v nologin | grep -v /bin/false

# Gebruikers met UID 0 (root equivalent)
awk -F: '$3 == 0 {print $1}' /etc/passwd

# Laatste logins
last -n 20
lastlog

# Gefaalde login pogingen
lastb -n 20
faillog -a

# Wie is nu ingelogd
w
who

# Gebruiker's groepen en sudo rechten
id username
sudo -l -U username

# SSH authorized keys
cat ~/.ssh/authorized_keys
find / -name "authorized_keys" 2>/dev/null

Je vermoedt dat er iemand binnen is die er niet hoort. last laat een login zien vanaf een IP dat je niet kent. grep "Accepted" /var/log/auth.log laat zien dat ze met een SSH-key binnenkwamen en niet met een wachtwoord.

Disk

Op een box is diskforensics verwijderde bestanden terughalen en de layout lezen. Op het werk is het de disk die vol is terwijl du zegt van niet.

# Disk gebruik per directory
du -sh /* 2>/dev/null | sort -h
du -sh /var/* 2>/dev/null | sort -h

# Vind wat ruimte gebruikt
ncdu /  # interactief

# Grote bestanden vinden
find / -type f -size +1G 2>/dev/null

# Verwijderde bestanden nog steeds open (houden disk space vast)
lsof +L1

# Inode gebruik
df -i

# Wat is gemount
mount | column -t
cat /proc/mounts
findmnt

Disk 100% vol en du zegt 50% in gebruik. lsof +L1 laat verwijderde logbestanden zien die een proces nog openhoudt, en dat proces herstarten geeft de ruimte terug.

Containers

De CTF-versie is de container escape, en de misconfiguratie die ’m mogelijk maakt. De werkversie is de container die niet wil starten, en weten in welke staat hij zit.

# Wat zit er in een draaiende container
docker exec -it <container> /bin/sh
kubectl exec -it <pod> -- /bin/sh

# Container processen vanaf host
docker top <container>
ps aux | grep containerd

# Container resource gebruik
docker stats
kubectl top pods

# Container logs
docker logs -f <container>
kubectl logs -f <pod>

# Container config inspecteren
docker inspect <container>
docker inspect <container> | jq '.[0].Config.Env'
kubectl describe pod <pod>

# Container bestandssysteem
docker diff <container>  # wat is veranderd
docker export <container> | tar -tf -  # bestanden listen

# Capabilities checken
docker inspect <container> | jq '.[0].HostConfig.CapAdd'
kubectl auth can-i --list

Een container crasht bij het opstarten en docker logs laat niks zien. docker inspect laat de verkeerde entrypoint zien, gezet door een image override.

Wat er opduikt op het werk

Na maanden van avonden hiermee duiken de gewoontes op het werk op zonder dat ik ervoor kies. Ik enumereer voordat ik iets aanraak, want het verkeerde ding fixen onder druk is hoe één storing er twee worden. Ik lees de foutmelding in plaats van nog een keer proberen en hopen, en meestal staat het antwoord er gewoon in.

Ik trace een probleem van de applicatie naar de syscall en dan naar het netwerk, hetzelfde pad als van webapp naar root op een box. Ik zie wat verkeerd geconfigureerd is voordat het bijt, omdat een CTF je traint om daar precies naar te kijken. En grep, find, awk en sed zijn geen dingen meer die ik opzoek.

Dat is allemaal herhaling, en een CTF is de goedkoopste plek die ik ken om die te krijgen zonder er een securitybaan voor te nemen.

Waar je begint

Wil je dezelfde toolkit, begin dan in het ondiepe:

  1. OverTheWire Bandit is pure Linux-commandline, geen setup. Doe dit eerst.
  2. TryHackMe heeft begeleide rooms met hints, een zachtere instap.
  3. Hack The Box daarna. Begin bij de makkelijke boxes en blijf bij de Linux-machines.
  4. PicoCTF heeft de goede forensics-challenges, voor als je dieper wilt.

Een avond per week is genoeg. Ik doe het nu maanden en ik ben nog steeds geen pentester. De volgende tien commando’s ken ik wel, als ik naar een kapotte server SSH.