Modules¶
Presentation¶
Mirage provides a modular framework for analyzing the security of wireless communication protocols, that’s why the available attacks and actions are implemented as modules. A module is a software component of Mirage, easy to run and use, allowing to perform a specific action or attack. It has multiple input parameters and generates some output parameters. Every parameter is named and allow to provide a specific information to the module in order to customize its execution.
The modules can be combined thanks to a chaining operator (|
). If you want more details about this operator, please refer to this documentation.
Finally, some modules provide complex behaviour, such as ble_master or ble_mitm. In order to easily customize their behaviour, Mirage allows to use scenarios which are special classes allowing to modify the execution of a module without modifying its source code.
List of Bluetooth Low Energy modules¶
The following modules allows to manipulate Bluetooth Low Energy communications :
Name |
Description |
Documentation |
---|---|---|
ble_info |
This module displays useful informations about a given interface. |
|
ble_connect |
This module connects to a Peripheral’s device as Central. |
|
ble_master |
This module simulates a Central device. |
|
ble_slave |
This module simulates a Peripheral device. |
|
ble_discover |
This module allows to dump the ATT/GATT database of a Peripheral. |
|
ble_adv |
This module sends advertisements. |
|
ble_scan |
This module discovers Advertisers and Peripherals by scanning advertisements. |
|
ble_pair |
This module performs a pairing with a Peripheral or a Central. |
|
ble_mitm |
This module performs a Man-in-the-Middle attack. |
|
ble_sniff |
This module sniffs the advertisements and new / existing connections. |
|
ble_jam |
This module jams the advertisements or connections. |
|
ble_hijack |
This module hijacks an existing connection. |
|
ble_crack |
This module cracks a Temporary Key. |
|
ble_monitor |
This module monitors an HCI communication. |
List of Enhanced ShockBurst modules¶
The following modules allows to manipulate Enhanced ShockBurst communications :
Name |
Description |
Documentation |
---|---|---|
esb_info |
This module displays useful informations about a given interface. |
|
esb_scan |
This module performs a scan in order to discover Enhanced ShockBurst devices. |
|
esb_sniff |
This module sniffs the Enhanced ShockBurst frames. |
|
esb_inject |
This module allows to inject some Enhanced ShockBurst frames. |
|
esb_ptx |
This module simulates an Enhanced ShockBurst PTX (transmitter). |
|
esb_prx |
This module simulates an Enhanced ShockBurst PRX (receiver). |
|
esb_mitm |
This module performs a Man-in-the-Middle targeting Logitech Unifying devices. |
List of Mosart modules¶
The following modules allows to manipulate Mosart communications :
Name |
Description |
Documentation |
---|---|---|
mosart_info |
This module displays useful informations about a given interface. |
|
mosart_scan |
This module performs a scan in order to discover Mosart devices. |
|
mosart_sniff |
This module sniffs the Mosart frames. |
|
mosart_inject |
This module allows to inject some Mosart frames. |
|
mosart_keylogger |
This module analyzes the keystrokes packets transmitted by a Mosart keyboard. |
|
mosart_keyinjector |
This module allows to transmit some keystrokes packets to a Mosart dongle. |
List of WiFi modules¶
The following modules allows to manipulate WiFi communications :
Name |
Description |
Documentation |
---|---|---|
wifi_info |
This module displays useful informations about a given interface. |
|
wifi_deauth |
This module performs a deauthentication attack. |
|
wifi_rogueap |
This module creates a basic rogue access point (not connectible). |
|
wifi_scan |
This module discovers Access Points and WiFi stations. |
List of Zigbee modules¶
The following modules allows to manipulate Zigbee communications :
Name |
Description |
Documentation |
---|---|---|
zigbee_info |
This module displays useful informations on a given interface. |
|
zigbee_deauth |
This module performs a deauthentication attack. |
|
zigbee_floodassoc |
This module performs an association flooding attack. |
|
zigbee_inject |
This module allows to inject some Zigbee frames. |
|
zigbee_scan |
This module scans for Zigbee devices on all channels. |
|
zigbee_sniff |
This module sniffs Zigbee communications on a given channel. |
List of Infrared Radiations modules¶
The following modules allows to manipulate Infrared Radiations signals :
Name |
Description |
Documentation |
---|---|---|
ir_info |
This module displays useful informations about a given interface. |
|
ir_sniff |
This module sniffs the Infrared Radiations signals. |
|
ir_inject |
This module injects the Infrared Radiations signals. |
Writing your own module¶
Generating a new module¶
Writing your own module is relatively simple. Indeed, Mirage allows to easily generates a basic source code using the create_module
command. You can launch it from the Command Line Interface :
~~> create_module
[QUESTION] Module's name : newmod
[QUESTION] Module's description : Test module
[QUESTION] Module's type : test
[QUESTION] Module's technology [ble] :
[QUESTION] Module's dependencies (separated by commas) : ble_sniff,ble_scan
[QUESTION] Input parameter #1 (name) : INTERFACE
[QUESTION] Input parameter #1 (default value) : hci0
[QUESTION] Input parameter #2 (name) : PARAM1
[QUESTION] Input parameter #2 (default value) : value1
[QUESTION] Input parameter #3 (name) :
[SUCCESS] Module newmod successfully generated : /home/user/.mirage/modules/newmod.py
Or you can launch it from the Direct Mode :
$ mirage --create_module
[QUESTION] Module's name : newmod
[QUESTION] Module's description : Test module
[QUESTION] Module's type : test
[QUESTION] Module's technology [ble] :
[QUESTION] Module's dependencies (separated by commas) : ble_sniff,ble_scan
[QUESTION] Input parameter #1 (name) : INTERFACE
[QUESTION] Input parameter #1 (default value) : hci0
[QUESTION] Input parameter #2 (name) : PARAM1
[QUESTION] Input parameter #2 (default value) : value1
[QUESTION] Input parameter #3 (name) :
[SUCCESS] Module newmod successfully generated : /home/user/.mirage/modules/newmod.py
It will generates the following code :
from mirage.core import module
from mirage.libs import utils,ble
class newmod(module.WirelessModule):
def init(self):
self.technology = "ble"
self.type = "test"
self.description = "Test module"
self.args = {'INTERFACE': 'hci0', 'PARAM1': 'value1'}
self.dependencies = ["ble_sniff","ble_scan"]
def run(self):
# Enter your code here.
return self.ok({})
Understanding the module environment¶
As you can see in the generated code, every module inherits from WirelessModule
(mirage.core.module.WirelessModule) and implements two main methods :
init
: this method allows to initialize the module. It is mainly used in order to fill the required attributes, such astechnology
(indicating the technology used by this module),type
(indicating the type of module),description
(short string describing the role of the module)args
(dictionnary indicating the named input parameters and their default values) anddependencies
(array containing the name of the modules needed in order to execute the module).
run
: this method implements the behaviour of the module : it is executed when the module is launched. If you need to execute some actions before or after this method, you can use two optional methods namedprerun
(launched beforerun
) andpostrun
(launched afterrun
).
In the run
method, you have to terminate the method execution by returning a dictionary composed of two fields, success and output. Two helpers methods allows you to easily generate the right output format :
ok
(mirage.core.module.Module.ok) : this method returns the dictionary indicating that the module execution is successful. The dictionary of output parameters can be passed as an argument in order to output some specific values.
nok
(mirage.core.module.Module.ok) : this method returns the dictionary indicating that the module execution has failed.
return self.ok({"INTERFACE":"hci0"}) # The module execution is successful, it returns an output parameter named INTERFACE
# or
return self.ok() # The module execution is successful, it returns no parameters
# or
return self.nok() # The module execution is not successful
Manipulating the input parameters¶
Every module can use some input parameters. These parameters are defined in the args
dictionnary, which is an attribute of the module class, and can be modified by the user.
# The arguments are defined in the init method, here there are six arguments :
# - INTERFACE : this parameter has a default value (the string "hci0")
# - ARGUMENT_A : this parameter has no default value
# - ARGUMENT_B : this parameter has a default value (the string "yes")
# - ARGUMENT_C : this parameter has a default value (the string "0x1234")
# - ARGUMENT_D : this parameter has a default value (the string "aa:bb:cc:dd:ee:ff")
# - ARGUMENT_E : this parameter has a default value (the string "one,two,three")
def init(self):
# [...]
self.args = {
"INTERFACE":"hci0",
"ARGUMENT_A":"",
"ARGUMENT_B":"yes",
"ARGUMENT_C":"0x1234",
"ARGUMENT_D":"aa:bb:cc:dd:ee:ff",
"ARGUMENT_E":"one,two,three"
}
As you can see, every input parameter is provided as a string, allowing to easily manipulate it from the command line. However, this string is generally used to transmit a “typed” value to the module (e.g. a boolean or an integer) : Mirage provides multiple functions to check and convert the value provided. These functions are defined in the utils
library (mirage.libs.utils).
For example, the function booleanArg
(mirage.libs.utils.booleanArg) allows you to easily convert a specific argument to a boolean. The expected values are :
“yes”,”true”,”1” indicate True
“no”,”false”,”0” indicate False (every other string is converted to False)
For example, if you want to convert the input parameter named ARGUMENT_B to a boolean, you can use :
booleanValue = utils.booleanArg(self.args["ARGUMENT_B"])
# booleanValue contains True
You can also convert a string to an integer value using the function integerArg
(mirage.libs.utils.integerArg). The provided value can be an hexadecimal number (e.g. “0x1a2b” or “aabb112233”) or a decimal number (e.g. “42” or “-23”). The following example converts the input parameter ARGUMENT_C to an integer :
integerValue = utils.integerArg(self.args["ARGUMENT_C"])
# integerValue contains 4660
Note
Please note that some functions of the library utils
(e.g. isNumber
or isHexadecimal
) allows to check if the provided string is a decimal or an hexadecimal number. You can refer to (the corresponding documentation) for more details.
It’s quite common to manipulate some MAC or BD addresses during the analysis of a wireless communications, that’s why Mirage provides another conversion function, named addressArg
(mirage.libs.utils.addressArg), in order to convert it to an address usable by Mirage. Mirage converts addresses to uppercase string in order to facilitate the comparison between them.
The following example converts the input parameter ARGUMENT_D to an address :
addressValue = utils.addressArg(self.args["ARGUMENT_D"])
# addressValue contains "AA:BB:CC:DD:EE:FF"
Finally, some input parameters can contain a list of strings, splitted by commas (e.g. “one,two,three” <=> [“one”,”two”,”three”]). You can easily convert them to a list of string thanks to the function listArg
(mirage.libs.utils.listArg). The following eaxample converts the input parameter ARGUMENT_E to a list of string :
listValue = utils.listArg(self.args["ARGUMENT_E"])
# listValue contains ["one","two","three"]
Interacting with the user¶
Mirage provides various functions in order to print datas to the user or asking him some informations. These functions are mainly defined in the io
library (mirage.libs.io). It allows to standardize the behaviour of modules in terms of user interaction.
Four different functions can be used to display a message, according to the type of information you want to print.
First, you can print an information message using the info
function (mirage.libs.io.info) :
io.info("This is an information message.")
Second, you can display a warning message thanks to the warning
function (mirage.libs.io.warning) :
io.warning("This is a warning message.")
Then, you can print a failure message using the fail
function (mirage.libs.io.fail):
io.fail("This is a failure message.")
Finally, you can print a success message using the success
function (mirage.libs.io.success) :
io.success("This is a success message.")
Warning
Please keep in mind that the user can control the verbosity level of Mirage. You can refer to this page of the documentation if you need more information about this feature.
You can also display a table using the function named chart
(mirage.libs.io.chart) :
io.chart(["A","B","A xor B"],[
["False","False","False"],
["True","False","True"],
["False", "True", "True"],
["True", "True", "False"]
],title="XOR Table")
The corresponding output is :
┌XOR Table──────┬─────────┐
│ A │ B │ A xor B │
├───────┼───────┼─────────┤
│ False │ False │ False │
│ True │ False │ True │
│ False │ True │ True │
│ True │ True │ False │
└───────┴───────┴─────────┘
The progress
function (mirage.libs.io.progress) displays a progress bar (it must be called multiple times in order to display the loading process) :
for i in range(10):
io.progress(i*10,total=100,suffix="fuzzing...")
utils.wait(seconds=1)
This example displays something like :
())))))))))))))))))))))))))))))))))))))))__________________) fuzzing...
Finally, you may need to ask your user to answer a question or provide an input. The ask
function (mirage.libs.io.ask) is dedicated to this operation :
answer = io.ask("Enter your age", default=25,final=": ")
This function returns the string entered by the user and this example displays the following line :
[QUESTION] Enter your age [25] : 26
Launching tasks in background¶
Mirage allows modules to run some tasks in background, in a daemon child process. This task may be persistent and can continue its execution after the end of the module execution (some commands allow to manipulate these background tasks in the command-line interpreter, please refer to the corresponding documentation if needed). It provides a simple API included in the utils
library (mirage.libs.utils).
Let’s imagine you have written a new method named helloworld
:
def helloworld(self):
while True:
print("HelloWorld")
If you want to register it as a background task, you can use the function named addTask
(mirage.libs.utils.addTask) :
task = utils.addTask(function=self.helloworld)
This function returns the name of the task created. Using this information, you can start the task using startTask
(mirage.libs.utils.startTask) :
utils.startTask(task)
You can also restart it using restartTask
(mirage.libs.utils.restartTask) :
utils.restartTask(task)
Or stop it using stopTask
(mirage.libs.utils.stopTask) :
utils.stopTask(task)
Manipulating a module from another one¶
If you want to manipulate a module from another one, you can use some helpers functions included in utils
(mirage.libs.utils). First of all, include this library using the following line :
from mirage.libs import utils
Then, you can use the loadModule
(mirage.libs.utils.loadModule) function in order to load a specific module :
mod = utils.loadModule("ble_info")
You can provide some input parameters using the following syntax :
mod["INTERFACE"] = "hci1"
Finally you can execute the module using the following method :
output = mod.execute()
The returned value is a dictionary composed of two main fields:
success : boolean indicating if the execution was successful
output : dictionary including the output parameters of the module
if output["success"]:
io.success("Successful execution !")
io.info("Output parameters :")
for outputParameterName,outputParameterValue in output.items():
io.info(outputParameterName + " = " + outputParameterValue)
else:
io.fail("An error occured during the execution !")
Integrating scenarios in your module¶
If you want to integrate scenarios in your module, please refer to the following documentation.