CoursesLinux hardeningAccess hardening

Scheduled-task hardening

cron & timer privilege boundaries and PATH hijack.

Advanced12 min · lesson 5 of 16

Scheduled tasks are a favourite of attackers on two fronts: as a privilege-escalation path (a root-run job with a weak file permission somewhere in its path) and as persistence (a job that quietly re-launches a payload). The essentials course showed you how to write a cron entry; hardening is about making sure the jobs on your host cannot be turned against you, and knowing exactly which ones exist so a new one stands out.

WRITABLE-SCRIPT ESCALATION
1Root cron job
runs /opt/app/backup.sh as root
2Weak permission
script or its directory is user-writable
3Attacker edits script
plants a payload inside backup.sh
4Cron runs it as root
payload executes with root privilege
5Root achieved
privilege escalation complete
Every file a root job runs, and its directory, must be root-owned and not writable by anyone else.

The writable-script escalation

The classic escalation: a root cron job runs /opt/app/backup.sh, and that script — or the directory containing it — is writable by a lower-privileged user. The attacker edits the script, waits for cron to run it as root, and now has root. The defense is ownership and permissions: every file a privileged job executes, and every directory in its path, must be owned by root and not writable by anyone else. Audit this for each root-scheduled task.

terminal
# audit every root-run scheduled task, then check that what it runs is not writable
$ cat /etc/crontab; ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/
$ sudo crontab -l # root’s own crontab
# every script a root job runs should be root-owned and NOT group/world-writable:
$ ls -l /opt/app/backup.sh
-rwxr-xr-x 1 root root ... /opt/app/backup.sh # good: only root can edit it
$ find /etc/cron* -perm -0002 -o -perm -0020 # any group/world-writable cron content = finding

PATH hijack in scheduled jobs

A subtler version: a root job runs a script that calls a command by bare name (backup instead of /usr/local/bin/backup), and PATH includes a directory an attacker can write to earlier than the real binary. The attacker plants a malicious backup in that directory and cron runs it as root. Two defenses: set a minimal, absolute PATH at the top of the crontab, and require scripts to call commands by full path. This is the same PATH-hijack idea from the privilege-escalation material, applied to automation.

/etc/crontab
# set a safe, minimal PATH so a job cannot resolve a command from a writable dir
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
# and inside scripts, call binaries by absolute path: /usr/bin/python3, not python3

Least privilege and systemd timers

Run scheduled work as the least-privileged user that can do it, not root by reflex — a backup that only needs to read /var/www and write to a backup volume does not need root. And prefer systemd timers over cron for anything you are hardening: a timer runs a service unit, so it inherits all the per-service confinement from the systemd lesson (User=, NoNewPrivileges, ProtectSystem, private tmp), the runs are logged in the journal, and the schedule and the job are separate, reviewable units. cron is fine for simple jobs; timers are the hardened choice.

backup.service + backup.timer
# backup.service — the job, confined like any hardened service
[Service]
Type=oneshot
User=backup # least privilege, not root
NoNewPrivileges=true
ProtectSystem=strict
ExecStart=/usr/local/bin/backup.sh
# backup.timer — the schedule (systemctl enable --now backup.timer)
[Timer]
OnCalendar=*-*-* 03:00:00 # 3am daily; journalctl -u backup.service shows every run
A new scheduled task is a persistence indicator
On a stable host the set of cron jobs and timers changes rarely, so baseline them (the auditd/osquery approach) and alert on additions — a new cron entry or timer, especially one pointing at /tmp, a home directory, or an odd binary, is a classic persistence mechanism. And harden the existing ones: root-owned non-writable scripts, absolute PATHs and command paths, least-privileged users, and systemd timers where confinement matters. The automation that keeps your host running is exactly the automation an attacker wants to hijack.