From 06f4cf13b4a34a66512f880984da2bc1d2e2a0d0 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 09:46:36 -0800 Subject: [PATCH 01/10] Fix spacing bug --- hash2phone/hashmap_gen.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hash2phone/hashmap_gen.py b/hash2phone/hashmap_gen.py index 45e552b..b2792c7 100644 --- a/hash2phone/hashmap_gen.py +++ b/hash2phone/hashmap_gen.py @@ -12,12 +12,11 @@ import psycopg2 if len(sys.argv)!=2: - print("\nUsage:\t",sys.argv[0],"<4-digit phone prefix>") - print("\nEx.:Calculate hashmap for range +12130000000 -- +12139999999:") - print(sys.argv[0],"1213") - print("\n\n"); - sys.exit() - + print("\nUsage:\t",sys.argv[0],"<4-digit phone prefix>") + print("\nEx.:Calculate hashmap for range +12130000000 -- +12139999999:") + print(sys.argv[0],"1213") + print("\n\n"); + sys.exit() prefix = sys.argv[1] num=int(prefix+"0000000") From f3d4a39a9ff2f68e78d81bfac344561792176b8c Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 10:01:04 -0800 Subject: [PATCH 02/10] Don't error if val_len empty (seen tag_len=2 i=52) --- ble_read_state.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ble_read_state.py b/ble_read_state.py index fb3cfdb..ec49c4e 100644 --- a/ble_read_state.py +++ b/ble_read_state.py @@ -504,7 +504,10 @@ def parse_ble_packet(data): i = 0 while i < len(data): tag = data[i:i + tag_len] - val_len = int(data[i + tag_len:i + tag_len + 2], 16) + try: + val_len = int(data[i + tag_len:i + tag_len + 2], 16) + except: + pass value_start_position = i + tag_len + 2 value_end_position = i + tag_len + 2 + val_len * 2 parsed_data[tag] = data[value_start_position:value_end_position] From dc0fd56a5ca00799a0dfcea6f5a4e4f964ee76ab Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 10:24:47 -0800 Subject: [PATCH 03/10] iOS13 can also be code 0x1c (13.2.2 iPad Pro) --- ble_read_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ble_read_state.py b/ble_read_state.py index ec49c4e..5e87e96 100644 --- a/ble_read_state.py +++ b/ble_read_state.py @@ -468,7 +468,7 @@ def parse_os_wifi_code(code, dev): if dev == 'MacBook': return ('Mac OS', 'On') else: - return ('iOS12', 'On') + return ('iOS12/13', 'On') if code == '18': if dev == 'MacBook': return ('Mac OS', 'Off') From 13bd2eeeb893bd5f8272bfdb746d37d0303089fd Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 10:26:24 -0800 Subject: [PATCH 04/10] Add more verbosity for device --- ble_read_state.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ble_read_state.py b/ble_read_state.py index 5e87e96..531e062 100644 --- a/ble_read_state.py +++ b/ble_read_state.py @@ -551,6 +551,8 @@ def parse_nearby(mac, header, data): for dev in dev_sig: if dev in header: dev_val = dev_sig[dev] + if args.verb: + dev_val += '-'.join(header) os_state, wifi_state = parse_os_wifi_code(result['wifi'], dev_val) if args.verb: wifi_state = '{}({})'.format(wifi_state, result['wifi']) From 6bc72bb2ed398727ffffc614506f7b92eace28c1 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 10:45:11 -0800 Subject: [PATCH 05/10] Add (multiple) MAC following from command line --- ble_read_state.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ble_read_state.py b/ble_read_state.py index 531e062..a67ea9c 100644 --- a/ble_read_state.py +++ b/ble_read_state.py @@ -32,6 +32,7 @@ urllib3.disable_warnings() parser = argparse.ArgumentParser(description=help_desc, formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('-c', '--check_hash', action='store_true', help='Get phone number by hash') +parser.add_argument('-f', '--follow', action='append', type=str, help='Follow MAC address(es), can be done multiple times') parser.add_argument('-n', '--check_phone', action='store_true', help='Get user info by phone number (TrueCaller/etc)') parser.add_argument('-r', '--check_region', action='store_true', help='Get phone number region info') parser.add_argument('-l', '--check_hlr', action='store_true', @@ -289,6 +290,14 @@ 'airdrop': '05', } +if args.follow: + # format MAC address to uppercase split by ':'s + for i in range(len(args.follow)): + mac = args.follow[i] + mac = mac.upper().replace('-', ':') + if ':' not in mac: + mac = ':'.join([mac[i:i+2] for i in range(0, len(mac), 2)]) + args.follow[i] = mac if args.check_hash: if not (hash2phone_url or path.isfile(hash2phone_db)): print("You have to specify hash2phone_url or create phones.db if you want to match hashes to phones. See howto here: https://github.com/hexway/apple_bleee/tree/master/hash2phone") @@ -719,12 +728,13 @@ def read_packet(mac, data_str): # os_state = '' # wifi_state = '' # unkn = '' + if args.follow and mac not in args.follow: + return if apple_company_id in data_str: header = data_str[:data_str.find(apple_company_id)] data = data_str[data_str.find(apple_company_id) + len(apple_company_id):] packet = parse_ble_packet(data) - # print(data) if ble_packets_types['nearby'] in packet.keys(): parse_nearby(mac, header, packet[ble_packets_types['nearby']]) if ble_packets_types['handoff'] in packet.keys(): From f354136162db30980bfd3b25261e85fb0e7d5bfa Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 11:21:03 -0800 Subject: [PATCH 06/10] Add packet dumps with additional verbosity -vv --- ble_read_state.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/ble_read_state.py b/ble_read_state.py index a67ea9c..4e6ac5f 100644 --- a/ble_read_state.py +++ b/ble_read_state.py @@ -40,7 +40,7 @@ parser.add_argument('-s', '--ssid', action='store_true', help='Get SSID from requests') parser.add_argument('-m', '--message', action='store_true', help='Send iMessage to the victim') parser.add_argument('-a', '--airdrop', action='store_true', help='Get info from AWDL') -parser.add_argument('-v', '--verb', action='store_true', help='Verbose output') +parser.add_argument('-v', '--verb', action='count', help='Verbose output') parser.add_argument('-t', '--ttl', type=int, default=15, help='ttl') args = parser.parse_args() @@ -735,6 +735,23 @@ def read_packet(mac, data_str): header = data_str[:data_str.find(apple_company_id)] data = data_str[data_str.find(apple_company_id) + len(apple_company_id):] packet = parse_ble_packet(data) + + if args.verb >= 2: + ptype = [] + for packet_type, packet_id in ble_packets_types.items(): + if packet_id in packet.keys(): + ptype.append(packet_type) + if len(ptype): + ptype = ','.join(ptype) + else: + ptype = '?' + ptype += '({})'.format(','.join(packet.keys())) + pdata = data + zeroes = 11 + if pdata.endswith('00' * zeroes): + pdata = "{} 00x{}".format(pdata[:-zeroes * 2], zeroes) + print("apple t={:20s} {} h={} o={} d={}".format(ptype, mac, header, data_str[4:10], pdata)) + if ble_packets_types['nearby'] in packet.keys(): parse_nearby(mac, header, packet[ble_packets_types['nearby']]) if ble_packets_types['handoff'] in packet.keys(): @@ -751,6 +768,10 @@ def read_packet(mac, data_str): parse_airpods(mac, packet[ble_packets_types['airpods']]) if ble_packets_types['airdrop'] in packet.keys(): parse_airdrop_r(mac, packet[ble_packets_types['airdrop']]) + else: + if args.verb >= 2: + print("data_str={}".format(data_str)) + print("other mac={} header={} data={} packet={}".format(mac, header, data, packet)) def get_phone_db(hashp): global phone_number_info @@ -982,6 +1003,7 @@ def print_results3(data): thread1 = Thread(target=do_sniff, args=(False,)) thread1.daemon = True thread1.start() -MyApp = App() -MyApp.run() +if args.verb < 2: + MyApp = App() + MyApp.run() thread1.join() From 730fd71c42226fb79daae8e825e2d7b5ace64e68 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 12:18:37 -0800 Subject: [PATCH 07/10] Add configurable wifi interface --- ble_read_state.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ble_read_state.py b/ble_read_state.py index 4e6ac5f..5aef389 100644 --- a/ble_read_state.py +++ b/ble_read_state.py @@ -40,6 +40,7 @@ parser.add_argument('-s', '--ssid', action='store_true', help='Get SSID from requests') parser.add_argument('-m', '--message', action='store_true', help='Send iMessage to the victim') parser.add_argument('-a', '--airdrop', action='store_true', help='Get info from AWDL') +parser.add_argument('-i', '--interface', type=str, help='Wifi interface to use') parser.add_argument('-v', '--verb', action='count', help='Verbose output') parser.add_argument('-t', '--ttl', type=int, default=15, help='ttl') args = parser.parse_args() @@ -58,7 +59,7 @@ hlr_api_url = 'https://www.hlrlookup.com/api/hlr/?apikey={}&password={}&msisdn='.format(hlr_key, hlr_pwd) region_check_url = '' # URL to region checker here imessage_url = '' # URL to iMessage sender (sorry, but we did some RE for that :) ) -iwdev = 'wlan0' +iwdev = args.interface or 'wlan0' apple_company_id = 'ff4c00' dev_id = 0 # the bluetooth device is hci0 @@ -769,9 +770,8 @@ def read_packet(mac, data_str): if ble_packets_types['airdrop'] in packet.keys(): parse_airdrop_r(mac, packet[ble_packets_types['airdrop']]) else: - if args.verb >= 2: - print("data_str={}".format(data_str)) - print("other mac={} header={} data={} packet={}".format(mac, header, data, packet)) + if args.verb >= 3: + print("other mac={} data={}".format(mac, data_str)) def get_phone_db(hashp): global phone_number_info From 02bf30cee7472ded888b1f50e31c316864d55156 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 12:23:22 -0800 Subject: [PATCH 08/10] Add new features --- README.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 37d12cc..8127271 100644 --- a/README.md +++ b/README.md @@ -47,21 +47,24 @@ Moreover, the tool detects requests for password sharing from Apple devices. In ```bash python3 ble_read_state.py -h -usage: ble_read_state.py [-h] [-c] [-n] [-r] [-l] [-s] [-m] [-a] [-t TTL] +usage: ble_read_state.py [-h] [-c] [-n] [-r] [-l] [-s] [-m] [-a] [-v] [-t TTL] [-f MAC] [-i iface] Apple bleee. Apple device sniffer ---chipik optional arguments: - -h, --help show this help message and exit - -c, --check_hash Get phone number by hash - -n, --check_phone Get user info by phone number (TrueCaller/etc) - -r, --check_region Get phone number region info - -l, --check_hlr Get phone number info by HLR request (hlrlookup.com) - -s, --ssid Get SSID from requests - -m, --message Send iMessage to the victim - -a, --airdrop Get info from AWDL - -t TTL, --ttl TTL ttl + -h, --help show this help message and exit + -c, --check_hash Get phone number by hash + -n, --check_phone Get user info by phone number (TrueCaller/etc) + -r, --check_region Get phone number region info + -l, --check_hlr Get phone number info by HLR request (hlrlookup.com) + -s, --ssid Get SSID from requests + -m, --message Send iMessage to the victim + -a, --airdrop Get info from AWDL + -v, --verbose Add more verbosity, including -vv and -vvv + -i, --interface Wifi interface to use + -f, --follow Follow one or more MAC addresses (can be used multiple times) + -t, --ttl ttl ``` For monitoring you can just run the script without any parameters From b2ba5e971ebdf20947ff12d2d56bac6d747b4b74 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 13:02:38 -0800 Subject: [PATCH 09/10] Added SQLite web api --- hash2phone/README.md | 4 +++- hash2phone/map_hash_num_sqlite.php | 38 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 hash2phone/map_hash_num_sqlite.php diff --git a/hash2phone/README.md b/hash2phone/README.md index 5082158..bac0873 100644 --- a/hash2phone/README.md +++ b/hash2phone/README.md @@ -25,7 +25,8 @@ sudo -u postgres psql < db_init.sql Place lookup script into webserver directory: ``` -cp map_hash_num.php /var/www/html/ +cp map_hash_num.php /var/www/html/ # postgres version +cp map_hash_num_sqlite.php /var/www/html/ # sqlite version ``` - SQLite @@ -54,6 +55,7 @@ Now you can get mobile phones by 3 bytes of SHA256(phone_number) this way: ``` http://127.0.0.1/map_hash_num.php?hash=112233 +http://127.0.0.1/map_hash_num_sqlite.php?hash=112233 ``` ![ph_candidates](img/hash_api.png) diff --git a/hash2phone/map_hash_num_sqlite.php b/hash2phone/map_hash_num_sqlite.php new file mode 100644 index 0000000..2e65781 --- /dev/null +++ b/hash2phone/map_hash_num_sqlite.php @@ -0,0 +1,38 @@ +query('SELECT count(*) FROM map'); + if (!$res) { + echo 'Err =('; + exit; + } + + if ($row = $res->fetchArray()) { + echo "current: {$row[0]}"; + } + +} else { + $hash = $_GET['hash']; + $stm = $db->prepare('SELECT phone FROM map WHERE hash = ?'); + $stm->bindValue(1, $hash, SQLITE3_TEXT); + $res = $stm->execute(); + + if (!$res) { + echo 'Err =('; + exit; + } + + $candidates = $res->fetchArray(SQLITE3_NUM); + + $time_end = microtime(true); + $time = $time_end - $time_start; + + echo json_encode(compact('candidates', 'time')); + +} From 9f3746210af6803aba88f8a7c2bfb14197343f55 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 1 Dec 2019 13:07:20 -0800 Subject: [PATCH 10/10] Don't require verbosity --- ble_read_state.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ble_read_state.py b/ble_read_state.py index 5aef389..8316d8d 100644 --- a/ble_read_state.py +++ b/ble_read_state.py @@ -291,6 +291,8 @@ 'airdrop': '05', } +if not args.verb: + args.verb = 0 if args.follow: # format MAC address to uppercase split by ':'s for i in range(len(args.follow)):