def main(): aparse = argparse.ArgumentParser(description="Host-side receiver for Sniffle BLE5 sniffer") aparse.add_argument("-s", "--serport", default="/dev/ttyACM0", help="Sniffer serial port name") aparse.add_argument("-c", "--advchan", default=40, choices=[37, 38, 39], type=int, help="Advertising channel to listen on") aparse.add_argument("-p", "--pause", action="store_const", default=False, const=True, help="Pause sniffer after disconnect") aparse.add_argument("-r", "--rssi", default=-80, type=int, help="Filter packets by minimum RSSI") aparse.add_argument("-m", "--mac", default=None, help="Filter packets by advertiser MAC") aparse.add_argument("-i", "--irk", default=None, help="Filter packets by advertiser IRK") aparse.add_argument("-a", "--advonly", action="store_const", default=False, const=True, help="Sniff only advertisements, don't follow connections") aparse.add_argument("-e", "--extadv", action="store_const", default=False, const=True, help="Capture BT5 extended (auxiliary) advertising") aparse.add_argument("-H", "--hop", action="store_const", default=False, const=True, help="Hop primary advertising channels in extended mode") aparse.add_argument("-l", "--longrange", action="store_const", default=False, const=True, help="Use long range (coded) PHY for primary advertising") aparse.add_argument("-q", "--quiet", action="store_const", default=False, const=True, help="Don't display empty packets") aparse.add_argument("-Q", "--preload", default=None, help="Preload expected encrypted " "connection parameter changes") aparse.add_argument("-o", "--output", default=None, help="PCAP output file name") args = aparse.parse_args() # Sanity check argument combinations if args.hop and args.mac is None and args.irk is None: print("Primary adv. channel hop requires a MAC address or IRK specified!", file=sys.stderr) return if args.longrange and not args.extadv: print("Long-range PHY only supported in extended advertising!", file=sys.stderr) return if args.longrange and args.hop: # this would be pointless anyway, since long range always uses extended ads print("Primary ad channel hopping unsupported on long range PHY!", file=sys.stderr) return if args.mac and args.irk: print("IRK and MAC filters are mutually exclusive!", file=sys.stderr) return if args.advchan != 40 and args.hop: print("Don't specify an advertising channel if you want advertising channel hopping!", file=sys.stderr) return global hw hw = SniffleHW(args.serport) # if a channel was explicitly specified, don't hop global _allow_hop3 if args.advchan == 40: args.advchan = 37 else: _allow_hop3 = False # set the advertising channel (and return to ad-sniffing mode) hw.cmd_chan_aa_phy(args.advchan, BLE_ADV_AA, 2 if args.longrange else 0) # set whether or not to pause after sniffing hw.cmd_pause_done(args.pause) # set up whether or not to follow connections hw.cmd_follow(not args.advonly) if args.preload: # expect colon separated triplets, separated by commas triplets = [] for tstr in args.preload.split(','): tsplit = tstr.split(':') tup = (int(tsplit[0]), int(tsplit[1]), int(tsplit[2])) triplets.append(tup) hw.cmd_interval_preload(triplets) else: # reset preloaded encrypted connection interval changes hw.cmd_interval_preload() # configure RSSI filter global _rssi_min _rssi_min = args.rssi hw.cmd_rssi(args.rssi) # disable 37/38/39 hop in extended mode unless overridden if args.extadv and not args.hop: _allow_hop3 = False # configure MAC filter global _delay_top_mac if args.mac is None and args.irk is None: hw.cmd_mac() elif args.irk: hw.cmd_irk(unhexlify(args.irk), _allow_hop3) elif args.mac == "top": hw.cmd_mac() _delay_top_mac = True else: try: macBytes = [int(h, 16) for h in reversed(args.mac.split(":"))] if len(macBytes) != 6: raise Exception("Wrong length!") except: print("MAC must be 6 colon-separated hex bytes", file=sys.stderr) return hw.cmd_mac(macBytes, _allow_hop3) # configure BT5 extended (aux/secondary) advertising hw.cmd_auxadv(args.extadv) # zero timestamps and flush old packets hw.mark_and_flush() global pcwriter if not (args.output is None): pcwriter = PcapBleWriter(args.output) while True: msg = hw.recv_and_decode() print_message(msg, args.quiet)
def main(): aparse = argparse.ArgumentParser( description="Host-side receiver for Sniffle BLE5 sniffer") aparse.add_argument("-s", "--serport", default="/dev/ttyACM0", help="Sniffer serial port name") aparse.add_argument("-c", "--advchan", default=37, choices=[37, 38, 39], type=int, help="Advertising channel to listen on") aparse.add_argument("-p", "--pause", action="store_const", default=False, const=True, help="Pause sniffer after disconnect") aparse.add_argument("-r", "--rssi", default=-80, type=int, help="Filter packets by minimum RSSI") aparse.add_argument("-m", "--mac", default=None, help="Filter packets by advertiser MAC") aparse.add_argument( "-a", "--advonly", action="store_const", default=False, const=True, help="Sniff only advertisements, don't follow connections") aparse.add_argument("-e", "--extadv", action="store_const", default=False, const=True, help="Capture BT5 extended (auxiliary) advertising") aparse.add_argument( "-H", "--hop", action="store_const", default=False, const=True, help="Hop primary advertising channels in extended mode") aparse.add_argument( "-l", "--longrange", action="store_const", default=False, const=True, help="Use long range (coded) PHY for primary advertising") aparse.add_argument("-o", "--output", default=None, help="PCAP output file name") args = aparse.parse_args() # Sanity check argument combinations if args.hop and args.mac is None: print("Primary adv. channel hop requires a MAC address specified!", file=sys.stderr) return if args.longrange and not args.extadv: print("Long-range PHY only supported in extended advertising!", file=sys.stderr) return if args.longrange and args.hop: # this would be pointless anyway, since long range always uses extended ads print("Primary ad channel hopping unsupported on long range PHY!", file=sys.stderr) return global hw hw = SniffleHW(args.serport) # set the advertising channel (and return to ad-sniffing mode) hw.cmd_chan_aa_phy(args.advchan, BLE_ADV_AA, 2 if args.longrange else 0) # set whether or not to pause after sniffing hw.cmd_pause_done(args.pause) # set up endTrim if args.advonly: hw.cmd_endtrim(0xB0) else: hw.cmd_endtrim(0x10) # configure RSSI filter global _rssi_min _rssi_min = args.rssi hw.cmd_rssi(args.rssi) # disable 37/38/39 hop in extended mode unless overridden global _allow_hop3 if args.extadv and not args.hop: _allow_hop3 = False # configure MAC filter global _delay_top_mac if args.mac is None: hw.cmd_mac() elif args.mac == "top": hw.cmd_mac() _delay_top_mac = True else: try: macBytes = [int(h, 16) for h in reversed(args.mac.split(":"))] if len(macBytes) != 6: raise Exception("Wrong length!") except: print("MAC must be 6 colon-separated hex bytes", file=sys.stderr) return hw.cmd_mac(macBytes, _allow_hop3) # configure BT5 extended (aux/secondary) advertising hw.cmd_auxadv(args.extadv) global pcwriter if not (args.output is None): pcwriter = PcapBleWriter(args.output) while True: msg_type, msg_body = hw.recv_msg() print_message(msg_type, msg_body)
'--verbose', dest='verbose', action='store_true', default=False, help='Enable verbose mode') parser.add_argument('-o', '--output', dest='output', default=None, help='PCAP output file') args = parser.parse_args() try: output = PcapBleWriter(args.output) l = Link(args.device, 115200) l.reset() major, minor = l.get_version() print('uBitle v1.0 [firmware version %d.%d]' % (major, minor)) print('') if args.scan_aa: aad = {} print('[i] Listing available access addresses ...') for aa in l.scan_access_addresses(): if aa.access_address not in aad: aad[aa.access_address] = 1 else: aad[aa.access_address] += 1