Enumeration¶
The MQTT protocol allows by design to every entity (device, sensor etc.) to subscribe to any topic it wishes (as long
the broker hasn’t enabled any security measures, which by default are off). Using this method, we developed what we
called - the discovery
plugin, which subscribes for a certain amount of time, to all topics (using wildcard
notation) by that enumerating all available topics at a certain time.
Wildcard Topic¶
MQTT supports subscribing to topics using 2 wildcard options:
Single Level¶
A single level wildcard replaces one topic level using the +
sign, in example:
home/daniel/+/open
This means that every topic matching the pattern above will match, in example considering the following topics:
- home/daniel/door/status
- home/daniel/lights/status
- home/daniel/garage/status
All of them are going to match.
Multi Level¶
In contrast to the single level wildcard, the multi level comes handy when we don’t now the tail of the topic, and we
want to wildcard more than one level, it is used with the #
sign. In example:
home/daniel/#
This means every topic from this level and below will match, considering the topics bellow:
- home/daniel/door/status
- home/daniel/door/opened
- home/daniel/lights/status
- home/daniel/lights/closed
- home/daniel/garage/status
- home/daniel/garage/closed
All of them are going to match.
Discover¶
In order to enumerate topics, first make sure you are connected to a MQTT broker (using the connect
command).
Let’s examine the discovery
command:
localhost:1883 >> discovery --help
usage: discovery [-h] [-t TIMEOUT] [-p TOPICS [TOPICS ...]] [-q QOS]
Discover new topics/messages in the current connected broker
optional arguments:
-h, --help show this help message and exit
-t TIMEOUT, --timeout TIMEOUT
for how long to discover (default: 60)
-p TOPICS [TOPICS ...], --topics TOPICS [TOPICS ...]
which topics to listen to (default: ['$SYS/#', '#'])
-q QOS, --qos QOS which quality of service (default: 0)
Now, let’s run the discovery for 10 seconds with quality of service of 0:
localhost:1883 >> discovery -t 10 -q 0
[!] Starting MQTT discovery (id #1) ...
localhost:1883 >>
localhost:1883 >>
[+] Scan #1 has finished!
We can observe that the scan is asynchronous (runs on a different thread), so are free to handle more operations in
the meanwhile. We can see the status of scans using the scans
command:
localhost:1883 >> scans
+----+-----------------+----------------------------+---------+
| ID | Type | Created At | Is Done |
+----+-----------------+----------------------------+---------+
| 1 | topic_discovery | 2018-07-19 15:10:07.988613 | True |
+----+-----------------+----------------------------+---------+
We see that the can is finished, in order to see which topics/messages we have enumerated, we need to select it first.
This can be done using the scans
command as well:
localhost:1883 >> scans -i 1
localhost:1883 [Scan #1] >>
The scan has been chosen and added as a global context variables, meaning that choosing scan number 1 will affect the output of further plugins now.
Topics¶
To explore which topics we have enumerated, make sure we have selected a scan (explained in the last section). Then,
simply use the topics
command:
localhost:1883 [Scan #1] >> topics
[+] Fetching data..
+-------+-------------------------------------------+----------+
| ID | Topic | Label |
+-------+-------------------------------------------+----------+
| 2609 | some/topic/we_caught | |
| 5 | $SYS/broker/clients/maximum | |
| 2427 | some/other/topic/we_caught | |
....
The list goes on and one, similarly to the output of a more command. However, the plugin supports many useful flags, let’s examine the help strings:
localhost:1883 [Scan #1] >> topics --help
usage: topics [-h] [-s] [-l LIMIT] [-r REGEX] [-c]
List topics that were detected through discovery scans
optional arguments:
-h, --help show this help message and exit
-s, --show-only-labeled
show only labeled topics
-l LIMIT, --limit LIMIT
get the first X rows
-r REGEX, --regex REGEX
search for a pattern in the topic name
-c, --case-sensitive make the regex search case sensitive (default is case
insensitive)
First of all, we see a flag called –show-only-labeled, we have came up with a list of known topic patterns (the list can be found in ./resources/definitions.json. It contains the topic pattern and a friendly name. Turning this flag, shows only topics that we have found in the definitions.json file.
Furthermore, we can limit the results and search for a specific regular expression pattern withing the topic name.
Messages¶
Aside from topics enumeration, MQTT-PWN supports also message enumeration, as part of the discovery the scan also
stores the messages body. They can be viewed, similarly to the topics plugin, using the messages
plugin:
localhost:1883 [Scan #1] >> messages
[+] Fetching data..
+-------+----------------------------+------------------+-----------+
| ID | Topic | Message | Label |
+-------+----------------------------+------------------+-----------+
| 2096 | some/topic/we_caught | hello world | |
...
It has similar flags as the topics plugin:
localhost:1883 [Scan #1] >> messages --help
usage: messages [-h] [-i INDEX] [-j] [-s] [-l LIMIT] [-mr MESSAGE_REGEX]
[-tr TOPIC_REGEX] [-c]
List Messages that were detected through discovery scans
optional arguments:
-h, --help show this help message and exit
Single Message Arguments
-i INDEX, --index INDEX
show a message based on an ID
-j, --json-prettify JSON prettify the message body
Multi Message Arguments
-s, --show-only-labeled
show only labeled topics
-l LIMIT, --limit LIMIT
get the first X rows
-mr MESSAGE_REGEX, --message-regex MESSAGE_REGEX
search for a pattern in the message body
-tr TOPIC_REGEX, --topic-regex TOPIC_REGEX
search for a pattern in the topic name
-c, --case-sensitive make the regex search case sensitive (default is case
insensitive)
There are a couple of differences, the first one is that we have two operational modes here;
Multi¶
Similarly to the topics
plugin, we can set a limit to the messages and look for regular expressions patterns (either
in the topic name or the message body), along with setting the search case sensitive or not. Because the message body
can be extremely long, they are pruned after a certain amount of characters.
Single¶
Using the -i
flag, we can select a single message, by that showing the full length of the body, along of a special
flag -j
that enables JSON formatting, in example:
localhost:1883 [Scan #1] >> messages -i 27607 -j
Message #27607:
- Topic: owntracks/daniel/iPhone7
- Timestamp: 2018-07-25 13:18:33.237445
- Body: {
"_type": "location",
"tid": "n5",
"acc": 17,
"batt": 56,
"conn": "w",
"lat": 32.1657401,
"lon": 34.8116074,
"t": "c",
"tst": 1532513147
}