Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2021-3560 — CVE-2021-3560の詳細な分析。Linux PolKitにおけるローカル権限昇格の脆弱性で、根本原因の分析、エクスプロイトの仕組み、そしてrootアクセスに至る競合状態の実演を含みます。 | Kitploit
ツール/GitHubGitHub/chenaotian/cve-2021-3560
特権昇格脆弱性分析エクスプロイトバイナリ解析学習と教育
GitHubchenaotian/cve-2021-3560

CVE-2021-3560

CVE-2021-3560の詳細な分析。Linux PolKitにおけるローカル権限昇格の脆弱性で、根本原因の分析、エクスプロイトの仕組み、そしてrootアクセスに至る競合状態の実演を含みます。

リポジトリを見る
93224年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2021-3560 PolKit 競合状態 ローカル権限昇格 分析

[toc]

脆弱性の概要

脆弱性ID: CVE-2021-3560

脆弱性スコア:

脆弱性製品: linux PolKit (polkitd)

影響範囲: ソースコード 0.113 で導入;https://www.venustech.com.cn/new_type/aqtg/20210611/22788.html

  • RHEL 8
  • Fedora 21 以降
  • Debian testing (“bullseye”)
  • Ubuntu 20.04

利用条件: linux ローカル;dbus + polkitd が存在

利用効果: ローカル権限昇格

ソースコード入手先:

  • polkit-0.113: https://launchpad.net/debian/+source/policykit-1/0.113-5
  • accountsservice: apt source accountsservice
  • dbus: apt source dbus

環境構築

ubuntu デフォルトイメージ ubuntu-20.04.2 で再現可能: http://old-releases.ubuntu.com/releases/20.04.2/ubuntu-20.04.2-desktop-amd64.iso

脆弱性の原理

脆弱性の発生箇所

まず問題のコードを確認する

/polkit-0.113/src/polkit/polkitsystembusname.c : 388 : polkit_system_bus_name_get_creds_sync

static void
on_retrieved_unix_uid_pid (GObject              *src,
			   GAsyncResult         *res,
			   gpointer              user_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
  {
      ··· ···//成功時のデータ処理
  }
  ··· ···
}

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, }; //data は 0 で初期化
  ··· ···
  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, //コールバック関数
			  &data);
  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, //コールバック関数
			  &data);

  while (!((data.retrieved_uid && data.retrieved_pid) || data.caught_error))
    g_main_context_iteration (tmp_context, TRUE); //バス側の処理完了を待つ、uid と pid が両方処理されるかエラーになるまで

  if (out_uid)
    *out_uid = data.uid;
  if (out_pid)
    *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;
}

polkit_system_bus_name_get_creds_sync 関数では、特定のリクエストに対する認証を行います(具体的なロジックのシナリオは後述)。org.freedesktop.DBus バスを介して GetConnectionUnixUser メソッドと GetConnectionUnixProcessID メソッドを順に呼び出します。これらのメソッドは org.freedesktop.DBus バスによって提供され、リクエストプロセスの PID とユーザー UID を取得し、コールバック関数 on_retrieved_unix_uid_pid に渡してデータを処理します。その後、バス側の処理が完了するまでブロックします。

on_retrieved_unix_uid_pid 関数では、バスが返した結果に応じて異常(error?)を設定するかどうかを判断し、異常フラグを設定します。成功した場合は、ユーザー UID またはプロセス PID をそのまま返します。しかし polkit_system_bus_name_get_creds_sync 関数では、バスの戻りを待ってブロック解除した後(処理完了のフラグは UID と PID の両方が処理されたか、異常が発生したかのいずれか)、つまりバスからの戻りは論理的には3種類: ユーザーUIDが0(特権ユーザー)、ユーザーUIDが0以外(通常ユーザー)、異常。 しかし後続の処理では異常を処理せず、上位に返す out_uid をバスが返した data.uid にそのまま設定し、ret を TRUE に設定しています:

  while (!((data.retrieved_uid && data.retrieved_pid) || data.caught_error))
    g_main_context_iteration (tmp_context, TRUE); //バス側の処理完了を待つ、uid と pid が両方処理されるかエラーになるまで

  if (out_uid)
    *out_uid = data.uid;
  if (out_pid)
    *out_pid = data.pid;
  ret = TRUE; //とにかく TRUE?

