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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
GhostLock-GOT-W29 — HUAWEI MatePad Pro 11 GOT-W29 における CVE-2026-43499 (GhostLock) の研究 | Kitploit
ツール/GitHubGitHub/zzzxxxxxxxxxx/ghostlock-got-w29
特権昇格脆弱性分析エクスプロイトリバースエンジニアリングモバイルセキュリティバイナリエクスプロイト
GitHubzzzxxxxxxxxxx/ghostlock-got-w29

GhostLock-GOT-W29

HUAWEI MatePad Pro 11 GOT-W29 における CVE-2026-43499 (GhostLock) の研究

リポジトリを見る
613019日前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2026-43499 (GhostLock) — HUAWEI MatePad Pro 11 GOT-W29

GOT-W29(HarmonyOS 4.0、kernel 4.19.157-perf+)における CVE-2026-43499(rtmutex/futex-PI スタック UAF、"GhostLock")の権限昇格研究。

最終結論

  1. 脆弱性は実在し、トリガー可能:値保持 PI リングにより FUTEX_CMP_REQUEUE_PI が -EDEADLK を返し、 ロールバック経路が remove_waiter() の current != waiter->task クリーンアップバグを発動させる(本カーネル kernel/locking/rtmutex.c:1110-1112、上流修正 3bfdc63936dd)。waiter の pi_blocked_on がダングリング(自身のカーネルスタック E-0x1b0 の rt_waiter を指す)。
  2. 書き込みプリミティブは純ユーザーランドでエンドツーエンド検証済み(QEMU kernel.patched、GDB/KPM 注入なし): EDEADLK ダングリング → setsockopt(SOL_IP, MCAST_BLOCK_SOURCE, group_source_req 0x108) で fake waiter を投入(copy 着地点 E-0x210、waiter を buf+0x60 に置くことでちょうど E-0x1b0 をカバー) → sched_setattr で walk を発動 → rb_erase が sysctl_bootid を書き込み、ツールが自己検証 write_ok=1(boot_id 上位 8 バイト = 0xffffff800b412320)。
  3. 初期の「投入デッドロック」結論は撤回済み:旧スキャンは sock_setsockopt の 0x80 フレームを setsockopt チェーンに算入していた。逆アセンブル + QEMU 実測で __arm64_sys_setsockopt は level != SOL_SOCKET に対して直接 blr ops->setsockopt し、sock_setsockopt を経由しないことを確認。 修正後の do_ip_setsockopt コピー深度 = 0x210(旧判定 0x290)で、ジオメトリが適合。 除外済みのメカニズム:pselect/select、ptrace、import_iovec、ppoll、SCTP(実測 0x158)。
  4. デバイス側の残作業:MCAST setsockopt の SELinux 許可検証(mrx は EMUI 下で shell 権限で同種のキャリアを使い権限昇格に成功しており、実行可能と予想)、実機での戻り経路/park 挙動の再確認 (KPM で W を直接観測可能)、および後利用チェーンの SELinux 適応(メカニズムは実装済み、--root 参照)。 HKIP 差異:GOT-W29 のカーネルシンボルテーブルとイメージに hkip_*/ hypervisor フックはなく、全イメージ 97 箇所の hvc 命令も cred/cap/SELinux 経路には存在しない (KVM/SMCCC/デバッグ転送ドライバのみ)。つまり mrx の hypervisor xid 保護は本機には おそらく存在せず、実機では通常の root 手順で直接進められる。

デバイス

項目値
型番HUAWEI MatePad Pro 11 GOT-W29
SoCQualcomm kona (SM8250, Snapdragon 870)
システムHarmonyOS 4.0 (104.0.0.136)
カーネル4.19.157-perf+(boot.elf 逆アセンブル + firmware/symtab.txt)
VA39-bit, 4K pages, KASLR on

脆弱性とトリガー(最終版)

トリガー前提

  • shell 権限:adb shell または Shizuku のいずれでも可。
  • ファーウェイのバックグラウンド管理サービス 2 つを無効化し、shell プロセスにルート cpuset を取得させる(そうしないとトリガーチェーンが目標経路に入らない):
pm disable-user com.huawei.powergenie
pm disable-user com.huawei.iaware

