CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/misc/ibm_mq_enum.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::Tcp
8
include Msf::Auxiliary::Scanner
9
include Msf::Auxiliary::Report
10
11
def initialize(info = {})
12
super(update_info(info,
13
'Name' => 'Identify Queue Manager Name and MQ Version',
14
'Description' => 'Run this auxiliary against the listening port of an IBM MQ Queue Manager to identify its name and version. Any channel type can be used to get this information as long as the name of the channel is valid.',
15
'Author' => [ 'Petros Koutroumpis' ],
16
'License' => MSF_LICENSE
17
))
18
register_options(
19
[
20
OptString.new('CHANNEL', [ true, "Channel to use" ,"SYSTEM.DEF.SVRCONN"]),
21
OptInt.new('CONCURRENCY', [true, "The number of concurrent ports to check per host", 10]),
22
OptInt.new('TIMEOUT', [true, "The socket connect timeout in seconds", 10]),
23
OptString.new('PORTS', [true, 'Ports to probe', '1414']),
24
25
])
26
deregister_options('RPORT')
27
end
28
29
30
def create_packet(channel_type)
31
chan = datastore['CHANNEL'] + "\x20"*(20-datastore['CHANNEL'].length.to_i)
32
if channel_type == 0
33
chan_type = "\x26"
34
elsif channel_type == 1
35
chan_type = "\x07"
36
elsif channel_type == 2
37
chan_type = "\x08"
38
end
39
40
packet = "\x54\x53\x48\x20" + # StructID
41
"\x00\x00\x01\x0c" + # MQSegmLen
42
"\x02" + # ByteOrder
43
"\x01" + # SegmType
44
"\x01" + # CtlFlag1
45
"\x00" + # CtlFlag2
46
"\x00\x00\x00\x00\x00\x00\x00\x00" + # LUW Ident
47
"\x22\x02\x00\x00" + # Encoding
48
"\xb5\x01" + # CCSID
49
"\x00\x00" + # Reserved
50
"\x49\x44\x20\x20" + # StructId
51
"\x0d" + # FAP level
52
chan_type + # CapFlag1 - Message Type
53
"\x00" + # ECapFlag1
54
"\x00" + # IniErrFlg1
55
"\x00\x00" + # Reserved
56
"\x32\x00" + # MaxMsgBtch
57
"\xec\x7f\x00\x00" + # MaxTrSize
58
"\x00\x00\x40\x00" + # MaxMsgSize
59
"\xff\xc9\x9a\x3b" + # SeqWrapVal
60
chan + # Channel Name
61
"\x87" + # CapFlag2
62
"\x00" + # ECapFlag2
63
"\x5b\x01" + # ccsid
64
"QM1" + "\x20"*45 + # Queue Manager Name
65
"\x2c\x01\x00\x00" + # HBInterval
66
"\x8a\x00" + # EFLLength
67
"\x00" + # IniErrFlg2
68
"\x55" + # Reserved1
69
"\x00\xff" + # HdrCprsLst
70
"\x00\xff\xff\xff\xff\xff\xff\xff\xff" + # MsgCprsLst1
71
"\xff\xff\xff\xff\xff\xff\xff" + # MsgCprsLst2
72
"\x00\x00" + # Reserved2
73
"\x00\x00\x00\x00" + # SSLKeyRst
74
"\x00\x00\x00\x00" + # ConvBySkt
75
"\x05" + # CapFlag3
76
"\x00" + # ECapFlag3
77
"\x00\x00" + # Reserved3
78
"\x10\x13\x00\x00" + # ProcessId
79
"\x01\x00\x00\x00" + # ThreadId
80
"\x01\x00\x00\x00" + # TraceId
81
"MQMM09000000" + # ProdId
82
"MQMID" + "\x20"*43 + # MQM ID
83
"\x00\x00\xff\xff\xff\xff\xff\xff\xff" + # Unknown1
84
"\xff\xff\xff\xff\xff\xff\xff\xff\xff" + # Unknown2
85
"\xff\xff\x00\x00\x00\x00\x00\x00\x00" + # Unknown3
86
"\x00\x00\x00\x00\x00" # Unknown4
87
end
88
89
90
def run_host(ip)
91
chan = datastore['CHANNEL']
92
if chan.length > 20
93
print_error("Channel name must be less than 20 characters.")
94
raise Msf::OptionValidateError.new(['CHANNEL'])
95
end
96
ports = Rex::Socket.portspec_crack(datastore['PORTS'])
97
while(ports.length > 0)
98
t = []
99
r = []
100
begin
101
1.upto(datastore['CONCURRENCY']) do
102
this_port = ports.shift
103
break if not this_port
104
t << framework.threads.spawn("Module(#{self.refname})-#{ip}:#{this_port}", false, this_port) do |port|
105
begin
106
data_recv = ""
107
3.times do |channel_type|
108
data_recv = send_packet(ip,port,channel_type)
109
if data_recv.nil?
110
next
111
end
112
# check if CHANNEL_WRONG_TYPE error received and retry with different type
113
if data_recv[data_recv.length-4...data_recv.length] != "\x02\x00\x00\x00"
114
break
115
end
116
end
117
if data_recv.nil?
118
print_status("No response received. Try increasing TIMEOUT value.")
119
print_line
120
next
121
end
122
status_code = data_recv[-4..-1]
123
if status_code == "\x18\x00\x00\x00"
124
print_status("Channel Requires SSL. Could not get more information.")
125
print_line
126
end
127
if not data_recv[0...3].include?('TSH')
128
next
129
end
130
if status_code == "\x01\x00\x00\x00"
131
print_error('Channel "' + chan + '" does not exist.')
132
print_line
133
end
134
if status_code == "\x02\x00\x00\x00" or status_code == "\x06\x00\x00\x00"
135
print_error('Unsupported channel type. Try a different channel.')
136
print_line
137
end
138
if data_recv.length < 180
139
next
140
end
141
qm_name = data_recv[76...124].delete(' ')
142
mq_version = data_recv[180...188].scan(/../).collect{|x| x.to_i}.join('.')
143
print_good("#{ip}:#{port} - Queue Manager Name: #{qm_name} - MQ Version: #{mq_version}")
144
print_line
145
end
146
end
147
end
148
t.each {|x| x.join }
149
end
150
end
151
end
152
153
def send_packet(ip,port,channel_type)
154
begin
155
timeout = datastore['TIMEOUT'].to_i
156
packet = create_packet(channel_type)
157
s = connect(false,
158
{
159
'RPORT' => port,
160
'RHOST' => ip,
161
}
162
)
163
s.put(packet)
164
data = s.get_once(-1,timeout)
165
return data
166
rescue ::Rex::ConnectionRefused
167
print_error("#{ip}:#{port} - TCP Port Closed.")
168
print_line
169
rescue ::Rex::ConnectionError, ::IOError, ::Timeout::Error, Errno::ECONNRESET
170
print_error("#{ip}:#{port} - Connection Failed.")
171
print_line
172
rescue ::Interrupt
173
raise $!
174
ensure
175
if s
176
disconnect(s) rescue nil
177
end
178
end
179
end
180
181
end
182
183