learn/phase-2/p2-w6/lesson 08
Milestone 6 · lesson 8

Scheduled Tasks: cron & systemd Timers

Hands-on. Read and write cron schedules, meet systemd timers, and enumerate both, a favourite privesc and persistence spot.
Lab: Scheduled for Root

Enumerate the scheduled tasks, find the script a root cron job runs, and read the flag inside it.

What you'll learn

  • Read and write a five-field cron schedule, and use the @reboot/@daily shortcuts.
  • Tell the difference between a user crontab and the system crontab / cron.d files.
  • Explain how a systemd timer works: a .timer (when) paired with a .service (what).
  • List active timers with systemctl list-timers and read a schedule from OnCalendar.
  • Enumerate every scheduled task on a box, the first place to look for privilege escalation and attacker persistence.

Scheduled Tasks: cron & systemd Timers

A lot of what a Linux box does happens on a schedule with nobody watching: backups at 2 AM, log rotation nightly, updates every morning. Two systems handle this, the old classic cron and the modern systemd timers. You need to read both, because scheduled tasks are also one of the first places an attacker looks, a job that runs as root plus a script you can edit equals instant root.

cron: the classic scheduler

cron runs commands on a repeating schedule. Each line is a cron job, and the schedule is five time fields followed by the command:

┌───────── minute        (0,59)
│ ┌─────── hour          (0,23)
│ │ ┌───── day of month  (1,31)
│ │ │ ┌─── month         (1,12)
│ │ │ │ ┌─ day of week   (0,7, 0 and 7 are Sunday)
│ │ │ │ │
* * * * *  command-to-run

A * means "every". Read these examples until the pattern clicks:

0 2 * * *      /opt/backup.sh       # 02:00 every day
*/5 * * * *    /usr/bin/collect     # every 5 minutes
30 8 * * 1     /opt/report.sh       # 08:30 every Monday (1 = Mon)
0 0 1 * *      /opt/monthly.sh      # midnight on the 1st of each month

There are handy shortcuts that replace all five fields:

@reboot   /home/me/start.sh    # once, each time the box boots
@daily    /opt/nightly.sh      # once a day (same as 0 0 * * *)
@hourly   ...   @weekly   ...   @monthly   ...

Where cron jobs live

  • Your own crontab , per-user, edited with crontab -e, listed with crontab -l. These lines have no user field (they run as you).
  • The system crontab , /etc/crontab and drop-in files in /etc/cron.d/. These add an extra user field ("run this as root").
  • Run-parts directories , anything dropped in /etc/cron.daily/, /etc/cron.hourly/, /etc/cron.weekly/, /etc/cron.monthly/ runs on that cadence.
crontab -l                 # list YOUR cron jobs
crontab -e                 # edit them
cat /etc/crontab           # the system-wide schedule (has a user column)
ls -la /etc/cron.d /etc/cron.daily   # more places jobs hide

cron's output isn't shown on screen; jobs usually log to the system log (journalctl or /var/log/syslog), or email the user, which is why job lines often end in >> logfile 2>&1.

systemd timers: the modern way

Newer systems increasingly replace cron with systemd timers. A timer always comes in two pieces:

  • a .service unit , what to run,
  • a .timer unit , when to run it.

backup.service (the what):

[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/opt/backup.sh

backup.timer (the when):

[Unit]
Description=Run the backup nightly

[Timer]
OnCalendar=*-*-* 02:15:00      # every day at 02:15 (cron-like calendar)
Persistent=true               # if the box was off, catch up on next boot

[Install]
WantedBy=timers.target

You turn it on like any unit, and inspect the schedule:

systemctl enable --now backup.timer    # enable + start it
systemctl list-timers                  # every active timer, and when it next fires
systemctl status backup.timer

OnCalendar is the cron-style "at this wall-clock time" schedule; timers can also fire relative to events with OnBootSec= (after boot) or OnUnitActiveSec= (after the last run). The pay-off over cron: proper logging in journald, dependencies on other units, a randomised delay to avoid thundering herds (RandomizedDelaySec), and catch-up runs with Persistent=true.

cron vs systemd timers

cronsystemd timer
Define withone crontab linea .timer + a .service
Schedule syntax* * * * *OnCalendar=, OnBootSec=
List themcrontab -l, cat /etc/crontabsystemctl list-timers
Loggingsyslog / emailjournald (journalctl -u name)
Missed runsskippedcaught up (Persistent=true)

Both still exist everywhere, so learn to read both.

Enumerating scheduled tasks (the security bit)

When you land on a box, scheduled tasks are a top thing to enumerate, for two reasons: privilege escalation (a job that runs as root, calling a script you can write to, is a direct path to root) and persistence (attackers add a cron job or timer so their access survives a reboot). The sweep:

crontab -l                          # your jobs
cat /etc/crontab                    # system jobs (note the user column)
ls -la /etc/cron.d /etc/cron.*      # drop-in and run-parts jobs
systemctl list-timers --all         # every timer
# then: are any scripts those jobs run world-writable?
ls -la /opt/backup/run.sh

A root cron entry like * * * * * root /opt/backup/run.sh, where run.sh is writable by your user, means you can put any command in that script and it will run as root within a minute. You'll use exactly this in the Privilege Escalation lesson.

Try it (terminal)

  1. crontab -l , read your own scheduled jobs.
  2. cat /etc/crontab , the system schedule, spot the extra user column.
  3. systemctl list-timers , the modern equivalent, and when each next runs.

Why this matters

Scheduled tasks are how a system takes care of itself, and how both defenders and attackers get things to run automatically. Reading a cron line at a glance and knowing where every job hides, crontabs, /etc/cron.d, and systemd timers, is core Linux fluency, and enumerating them is one of the highest-value moves the moment you have a foothold.

Check your understanding

6 questions

Type an answer and press Check. Grading is keyword-based and forgiving, so short answers are fine.

  1. 1

    Write the command that lists the current user's cron jobs.

  2. 2

    In the cron line 0 2 * * * /opt/backup.sh, at what time does the job run, and how often?

  3. 3

    Write the five-field cron schedule that runs a job every 5 minutes.

  4. 4

    Write the cron shortcut that runs a job once each time the machine boots.

  5. 5

    Which command lists every active systemd timer, with when each next fires?

  6. 6

    A systemd timer is made of two unit files. Name them and what each defines.