← Digital forensicscron persistence hides in six spots, check them all

cron persistence hides in six spots, check them all

$for u in $(cut -f1 -d: /etc/passwd); do crontab -l -u $u 2>/dev/null; done

cron is boring, which is exactly why attackers love it

nobody gets excited about cron. that's the point. it's been quietly running scheduled jobs on linux since forever, admins ignore it, and most people only look at it when something breaks. that makes it a near-perfect persistence spot. an attacker drops one line into a cron job and they get a foothold that survives reboots, survives you changing your password, survives you feeling pretty good about your incident response. the problem is cron doesn't live in one place. it lives in six, and if you only check one or two, you're leaving the door open on the others.

the six spots you actually need to check

cron persistence can hide in any of these locations, and defenders almost always forget at least one:

1. per-user crontabs (/var/spool/cron/crontabs or /var/spool/cron depending on distro)
2. the system-wide /etc/crontab
3. /etc/cron.d/, a folder for drop-in cron files
4. /etc/cron.hourly/, cron.daily/, cron.weekly/, cron.monthly/
5. anacron jobs that fire on boot or after downtime
6. dot-file jobs, meaning hidden files sitting in any of the above, named to look boring on purpose

each of these gets read by cron independently. an attacker only needs one of them to survive. you need to check all of them, every time.

breaking down the hunt command

for u in $(cut -f1 -d: /etc/passwd); do crontab -l -u $u 2>/dev/null; done

this loop is doing something most people skip: checking every single user's personal crontab, not just root's. here's the walk-through.

cut -f1 -d: /etc/passwd pulls the first field from every line in /etc/passwd, split on colons. that first field is the username. so this grabs a list of every user account that exists on the box, including service accounts and weird leftover accounts nobody remembers creating.

for u in $(...); do ... done loops over that list of usernames one at a time.

crontab -l -u $u lists the crontab for that specific user. most people only ever run crontab -l, which shows your own crontab, or check root's. attackers know this, so they'll plant a job under a low-privilege service account that nobody thinks to audit, like a leftover ftp or backup user.

2>/dev/null just throws away the "no crontab for this user" errors so your output isn't noise city.

run this and actually read every line that comes back. a legit cron job usually points to something recognizable, a backup script, a log rotation, a monitoring check-in. a suspicious one often points to curl, wget, base64, or a script tucked away in /tmp or a hidden directory.

the second command, covering the other five spots

ls -la /etc/cron.d /etc/cron.hourly /var/spool/cron/crontabs; cat /etc/crontab

ls -la matters here specifically because of the -a flag. that flag shows dot-files, files that start with a period and are hidden from a normal ls. this is the actual trick behind a lot of cron persistence: dropping a file named something like .apache or .systemd-update into /etc/cron.d/. it blends in with real system files, doesn't show up on a casual glance, and looks harmless enough that even a careful admin might skim past it.

cat /etc/crontab shows the system-wide crontab directly, which lists jobs along with the user they run as. this file is short enough that you should just read the whole thing, not skim it.

what actually looks suspicious

a few patterns worth flagging immediately: jobs that run every minute (attackers love a tight interval for reliable callback), jobs owned by users who shouldn't be running anything, jobs referencing paths like /tmp, /dev/shm, or hidden directories, and any job you personally don't remember creating and can't explain in one sentence.

the takeaway

cron persistence works because it's spread across six different spots and almost nobody checks all of them in one pass. the fix isn't complicated, it's just thoroughness. run the loop against every user account, list cron.d and the spool directories with hidden files showing, and actually read /etc/crontab instead of glancing at it. do this on a schedule, not just when something feels off, and keep a known-good baseline of what your legit cron jobs look like so anything new stands out immediately. the attacker only needs the one spot you skip. don't skip any of them.

watch the reel ↗
the weekly drop

one command a week that makes you harder to hack.

a single tool, explained in plain english, every week. straight to your inbox.

no spam. one email a week. unsubscribe anytime.