メカニズム:PI リング(waiter→target→owner→chain→waiter)を生成し FUTEX_CMP_REQUEUE_PI を EDEADLK ロールバックに走らせる。ロールバック中に remove_waiter(lock, waiter) が current(requeue スレッド)で waiter->task ではなくクリーンアップする: rt_mutex_dequeue は実 waiter ノードを除去するが、waiter の pi_blocked_on はクリアされない (current->pi_blocked_on = NULL)。これがカーネルスタックの rt_waiter を指すダングリングポインタとなる。

値保持リング(probe リング、実測で安定して -EDEADLK):

  • waiter:FUTEX_LOCK_PI(chain) で chain を保持;FUTEX_WAIT_REQUEUE_PI(wait, 0, target)
  • owner:FUTEX_LOCK_PI(target) で target を保持;FUTEX_LOCK_PI(chain) がブロック
  • main:FUTEX_CMP_REQUEUE_PI(wait, 1, target) → -EDEADLK
  • waiter がタイムアウトで戻った後(WAIT_REQUEUE_PI 2s)、ダングリング pi_blocked_on がスタック上に残る

注意:旧「self-own」トリガー、edeadlk_probe variant 11 の -EDEADLK はいずれも owner==task の早期リターン(rtmutex.c:1035)であり、ダングリングポインタを生成しないため無効。

成果

KASLR リーク(perf_event_open、shell 権限で実行可能)

perf_event_paranoid=-1 下で perf_event_open(PERF_SAMPLE_IP, exclude_user=1) がカーネルテキストクラスタをサンプリングし、既知のシンボルオフセットに整列させて slide を取得:

samples=27651 kernel_ips=1685 lo=0xffffff948728176c hi=0xffffff9488ebfc7c
KASLR slide=0x147f200000    runtime _stext=0xffffff9487280800

ツール:tools/perf_kaslr.c。

EDEADLK トリガー(ダングリングポインタの確立)

[M] CMP_REQUEUE_PI ret=-1 errno=35 (EDEADLK!)
[W] WAIT_REQUEUE_PI ret=-1 errno=110 (ETIMEDOUT)  ← waiter が戻り、pi_blocked_on がダングリング

ツール:tools/edeadlk_probe.c。

書き込みプリミティブと投入チェーン(QEMU エンドツーエンド検証、注入なし)

rt_mutex_adjust_prio_chain の walk がダングリング pi_blocked_on の位置の fake rt_waiter を読む:

  • [3] next_lock == waiter->lock(lock = empty_zero_page の独立スロット、下記参照)
  • [5] raw_spin_trylock(&lock->wait_lock) がゼロロックで成功
  • [7] rt_mutex_dequeue → rb_erase 単一左子経路:*(rb_left) = rb_parent_color → 書き込み値 0xffffff800b412320(&loggers[0][1])を sysctl_bootid + 8 に書き込む
  • [9] ownerless でクリーンにリターン

owner-ful ページ / prepare_skb_payload / kernelsnitch は不要。fake rt_mutex はwalk をまたいで同じスロットを再利用できない:walk 終了時に waiters.root/leftmost がロック内に今回の waiter を指したまま残り、 2 回目の walk が旧ノードを読むと前回解放済みのカーネルスタックをデリファレンスし、 rt_mutex_top_waiter() の BUG_ON(w->lock != lock) を発動する(QEMU 実測:--verify-all の 2 番目のテストで直接 BUG)。実装では attempt ごとに empty_zero_page + n*0x20 (計 128 スロット、SLIDE_LOCK_STRIDE/SLOTS)を取得し、天然で全ゼロかつ相互汚染なし。

QEMU(kernel.patched、nokaslr、--probe-cycle --verify-all)のツール自己検証出力:

4.483 237 [+] slide write boot_id raw=00000000000000002023410b80ffffff lo=0 hi=ffffff800b412320 exp_lo=0 exp_hi=ffffff800b412320 ok=1
4.547 1   [+] slide write test PASSED
6.583 240 [+] slide leaf boot_id raw=00000000000000002023410b80ffffff lo=0 hi=ffffff800b412320 exp_lo=0 exp_hi=0 ok=1
6.636 1   [+] slide leaf test PASSED
8.671 243 [+] slide read boot_id raw=100000002401000030d74c0b80ffffff lo=0000012400000010 hi=ffffff800b4cd730 exp_lo=0000012400000010 exp_hi=ffffff800b4cd730 ok=1
8.724 1   [+] slide read test PASSED
10.811 1  [+] slide restore test PASSED
10.811 1  [+] slide verify all PASSED

