Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2021-3560 — ein zuverlässiger C-basierter Exploit und Writeup für CVE-2021-3560. | Kitploit
Tools/GitHubGitHub/hakivvi/cve-2021-3560
Authentifizierung & AutorisierungPrivilege EscalationSchwachstellenanalyseExploitationPenetrationstestsRed Teaming
GitHubhakivvi/cve-2021-3560

CVE-2021-3560

ein zuverlässiger C-basierter Exploit und Writeup für CVE-2021-3560.

Repository anzeigen
4012vor 5 JahrenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2021-3560

ein zuverlässiger C-basierter Exploit für CVE-2021-3560.

Zusammenfassung:

Gestern bin ich auf diesen Blogbeitrag von Kevin Backhouse gestoßen (der diese Schwachstelle entdeckt hat), ich habe die im Blogbeitrag bereitgestellten Bash-Befehle ausprobiert und zu meiner Überraschung funktionierten sie auf meiner Kali Linux-Box!

CVE-2021-3560 ist ein Authentifizierungsumgehung auf polkit, die es einem unprivilegierten Benutzer ermöglicht, privilegierte Methoden über DBus aufzurufen. Der PoC nutzt diesen Fehler aus, um zwei privilegierte Methoden von accountsservice aufzurufen (CreateUser und SetPassword), was es uns ermöglicht, einen privilegierten Benutzer zu erstellen und dann ein Passwort zu setzen.

polkit prüft, ob der Aufrufer berechtigt ist, eine solche Methode aufzurufen. Dazu wird zunächst die Benutzer-ID des Aufrufers überprüft. Ist diese Null, wird der Aufrufer als root angenommen und die Aktion ohne Authentifizierungsanforderung erlaubt. Andernfalls wird nach dem Passwort des Benutzers gefragt.

polkit_system_bus_name_get_creds_sync() ruft zwei Methoden auf, um die UID und PID des Aufrufers zu erhalten: GetConnectionUnixUser und GetConnectionUnixProcessID. Das Ergebnis dieser Aufrufe wird in die data-Struktur vom Typ AsyncGetBusNameCredsData geschrieben (diese Struktur wird auf 0 initialisiert) durch die Callback-Funktion on_retrieved_unix_uid_pid(), und polkit_system_bus_name_get_creds_sync() blockiert, während sie darauf wartet, dass die Callback-Funktion einen Fehler oder die UID und PID setzt.

root@kitploit:~
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);

Die Callback-Funktion on_retrieved_unix_uid_pid() wird nach jedem Methodenaufruf aufgerufen, um die Antwort (UID und PID) abzurufen oder einen Fehler zu setzen. Diese Funktion ruft g_dbus_connection_call_finish() auf, um die Antwort abzurufen, wenn ein Fehler aufgetreten ist. Dann setzt sie data.caught_error auf TRUE und kehrt zurück (data.uid und data.pid sind weiterhin auf 0 gesetzt). Andernfalls weist sie den abgerufenen Wert (UID oder PID) data.uid oder data.pid zu (abhängig davon, welcher Wert abgerufen wurde) und kehrt zurück.

root@kitploit:~
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;
	}
    }
}

Die Methoden GetConnectionUnixUser und GetConnectionUnixProcessID geben die UID und PID zurück, falls gefunden (der Aufruferprozess ist noch mit dem Bus verbunden), oder einen Fehler, falls ein Fehler aufgetreten ist (z.B. der Aufruferprozess wurde beendet).

Sobald data.uid und data.pid gesetzt sind oder data.caught_error gesetzt ist, fährt die Funktion polkit_system_bus_name_get_creds_sync() fort. Hier liegt die Schwachstelle: polkit_system_bus_name_get_creds_sync() gibt keinen Fehler zurück, wenn data.caught_error gesetzt ist, sondern setzt stattdessen den Wert von data.uid in out_uid und gibt TRUE zurück (selbst wenn data.caught_error gesetzt ist). out_pid ist ein Zeiger auf eine guint32-Variable, die an polkit_system_bus_name_get_creds_sync() übergeben wird, wenn sie von aufgerufen wird:

root@kitploit:~
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;

Ausnutzung:

Wenn ein Prozess A eine privilegierte Methode über DBus aufruft, dann überprüft polkit die UID des Aufrufers. Wenn Prozess A sofort nach dem Senden der Nachricht beendet wird, geben die Methoden GetConnectionUnixUser und GetConnectionUnixProcessID einen Fehler zurück, da der Aufruferprozess nicht mehr existiert. Die Callback-Funktion on_retrieved_unix_uid_pid() setzt data.caught_error auf TRUE, data.uid und data.pid bleiben unverändert (was bedeutet, dass beide auf 0 gesetzt sind, da die Datenstruktur auf 0 initialisiert wurde). Die Funktion polkit_system_bus_name_get_creds_sync() setzt die Ausführung fort und setzt out_uid auf data.uid (0) und gibt TRUE zurück.

Einige Funktionen geben weiterhin die gefälschte UID (0) zurück, bis polkit_backend_session_monitor_get_user_for_subject() user_of_subject (aus der gefälschten UID erstellt) an die Funktion check_authorization_sync() zurückgibt, die prüft, ob die UID root ist, indem sie identity_is_root_user(user_of_subject) aufruft. Dies gibt TRUE zurück und Prozess A wird autorisiert.

root@kitploit:~
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:

Ich entschied mich, einen PoC mit der dbus C API zu schreiben. Ich habe sleep() nicht verwendet, während ich darauf wartete, dass die Nachricht an den Zieldienst gesendet wird, sondern DBus-Funktionen bieten einen Timeout-Parameter. Durch (Miss-)Brauch dieses Parameters können wir die Funktion dazu zwingen, gleich nach dem Senden der Nachricht zurückzukehren und dann den Prozess zu beenden. Dies ermöglicht es uns, die Schwachstelle in polkit auszunutzen und die Authentifizierung zu umgehen. Für technische Details siehe diesen Blogbeitrag.

Ausführen:

  1. Exploit kompilieren:
root@kitploit:~
user@host: gcc -Wall exploit.c -o exploit $(pkg-config --libs --cflags dbus-1)
  1. Exploit ausführen:
root@kitploit:~
user@host: ./exploit
  • Ausgabe:
root@kitploit:~
user@host:~/CVE-2021-3560-testing$ gcc -Wall exploit.c -o exploit $(pkg-config --libs --cflags dbus-1)
user@host:~/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.

root@host:/home/user/CVE-2021-3560-testing# id
uid=0(root) gid=0(root) groups=0(root)
Tool herunterladen
polkit_system_bus_name_get_user_sync()