Rspec tests, get_broker_port addition

This commit is contained in:
Jack Heysel 2023-06-22 01:29:33 -04:00
parent e49e70ce93
commit 64b441be2a
3 changed files with 92 additions and 21 deletions

View File

@ -3,10 +3,11 @@
module Msf
###
#
# This module provides methods for working with Arista equipment
# This module provides methods for working with Apache RocketMQ
#
###
module Auxiliary::Rocketmq
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super
register_options([ Opt::RPORT(9876) ], Msf::Auxiliary::Rocketmq)
@ -21,7 +22,6 @@ module Msf
begin
connect
vprint_status('Sending request')
sock.send(header + data_length + data, 0)
res = sock.recv(1024)
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
@ -41,6 +41,18 @@ module Msf
return nil
end
res
end
def get_rocketmq_version(id)
# This function takes an ID (number) and looks through rocketmq's index of verison numbers to find the real version number
# Errors will result in "UNKNOWN_VERSION_ID_<id>" and may be caused by needing to update the version table
# from https://github.com/apache/rocketmq/blob/develop/common/src/4d82b307ef50f5cba5717d0ebafeb3cabf336873/java/org/apache/rocketmq/common/MQVersion.java
version_list = JSON.parse(File.read(::File.join(Msf::Config.data_directory, 'rocketmq_versions_list.json'), mode: 'rb'))
version_list.fetch(id, "UNKNOWN_VERSION_ID_#{id}").gsub('_', '.')
end
def parse_rocketmq_data(res)
# remove a response header so we have json-ish data
res = res[8..]
@ -63,15 +75,39 @@ module Msf
vprint_error("Unable to parse json data: #{j}")
next
end
result
parsed_data = {}
result.each do |j|
parsed_data['version'] = get_rocketmq_version(j['version']) if j['version']
parsed_data['brokerDatas'] = j['brokerDatas'] if j['brokerDatas']
end
if parsed_data == {} || parsed_data['version'].nil?
vprint_error('Unable to find version or other data within response.')
return
end
parsed_data
end
def get_rocketmq_version(id)
# This function takes an ID (number) and looks through rocketmq's index of verison numbers to find the real version number
# Errors will result in "UNKNOWN_VERSION_ID_<id>" and may be caused by needing to update the version table
# from https://github.com/apache/rocketmq/blob/develop/common/src/4d82b307ef50f5cba5717d0ebafeb3cabf336873/java/org/apache/rocketmq/common/MQVersion.java
version_list = JSON.parse(File.read(::File.join(Msf::Config.data_directory, 'rocketmq_versions_list.json'), mode: 'rb'))
version_list.fetch(id, "UNKNOWN_VERSION_ID_#{id}").gsub('_', '.')
def get_broker_port(brokerDatas, rhost)
# Example of brokerData:
# [{"brokerAddrs"=>{"0"=>"172.16.199.135:10911"}, "brokerName"=>"DESKTOP-8ATHH6O", "cluster"=>"DefaultCluster"}]
target_port = nil
brokerDatas.each do |brokerData|
brokerData.each do |key, broker_info|
next unless key == 'brokerAddrs'
broker_info.each do |_iterator, broker_endpoint|
next unless broker_endpoint.include?(rhost)
return broker_endpoint.match(/#{rhost}:(\d+)/)[1]
end
end
end
if target_port.nil?
print_status('autodetection failed, assuming default port of 10911')
target_port = 10911
end
target_port
end
end
end

View File

@ -42,17 +42,8 @@ class MetasploitModule < Msf::Auxiliary
return
end
parsed_data = {}
parsed_data = parse_rocketmq_data(res)
# grab some data that we need/want out of the response
res.each do |j|
parsed_data['version'] = get_rocketmq_version(j['version']) if j['version']
parsed_data['brokerDatas'] = j['brokerDatas'] if j['brokerDatas']
end
if parsed_data == {} || parsed_data['version'].nil?
vprint_error('Unable to find version or other data within response.')
return
end
output = "RocketMQ version #{parsed_data['version']}"
output += " found with brokers: #{parsed_data['brokerDatas']}" if parsed_data['brokerDatas']
print_good(output)

View File

@ -2,7 +2,8 @@ require 'spec_helper'
RSpec.describe Msf::Auxiliary::Rocketmq do
subject do
mod = Msf::Module.new
mod = Msf::Auxiliary.new
mod.extend(Msf::Exploit::Remote::Tcp)
mod.extend(Msf::Auxiliary::Rocketmq)
mod
end
@ -20,4 +21,47 @@ RSpec.describe Msf::Auxiliary::Rocketmq do
end
end
end
end
let(:expected_name_server_request) do
"\x00\x00\x00\xC7\x00\x00\x00\xC3{\"code\":105,\"extFields\":{\"Signature\":\"/u5P/wZUbhjanu4LM/UzEdo2u2I=\",\"topic\":\"TBW102\",\"AccessKey\":\"rocketmq2\"},\"flag\":0,\"language\":\"JAVA\",\"opaque\":1,\"serializeTypeCurrentRPC\":\"JSON\",\"version\":401}".b
end
let(:expected_name_server_response) do
"\x00\x00\x01a\x00\x00\x00_{\"code\":0,\"flag\":1,\"language\":\"JAVA\",\"opaque\":1,\"serializeTypeCurrentRPC\":\"JSON\",\"version\":403}{\"brokerDatas\":[{\"brokerAddrs\":{\"0\":\"172.16.199.135:10911\"},\"brokerName\":\"DESKTOP-8ATHH6O\",\"cluster\":\"DefaultCluster\"}],\"filterServerTable\":{},\"queueDatas\":[{\"brokerName\":\"DESKTOP-8ATHH6O\",\"perm\":7,\"readQueueNums\":8,\"topicSysFlag\":0,\"writeQueueNums\":8}]}".b
end
let(:expected_parsed_data_response) do
{"brokerDatas" => [{"brokerAddrs"=>{"0"=>"172.16.199.135:10911"}, "brokerName"=>"DESKTOP-8ATHH6O", "cluster"=>"DefaultCluster"}],
"version" => "V4.9.5"}
end
let(:mock_sock) { double :'Rex::Socket::Tcp', send: expected_name_server_request, recv: expected_name_server_response, close: nil, shutdown: nil }
before(:each) do
allow(subject).to receive(:connect).and_return(mock_sock)
allow(subject).to receive(:sock).and_return(mock_sock)
end
describe '#send_version_request' do
it 'returns version info' do
expect(mock_sock).to receive(:send).with(expected_name_server_request, 0)
expect(subject.send_version_request).to eq(expected_name_server_response)
end
end
describe '#parse_rocketmq_data' do
it 'correctly parses the response from the name server into version and brokeDatas info' do
expect(subject.parse_rocketmq_data(expected_name_server_response)).to eq(expected_parsed_data_response)
end
end
describe '#get_broker_port' do
it 'returns the broker port associated with the given rport in the name server response ' do
expect(subject.get_broker_port(expected_parsed_data_response, '172.16.199.135')).to eq(10911)
end
it 'returns the default broker port 10911 when rhost is not found in the name server response' do
expect(subject.get_broker_port(expected_parsed_data_response, '172.16.199.1')).to eq(10911)
end
end
end