(各 attempt の requeue=-1/35 trigger=0/0 wait=-1/110 carrier=-1/22 は一貫: EDEADLK、walk 成功、hrtimer タイムアウト、キャリアコピー成功後に偽アドレスグループにより EINVAL を返す。)

注意:検証ターゲットは boot_id + 8 に書き込む。proc_do_uuid() は bootid[8] == 0 のとき UUID 全体を再生成するため、下位 8 バイトへの書き込みは検証読み取り自体に上書きされる(QEMU 実測で確認)。

書き込みプリミティブの形状(--verify-all 全網羅自己チェック)

形状fake waiter tree の 3 ワード効果
pointer(rb_erase Case 2:単一左子)pc=value, right=0, left=target*(target) = value(64 ビット全量、色ビット保持);副作用 *(value+8) = target、したがって value は読み取り可能かつその +8 が犠牲可能でなければならない
leaf(Case 1:子なし)pc=target-8, right=0, left=0*(target) = 0;クリーンな書き込み 1 回のみ(副作用なし)、pc 下位ビット=0 → RED → rebalance は発動しないが、__rb_change_child が *(target-8) を 1 回読む

読み取りプリミティブ(mrx-w09 の boot_id チャネルから移植)

random_table[4].data(= &sysctl_bootid、link 0xffffff800b4cd730;.rela.dyn 内の唯一の addend=0xffffff800b7f8b64 の R_AARCH64_RELATIVE で確認) を書き込みプリミティブでターゲットアドレス A に変更した後、/proc/sys/kernel/random/boot_id を読むと [A, A+16) が返る。注意:

  • proc_do_uuid() は ((u8 *)A)[8] == 0 のとき 16 バイト UUID を再生成する(かつ A を書き換える)。 読み取りウィンドウの byte 8 は非ゼロでなければならない;
  • ポインタ書き込みの副作用が A+8 = .data スロットアドレスを書き込むため、読み戻しの上位半分は常にそのスロットアドレスとなる。 正確に 16 バイト読む必要がある場合はこの位置を避けるべき。

--verify-read 自己チェック:.data を boot_id ctl_table エントリ +0x10(maxlen=16, mode=0444 → 定数 0x0000012400000010)に向けて読み戻し、その後 restore ステップで sysctl_bootid に戻す。

エンドツーエンド権限昇格(uid 2000 → 0、QEMU 検証済み)

--escalate(デバイス shell 経路と同型、全行程 RT なし):

  1. perf で current をリーク:PERF_COUNT_SW_CPU_CLOCK + PERF_SAMPLE_REGS_INTR (arm64 33 レジスタ)、トリガーは nanosleep(1µs)(単一タスク時は sched_yield が __schedule に入らない)。__schedule 内の x27 を取得:mrs x27, sp_el0 は +0x40 だが、 +0x68 の ldr w8, [x27, 0x50]! が x27 を 0x50 押し上げるため減算して戻す必要がある。候補は 64 バイトアラインメントを要求。
  2. comm 検証:読み取りプリミティブで候補 task+0x990 を読み、"ghostloc" と等しい場合のみ続行 (読み取りの副作用で comm 上位 8 バイトが破壊されるが、プロセス名表示にのみ影響)。
  3. cred ポインタ書き込み:task+0x980(real_cred) / task+0x988(cred) ← init_cred (0xffffff800b42e9c0)、その後本プロセスの getuid()==0。
  4. 修復:ポインタ書き込みの副作用で init_cred+8(gid) がターゲットアドレスに上書きされるため、leaf ゼロ書きで 復元;最後に boot_id .data を sysctl_bootid に戻す。

QEMU 実測(--no-rt --attempts 4、uid 2000 から開始):

escalate: candidate 1/1 task=ffffffc07a373240 (n=12)
slide read8 boot_id ... lo=636f6c74736f6867 ...  ok=1        # "ghostloc" 確認
slide escalate-cred attempt 1 ok=1 ... target=ffffffc07a373bc8
slide child pid=246 uid=0 ...                                # 以降の子プロセスは root
init: ghostlock_exe exited status=0x0 (SUCCESS)              # wrapper 独立終了コードマーカー

失敗モード(flaky):数 attempt に 1 回程度、walk が rt_mutex_adjust_prio_chain の raw_spin_trylock リトライループでスタックする(fake waiter が 戻り経路で clobber される)。この attempt はタイムアウトする。--attempts N でリトライ(デバイス側も mrx 同様:成功するまでリトライ)。

後利用チェーン(--root、端局メカニズムは QEMU でテスト可能)

ツールをダウンロード