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 diff --git a/ble_read_state.py b/ble_read_state.py index fb3cfdb..8316d8d 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', @@ -39,7 +40,8 @@ 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('-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() @@ -57,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 @@ -289,6 +291,16 @@ '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)): + 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") @@ -468,7 +480,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') @@ -504,7 +516,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] @@ -548,6 +563,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']) @@ -714,12 +731,30 @@ 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 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(): @@ -736,6 +771,9 @@ 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 >= 3: + print("other mac={} data={}".format(mac, data_str)) def get_phone_db(hashp): global phone_number_info @@ -967,6 +1005,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() 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/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") 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')); + +}