Mosart protocol

Mosart is a wireless communication protocol widely used by wireless mices and keyboards. Mirage includes a lot of software components allowing to communicate with Mosart devices. This page presents a subset of these components, and provides some basic examples presenting their usage.

Mosart modules

Mirage includes many modules allowing to analyze the security of Mosart communications. These modules can perform attacks or useful actions in order to manipulate a Mosart device. The available modules and the links to the corresponding documentation pages are listed in the following table :

Name

Description

Documentation

mosart_info

This module displays useful informations about a given interface.

here

mosart_scan

This module performs a scan in order to discover Mosart devices.

here

mosart_sniff

This module sniffs the Mosart frames.

here

mosart_inject

This module allows to inject some Mosart frames.

here

mosart_keylogger

This module analyzes the keystrokes packets transmitted by a Mosart keyboard.

here

mosart_keyinjector

This module allows to transmit some keystrokes packets to a Mosart dongle.

here

Importing the Mosart software components

Every software component described in this page can be easily imported from a module or a scenario environment using the following statement :

from mirage.libs import mosart

Then, every component is available using the mosart namespace :

packet = mosart.MosartMouseMovementPacket(address="11:22:33:44", x1=1,x2=2,y1=-5,y2=-3)

Interacting with the protocol

Mirage currently allows to interact with the Mosart protocol using an NRF24-based device, embedding the RFStorm firmware written by Bastille Research. The supported Devices are listed 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.

Mosart packets

Mirage manipulates the Mosart packets as child classes of MosartPacket (mirage.libs.mosart_utils.packets.MosartPacket), 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 :

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 MosartSniffingParameters (mirage.libs.esb_utils.packets.MosartSniffingParameters).

Mosart Dissectors

Some Mosart 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 Mosart 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 keystroke field (mirage.libs.mosart_utils.dissectors.MosartKeystroke):

Example
>>> MosartKeystroke(hidCode=5,modifiers=0).data.hex()
'812d'
>>> MosartKeystroke(data=bytes.fromhex("812d")).hidCode
5
>>> MosartKeystroke(data=bytes.fromhex("812d")).modifiers
0

Warning

The Mosart protocol seems to use some arbitrary values to describe keystrokes. The values provided by this dissectors has been collected empirically and as a consequence, they are probably not complete and they probably include some mistakes.

Dongle Acknowledgement and Sync packets

The Mosart protocol doesn’t allow to inject keystrokes at any time: the packets have to be transmitted right after the reception of a synchonization frame transmitted by the dongle itself. Similarly, the frame are acknowledged by the same kind of frames by the dongle. In order to allow the active attacks targeting this protocol, the supported devices implements a synchronization mode, allowing to wait a sync packet before transmitting the next frame. You can enable and disable this mode using the following shared methods:

Example
>>> self.emitter.enableSync()
>>> self.emitter.sendp(mosart.MosartMouseMovementPacket(address="11:22:33:44", x1=1,x2=2,y1=-5,y2=-3))

Similarly, if you want to passively capture this kind of frame, you have to enable the dongle packets reception using the following shared methods:

HID helpers

The Mosart 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 a keystroke injection targeting a Mosart device:

def addMosartKeystroke(locale="fr",key="a",ctrl=False, alt=False, gui=False,shift=False):
        keystrokes = []
        if key == "\n":
                key = "ENTER"
        hid,mod = HIDMapping(locale=locale).getHIDCodeFromKey(key=key)

        if mod == 0:
                keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=hid,modifiers=0,state="pressed"))
                keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=hid,modifiers=0,state="pressed"))

                counter = counter + 1 if counter + 1 <= 15 else 0
        else:
                keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=0,modifiers=mod,state="pressed"))
                keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=0,modifiers=mod,state="pressed"))
                keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=hid,modifiers=0,state="pressed"))
                keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=hid,modifiers=0,state="pressed"))

                counter = counter + 1 if counter + 1 <= 15 else 0
        keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=hid,modifiers=0,state="released"))
        keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=hid,modifiers=0,state="released"))
        keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=0,modifiers=mod,state="released"))
        keystrokes.append(mosart.MosartKeyboardKeystrokePacket(sequenceNumber=counter,address="11:22:33:44",hidCode=0,modifiers=mod,state="released"))
        keystrokes.append(wireless.WaitPacket(time=0.4))
        counter = counter + 1 if counter + 1 <= 15 else 0
        return keystrokes

def addMosartText(self,string="",locale="fr"):
        keystrokes = []
        for letter in string:
                keystrokes += self.addMosartKeystroke(key=letter,locale=locale)

        return keystrokes

def startMosartInjection():
        return []

def addMosartDelay(duration=1000):
        keystrokes = []
        keystrokes.append(wireless.WaitPacket(time=0.0001*duration))
        return keystrokes

parser = DuckyScriptParser(filename="/tmp/ducky.txt")
attackStream = parser.generatePackets(
        textFunction=addMosartText,
        initFunction=startMosartInjection,
        keyFunction=addMosartKeystroke,
        sleepFunction=addMosartDelay
        )
emitter.sendp(*attackStream)