Skip to content

Commit f15309b

Browse files
committed
Add basic framework for interacting with MQTT
1 parent fe4c701 commit f15309b

File tree

6 files changed

+129
-0
lines changed

6 files changed

+129
-0
lines changed

Gemfile.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ PATH
2020
metasploit-payloads (= 1.3.19)
2121
metasploit_data_models
2222
metasploit_payloads-mettle (= 0.3.2)
23+
mqtt
2324
msgpack
2425
nessus_rest
2526
net-ssh
@@ -192,6 +193,7 @@ GEM
192193
method_source (0.9.0)
193194
mini_portile2 (2.3.0)
194195
minitest (5.10.3)
196+
mqtt (0.5.0)
195197
msgpack (1.2.0)
196198
multi_json (1.12.2)
197199
multipart-post (2.0.0)

lib/msf/core/auxiliary/mixins.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
require 'msf/core/auxiliary/kademlia'
2424
require 'msf/core/auxiliary/llmnr'
2525
require 'msf/core/auxiliary/mdns'
26+
require 'msf/core/auxiliary/mqtt'
2627
require 'msf/core/auxiliary/nmap'
2728
require 'msf/core/auxiliary/natpmp'
2829
require 'msf/core/auxiliary/iax2'

lib/msf/core/auxiliary/mqtt.rb

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# -*- coding: binary -*-
2+
3+
require 'msf/core/exploit'
4+
require 'rex/proto/mqtt'
5+
6+
module Msf
7+
module Auxiliary::MQTT
8+
include Exploit::Remote::Tcp
9+
10+
def initialize(info = {})
11+
super
12+
13+
register_options(
14+
[
15+
Opt::RPORT(Rex::Proto::MQTT::DEFAULT_PORT),
16+
OptString.new('USERNAME', [false, 'The user to authenticate as']),
17+
OptString.new('PASSWORD', [false, 'The password to authenticate with'])
18+
]
19+
)
20+
21+
register_advanced_options(
22+
[
23+
OptString.new('CLIENT_ID', [false, 'The client ID to send if necessary for bypassing clientid_prefixes']),
24+
OptInt.new('READ_TIMEOUT', [true, 'Seconds to wait while reading MQTT responses', 5])
25+
]
26+
)
27+
28+
register_autofilter_ports([Rex::Proto::MQTT::DEFAULT_PORT])
29+
end
30+
31+
def setup
32+
fail_with(Failure::BadConfig, 'READ_TIMEOUT must be > 0') if read_timeout <= 0
33+
client_id_arg = datastore['CLIENT_ID']
34+
if client_id_arg
35+
fail_with(Failure::BadConfig, 'CLIENT_ID must be a non-empty string') if client_id_arg.blank?
36+
end
37+
end
38+
39+
def read_timeout
40+
datastore['READ_TIMEOUT']
41+
end
42+
43+
def client_id
44+
datastore['CLIENT_ID'] || Rex::Text.rand_text_alpha(1 + rand(10))
45+
end
46+
47+
def mqtt_client
48+
client_opts = {
49+
client_id: client_id().to_s,
50+
username: datastore['USERNAME'],
51+
password: datastore['PASSWORD'],
52+
read_timeout: read_timeout
53+
}
54+
Rex::Proto::MQTT::Client.new(sock, client_opts)
55+
end
56+
57+
def mqtt_connect(client)
58+
client.connect
59+
end
60+
61+
def mqtt_connect?(client)
62+
mqtt_connect(client).return_code == 0
63+
end
64+
65+
def mqtt_disconnect(client)
66+
client.disconnect
67+
end
68+
end
69+
end

lib/rex/proto/mqtt.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# -*- coding: binary -*-
2+
#
3+
# Support for MQTT
4+
5+
require 'rex/proto/mqtt/client'
6+
7+
module Rex
8+
module Proto
9+
module MQTT
10+
DEFAULT_PORT = 1883
11+
DEFAULT_SSL_PORT = 8883
12+
end
13+
end
14+
end

lib/rex/proto/mqtt/client.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# -*- coding: binary -*-
2+
3+
require 'mqtt'
4+
5+
##
6+
# MQTT protocol support
7+
##
8+
9+
module Rex
10+
module Proto
11+
module MQTT
12+
class Client
13+
14+
def initialize(sock, opts = {})
15+
@sock = sock
16+
@opts = opts
17+
end
18+
19+
def connect
20+
connect_opts = {
21+
client_id: @opts[:client_id],
22+
username: @opts[:username],
23+
password: @opts[:password]
24+
}
25+
connect = ::MQTT::Packet::Connect.new(connect_opts).to_s
26+
@sock.put(connect)
27+
res = @sock.get_once(-1, @opts[:read_timeout])
28+
::MQTT::Packet.parse(res)
29+
end
30+
31+
def connect?
32+
connect.return_code == 0
33+
end
34+
35+
def disconnect
36+
disconnect = ::MQTT::Packet::Disconnect.new().to_s
37+
@sock.put(disconnect)
38+
end
39+
end
40+
end
41+
end
42+
end

metasploit-framework.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ Gem::Specification.new do |spec|
123123
# Protocol Libraries
124124
#
125125
spec.add_runtime_dependency 'dnsruby'
126+
spec.add_runtime_dependency 'mqtt'
126127
spec.add_runtime_dependency 'net-ssh'
127128
spec.add_runtime_dependency 'rbnacl', ['< 5.0.0']
128129
spec.add_runtime_dependency 'bcrypt_pbkdf'

0 commit comments

Comments
 (0)