Cron Job and Systemd Timer Privilege Escalation
Cybersecurity
Cron and systemd timers run as root on a schedule, and they are full of writable scripts, weak permissions, and PATH games. We cover how to find them and abuse them.
By Arjun Raghavan, Security & Systems Lead, BIPI · March 14, 2025 · 10 min read
Scheduled tasks are a privesc factory
Cron jobs and systemd timers run as a chosen user, usually root, on a predictable schedule. If you can influence what they execute, you control what runs as root. The trick is finding the influence point.
Enumerating cron
- ls -la /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/cron.weekly /etc/cron.monthly
- cat /etc/crontab and per user crontabs in /var/spool/cron/crontabs
- ls -la /var/spool/anacron for anacron jobs
- Read scripts referenced in cron entries, especially those owned by other users
- Check file permissions on each referenced script and its parent directories
Enumerating systemd timers
- systemctl list-timers --all shows every timer and its next run
- For each timer, systemctl cat timer.timer and the matching .service unit
- Check ExecStart paths and the user the service runs as
- ls -la on the binary or script, look for writable group or other
pspy is your friend
pspy by DominicBreuker watches /proc for new processes without needing root. Run pspy64 in a screen session for thirty minutes. You will see every cron and timer fire, every command they invoke, and every environment variable they pass.
Common abuse patterns
- Writable script referenced by a root cron, append a reverse shell line
- Wildcard in a cron command, drop a malicious file with a flag like name
- PATH set to /usr/local/bin:/usr/bin:/bin with a writable /usr/local/bin
- Cron invoking a binary without an absolute path, PATH hijack
- tar with a wildcard in a backup cron, classic --checkpoint-action exploit
Writable systemd unit files
- ls -la /etc/systemd/system /lib/systemd/system /run/systemd/system
- Any writable .service or .timer file is a direct path to root
- Drop user units in ~/.config/systemd/user, then check if they run as a privileged user
- Watch for unit files in non standard paths included via Alias or Wants
Race conditions on cron scripts
If a cron script is owned by root but lives in a directory writable by your user, you can delete and replace it just before the cron fires. Combine with inotifywait to time the swap perfectly.
Detection and hardening
- File integrity monitoring on /etc/cron.* and /etc/systemd/system
- auditd watch on /etc/crontab and /var/spool/cron
- Falco rule on writes to cron and systemd paths by non root users
- Set ProtectSystem=strict and NoNewPrivileges=yes in unit files
- Use absolute paths in every scheduled command, never rely on PATH
If you find a cron and forget to also enumerate systemd timers, you have skipped half the modern Linux scheduling surface.
Operator habit
On every Linux box, run pspy in a screen session as soon as you have a shell. By the time you finish your other enumeration, you will have a log of every privileged process the box ran in the last half hour.
Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.