Land #9329, Add basic framework for interacting with MQTT

MS-2855/keylogger-mettle-extension
Jeffrey Martin 2017-12-27 14:59:34 -06:00
commit 8ea50572df
No known key found for this signature in database
GPG Key ID: 0CD9BBC2AF15F171
6 changed files with 127 additions and 0 deletions

View File

@ -20,6 +20,7 @@ PATH
metasploit-payloads (= 1.3.23) metasploit-payloads (= 1.3.23)
metasploit_data_models metasploit_data_models
metasploit_payloads-mettle (= 0.3.3) metasploit_payloads-mettle (= 0.3.3)
mqtt
msgpack msgpack
nessus_rest nessus_rest
net-ssh net-ssh
@ -192,6 +193,7 @@ GEM
method_source (0.9.0) method_source (0.9.0)
mini_portile2 (2.3.0) mini_portile2 (2.3.0)
minitest (5.10.3) minitest (5.10.3)
mqtt (0.5.0)
msgpack (1.2.0) msgpack (1.2.0)
multi_json (1.12.2) multi_json (1.12.2)
multipart-post (2.0.0) multipart-post (2.0.0)

View File

@ -23,6 +23,7 @@ require 'msf/core/auxiliary/cisco'
require 'msf/core/auxiliary/kademlia' require 'msf/core/auxiliary/kademlia'
require 'msf/core/auxiliary/llmnr' require 'msf/core/auxiliary/llmnr'
require 'msf/core/auxiliary/mdns' require 'msf/core/auxiliary/mdns'
require 'msf/core/auxiliary/mqtt'
require 'msf/core/auxiliary/nmap' require 'msf/core/auxiliary/nmap'
require 'msf/core/auxiliary/natpmp' require 'msf/core/auxiliary/natpmp'
require 'msf/core/auxiliary/iax2' require 'msf/core/auxiliary/iax2'

View File

@ -0,0 +1,67 @@
# -*- coding: binary -*-
require 'msf/core/exploit'
require 'rex/proto/mqtt'
module Msf
module Auxiliary::MQTT
def initialize(info = {})
super
register_options(
[
Opt::RPORT(Rex::Proto::MQTT::DEFAULT_PORT)
]
)
register_advanced_options(
[
OptString.new('CLIENT_ID', [false, 'The client ID to send if necessary for bypassing clientid_prefixes']),
OptInt.new('READ_TIMEOUT', [true, 'Seconds to wait while reading MQTT responses', 5])
]
)
register_autofilter_ports([Rex::Proto::MQTT::DEFAULT_PORT, Rex::Proto::MQTT::DEFAULT_SSL_PORT])
end
def setup
fail_with(Failure::BadConfig, 'READ_TIMEOUT must be > 0') if read_timeout <= 0
client_id_arg = datastore['CLIENT_ID']
if client_id_arg && client_id_arg.blank?
fail_with(Failure::BadConfig, 'CLIENT_ID must be a non-empty string')
end
end
def read_timeout
datastore['READ_TIMEOUT']
end
def client_id
datastore['CLIENT_ID'] || 'mqtt-' + Rex::Text.rand_text_alpha(1 + rand(10))
end
# creates a new mqtt client for use against the connected socket
def mqtt_client
client_opts = {
client_id: client_id,
username: datastore['USERNAME'],
password: datastore['PASSWORD'],
read_timeout: read_timeout
}
Rex::Proto::MQTT::Client.new(sock, client_opts)
end
def mqtt_connect(client)
client.connect
end
def mqtt_connect?(client)
client.connect?
end
def mqtt_disconnect(client)
client.disconnect
end
end
end

14
lib/rex/proto/mqtt.rb Normal file
View File

@ -0,0 +1,14 @@
# -*- coding: binary -*-
#
# Support for MQTT
require 'rex/proto/mqtt/client'
module Rex
module Proto
module MQTT
DEFAULT_PORT = 1883
DEFAULT_SSL_PORT = 8883
end
end
end

View File

@ -0,0 +1,42 @@
# -*- coding: binary -*-
require 'mqtt'
##
# MQTT protocol support
##
module Rex
module Proto
module MQTT
class Client
def initialize(sock, opts = {})
@sock = sock
@opts = opts
end
def connect
connect_opts = {
client_id: @opts[:client_id],
username: @opts[:username],
password: @opts[:password]
}
connect = ::MQTT::Packet::Connect.new(connect_opts).to_s
@sock.put(connect)
res = @sock.get_once(-1, @opts[:read_timeout])
::MQTT::Packet.parse(res)
end
def connect?
connect.return_code.zero?
end
def disconnect
disconnect = ::MQTT::Packet::Disconnect.new().to_s
@sock.put(disconnect)
end
end
end
end
end

View File

@ -123,6 +123,7 @@ Gem::Specification.new do |spec|
# Protocol Libraries # Protocol Libraries
# #
spec.add_runtime_dependency 'dnsruby' spec.add_runtime_dependency 'dnsruby'
spec.add_runtime_dependency 'mqtt'
spec.add_runtime_dependency 'net-ssh' spec.add_runtime_dependency 'net-ssh'
spec.add_runtime_dependency 'rbnacl', ['< 5.0.0'] spec.add_runtime_dependency 'rbnacl', ['< 5.0.0']
spec.add_runtime_dependency 'bcrypt_pbkdf' spec.add_runtime_dependency 'bcrypt_pbkdf'