しかし、DBUS バス側で例外が発生し、コールバック関数が異常フラグを設定しただけで data を処理せずに戻ってしまうケースが考慮されていません。data は 0 で初期化されているため、後続で out_uid が 0、すなわち特権ユーザーとして設定されてしまいます。

では、この問題のある polkit_system_bus_name_get_creds_sync 関数はどこで使われるのでしょうか。

トリガーパス

脆弱性の発生点は polkitd プロセス内です:

polkit はアプリケーションレベルのツールセットで、権限ルールを定義・監査することで、異なる優先度のプロセス間の通信を実現します。制御判断は統一フレームワークに集中し、低優先度プロセスが高優先度プロセスにアクセスする権限があるかどうかを決定します。

簡単に言えば、バックグラウンドで動作する root プロセスであり、プロセス間通信を介して、他の低権限プロセスが高権限プロセスが提供する機能にアクセスする際の権限判断を行います。このプロセスは gdb でアタッチすると再起動するため、ソースコードレベルで分析し、脆弱性関数のトリガーパスを見つける必要があります:

polkitd は gio DBUS プロセス間通信フレームワークを多用しています。事前にマニュアルを確認し、いくつかの重要な関数を把握しておくとよいでしょう。

次に polkitd の脆弱性トリガーパスを分析します。

  1. まず main:

    polkit-0.113\src\polkitbackend\polkitd.c : 155 : main

    int
    main (int    argc,
          char **argv)
    {
      ··· ···
      ··· ···
    
      loop = g_main_loop_new (NULL, FALSE);
    
      sigint_id = g_unix_signal_add (SIGINT,
                                     on_sigint,
                                     NULL);
    
      name_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
                                      "org.freedesktop.PolicyKit1",  //バス名を登録
                                      G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
                                        (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
                                      on_bus_acquired, //バスにアクセスされたときのコールバック
                                      on_name_acquired,
                                      on_name_lost,
                                      NULL,
                                      NULL);
    
      g_print ("Entering main event loop\n");
      g_main_loop_run (loop); //ループ開始
      ··· ···
      ··· ···
    }
    
  2. org.freedesktop.PolicyKit1 というバス名を登録し、3つのコールバック関数があります。特に on_bus_acquired に注目します。これはバスにアクセスされたときに呼び出されます。

  3. on_bus_acquired 関数では、直接 polkit_backend_authority_register という型登録関数を呼び出します。

  4. polkit_backend_authority_register 関数では、インターフェースオブジェクト org.freedesktop.PolicyKit1.Authority を登録し、コールバック関数テーブル server_vtable を渡します。脆弱性のトリガーポイントはこのコールバック関数テーブル内の一つです:

    policykit-1_0.113.orig\polkit-0.113\src\polkitbackend\polkitbackendauthority.c : 1333 : server_vtable

    static const GDBusInterfaceVTable server_vtable =
    {
      server_handle_method_call, //コールバック関数
      server_handle_get_property,
      NULL, /* server_handle_set_property */
    };
    static void
    server_handle_method_call (GDBusConnection        *connection,
                               const gchar            *sender,
                               const gchar            *object_path,
                               const gchar            *interface_name,
                               const gchar            *method_name,
                               GVariant               *parameters,
                               GDBusMethodInvocation  *invocation,
                               gpointer                user_data)
    {
      Server *server = user_data;
      PolkitSubject *caller;
    
      caller = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation));
    
      if (g_strcmp0 (method_name, "EnumerateActions") == 0)
        server_handle_enumerate_actions (server, parameters, caller, invocation);
      else if (g_strcmp0 (method_name, "CheckAuthorization") == 0)
        server_handle_check_authorization (server, parameters, caller, invocation); //脆弱性関数のパスはここ
      ··· ···
      ··· ···
    }
    

    他のプロセスがバスを介して CheckAuthorization メソッドを呼び出すと、server_handle_check_authorization 関数が呼び出されます。

  5. server_handle_check_authorization 関数内で polkit_backend_authority_check_authorization を呼び出します。

  6. polkit_backend_authority_check_authorization 関数内でコールバックを介して klass->check_authorization を呼び出します。後者は登録された関数 polkit_backend_interactive_authority_check_authorization です:

ツールをダウンロード