Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/h323/h323_version.rb
19567 views
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
12
super(
13
'Name' => 'H.323 Version Scanner',
14
'Description' => 'Detect H.323 Version.',
15
'Author' => 'hdm',
16
'License' => MSF_LICENSE
17
)
18
19
register_options(
20
[
21
Opt::RPORT(1720),
22
]
23
)
24
end
25
26
def run_host(ip)
27
remote_display = nil
28
remote_product_id = nil
29
remote_version_id = nil
30
remote_vendor_id = nil
31
remote_protocol = nil
32
33
begin
34
# Wrap this in a timeout to prevent dead services from
35
# hanging this thread.
36
Timeout.timeout(call_timeout) do
37
connect
38
39
caller_name = "SYSTEM\x00"
40
h323_id = Rex::Text.rand_text_alpha(3)
41
vendor_id = Rex::Text.rand_text_alpha(32)
42
caller_host = Rex::Socket.source_address(ip)
43
caller_port = rand(32768) + 30000
44
callee_host = rhost
45
callee_port = rport
46
conf_guid = Rex::Text.rand_text(16)
47
call_guid = Rex::Text.rand_text(16)
48
49
pkt_setup = h323_setup_call({
50
:caller_name => caller_name,
51
:h323_id => h323_id,
52
:vendor_id => vendor_id,
53
:callee_host => callee_host,
54
:callee_port => callee_port,
55
:caller_host => caller_host,
56
:caller_port => caller_port,
57
:conf_guid => conf_guid,
58
:call_guid => call_guid
59
})
60
61
res = sock.put(pkt_setup) rescue nil
62
if not res
63
disconnect
64
return
65
end
66
67
cnt = 0
68
while (true)
69
info = read_packet
70
break if not info
71
72
# The remote side of the call disconnected us
73
break if info[:type] == @@H323_STATUS_RELEASE_COMPLETE
74
75
remote_display = info[40].strip if info[40]
76
remote_product_id = info[:product_id].strip if info[:product_id]
77
remote_version_id = info[:version_id].strip if info[:version_id]
78
remote_protocol = info[:protocol_version].strip if info[:protocol_version]
79
80
if info[:vendor_id] and [nil, "Unknown"].include?(remote_vendor_id)
81
remote_vendor_id = info[:vendor_id].strip
82
end
83
84
# Diagnostics
85
# print_status("Host: #{rhost}:#{rport} => #{info.inspect}")
86
87
# The remote side of the call was connected (kill it)
88
break if info[:type] == @@H323_STATUS_CONNECT
89
90
# Exit if we already received 5 packets from the server
91
break if (cnt += 1) > 5
92
93
end
94
95
# Make sure the call was shut down cleanly
96
pkt_release = h323_release_call({
97
:caller_name => caller_name,
98
:call_guid => call_guid
99
})
100
sock.put(pkt_release) rescue nil
101
102
# End timeout block
103
end
104
rescue ::Timeout::Error
105
rescue ::Interrupt
106
raise $!
107
rescue ::Rex::ConnectionError, ::IOError, ::Errno::ECONNRESET, ::Errno::ENOPROTOOPT
108
rescue ::Exception
109
print_error("#{rhost}:#{rport} #{$!.class} #{$!} #{$!.backtrace}")
110
ensure
111
disconnect
112
end
113
114
if remote_vendor_id
115
remote_product_id = remote_product_id.to_s.gsub(/[^\x20-\x7e]/, '')
116
remote_version_id = remote_version_id.to_s.gsub(/[^\x20-\x7e]/, '')
117
118
banner = "Protocol: #{remote_protocol} VendorID: #{remote_vendor_id} "
119
120
if remote_version_id and remote_version_id.length > 0
121
banner << "VersionID: #{remote_version_id} "
122
end
123
124
if remote_product_id and remote_product_id.length > 0
125
banner << "ProductID: #{remote_product_id} "
126
end
127
128
if remote_display and remote_display.length > 0
129
remote_display = remote_display.to_s.gsub(/[^\x20-\x7e]/, '')
130
banner << "DisplayName: #{remote_display}"
131
end
132
133
print_good("#{rhost}:#{rport} #{banner}")
134
report_service(:host => rhost, :port => rport, :name => "h323", :info => banner)
135
end
136
end
137
138
def read_packet
139
begin
140
::Timeout.timeout(read_timeout) do
141
ver = sock.read(2)
142
return if not (ver and ver == "\x03\x00")
143
144
bin = sock.read(2)
145
return if not bin
146
147
len = [ bin.unpack("n")[0] - 4, 0 ].max
148
return if len == 0
149
150
bin = sock.read(len)
151
return if not bin
152
153
f_desc, cref_len = bin.unpack("CC")
154
cref_val = bin[2, cref_len]
155
f_type = bin[2 + cref_len, 1].unpack("C")[0]
156
157
return { :type => f_type, :call_ref => cref_val }.merge(read_ies(f_type, bin[2 + cref_len + 1, bin.length]))
158
end
159
rescue ::Timeout::Error
160
end
161
nil
162
end
163
164
def read_ies(mtype, data)
165
r = {}
166
i = 0
167
168
while (i < (data.length - 1))
169
ie_type = data[i, 1].unpack("C")[0]
170
break if not ie_type
171
172
ie_len = 0
173
ie_data = ""
174
175
case ie_type
176
when @@H225_IE_USER_USER
177
ie_len = data[i + 1, 2].unpack("n")[0]
178
break if not ie_len
179
180
ie_data = data[i + 3, ie_len]
181
break if not ie_data
182
183
i = i + 3 + ie_len
184
else
185
ie_len = data[i + 1, 1].unpack("C")[0]
186
break if not ie_len
187
188
ie_data = data[i + 2, ie_len]
189
break if not ie_data
190
191
i = i + 2 + ie_len
192
end
193
194
r[ie_type] = ie_data
195
196
if ie_type == @@H225_IE_USER_USER
197
r.merge!((read_user_user(mtype, ie_data) rescue {}))
198
end
199
end
200
r
201
end
202
203
# This provides a weak method of decoding USER-USER PDUs. These are
204
# actually PER-encoded ASN.1, but we take a few shortcuts since PER
205
# encoding is such a pain.
206
def read_user_user(mtype, data)
207
r = {}
208
209
# Identify the embedded version (2/3/4/5/6 commonly found)
210
i = data.index("\x00\x08\x91\x4a\x00")
211
return r if not i
212
213
# Store the protocol version
214
pver = data[i + 5, 1].unpack("C")[0]
215
216
r[:protocol_version] = pver.to_s
217
218
# Bump the index over the version
219
i += 6
220
221
# print_line( Rex::Text.to_hex_dump( data[i, 32] ) )
222
223
# Set a placeholder VendorID so this system will be reported
224
r[:vendor_id] = "Unknown"
225
226
# We use the version offset to identify the destination block location
227
# This changes slightly based on the type of packet we receive
228
case mtype
229
when @@H323_STATUS_ALERTING, @@H323_STATUS_PROCEEDING
230
231
if pver == 2 and data[i, 2] == "\x20\x00"
232
r[:vendor_id] = "0x%.8x" % (data[i + 2, 4].unpack("N")[0] rescue 0)
233
return r
234
end
235
236
# Find the offset to the VendorID
237
if data[i + 1, 1] != "\xc0"
238
i += 7
239
end
240
241
# Stop processing if we can't identify a VendorID
242
return r if data[i + 1, 1] != "\xc0"
243
244
# Otherwise just add 2 to the offset of the version
245
i += 2
246
247
when @@H323_STATUS_CONNECT
248
249
# Bail early in some corner cases
250
return r if data[i, 1] == "\x00"
251
252
# Find the offset to the VendorID
253
if data[i + 1, 1] != "\xc0"
254
i += 7
255
end
256
257
# Stop processing if we can't identify a VendorID
258
return r if data[i + 1, 1] != "\xc0"
259
260
i += 2
261
262
return r
263
else
264
return r
265
end
266
267
# Extract the manufacturer ID
268
r[:vendor_id] = "0x%.8x" % (data[i, 4].unpack("N")[0] rescue 0)
269
i += 4
270
271
# No Product ID / Version ID in versions less than 3 (unless special cased above)
272
return r if pver < 3
273
274
# Get the product_id length (-1)
275
product_id_length = data[i, 1].unpack("C")[0] + 1
276
i += 1
277
278
# Extract the product ID
279
r[:product_id] = data[i, product_id_length]
280
i += product_id_length
281
282
# Get the version ID length (-1)
283
version_id_length = data[i, 1].unpack("C")[0] + 1
284
i += 1
285
286
# Extract the version ID
287
r[:version_id] = data[i, version_id_length]
288
289
# Thats it for now
290
291
r
292
end
293
294
def read_timeout
295
10
296
end
297
298
def call_timeout
299
30
300
end
301
302
@@H225_IE_BEARER_CAP = 0x04
303
@@H225_IE_DISPLAY = 0x28
304
@@H225_IE_USER_USER = 0x7e # Yes, really User-user
305
306
@@H323_STATUS_ALERTING = 0x01
307
@@H323_STATUS_PROCEEDING = 0x02
308
@@H323_STATUS_SETUP = 0x05
309
@@H323_STATUS_SETUP_ACK = 0x0D
310
@@H323_STATUS_CONNECT = 0x07
311
@@H323_STATUS_RELEASE_COMPLETE = 0x5a
312
@@H323_STATUS_FACILITY = 0x62
313
314
def encap_tpkt(ver, data)
315
[ ver, 0, data.length + 4 ].pack("CCn") + data
316
end
317
318
def encap_q225(desc, cref_value, msg_type, data)
319
[ desc, cref_value.length, cref_value, msg_type].pack("CCA*C") + data
320
end
321
322
def encap_q225_standard(msg_type, data)
323
encap_q225(0x08, [0x733f].pack("n"), msg_type, data)
324
end
325
326
def encap_q225_setup(data)
327
encap_q225_standard(0x05, data)
328
end
329
330
def encap_q225_release(data)
331
encap_q225_standard(0x5a, data)
332
end
333
334
def create_ie_byte(ie_type, data)
335
[ie_type, data.length].pack("CC") + data
336
end
337
338
def create_ie_short(ie_type, data)
339
[ie_type, data.length].pack("Cn") + data
340
end
341
342
def create_ie_bearer_capability(cap = 0x00038893)
343
create_ie_byte(@@H225_IE_BEARER_CAP, [cap].pack("N")[0, 3])
344
end
345
346
def create_ie_display(name = "DEBUG\x00")
347
create_ie_byte(@@H225_IE_DISPLAY, name)
348
end
349
350
def create_ie_user_user(data)
351
create_ie_short(@@H225_IE_USER_USER, data)
352
end
353
354
#
355
# This is ugly. Doing it properly requires a PER capable ASN.1 encoder, which is overkill for this task
356
#
357
def create_user_info(opts = {})
358
h323_id = opts[:h323_id]
359
vendor_id = opts[:vendor_id]
360
callee_host = opts[:callee_host]
361
callee_port = opts[:callee_port]
362
caller_host = opts[:caller_host]
363
caller_port = opts[:caller_port]
364
conf_guid = opts[:conf_guid]
365
call_guid = opts[:call_guid]
366
367
buff = "\x05" # Protocol descriminator: X.208/X.209 coded user information
368
369
buff << "\x20\xa8\x06\x00\x08\x91\x4a\x00\x06\x01\x40\x02"
370
371
# H323-ID
372
buff << h323_id.unpack("C*").pack("n*")
373
374
buff << "\x22\xc0\x09\x00\x00\x3d\x02\x00\x00\x00\x21"
375
376
# VENDOR: 32 + 2 null bytes
377
buff << [vendor_id].pack("Z32") + "\x00\x00"
378
379
buff << "\x00"
380
381
# Remote IP + Remote Port
382
buff << (::Rex::Socket.addr_aton(callee_host) + [ callee_port.to_i ].pack("n"))
383
384
buff << "\x00"
385
386
# Conference GUID
387
buff << conf_guid
388
389
buff << "\x00\xc5\x1d\x80\x04\x07\x00"
390
391
# Local IP + Port
392
buff << (::Rex::Socket.addr_aton(caller_host) + [ caller_port.to_i ].pack("n"))
393
394
buff << "\x11\x00"
395
396
# Call GUID
397
buff << call_guid
398
399
buff <<
400
"\x82\x49\x10\x47\x40\x00\x00\x06\x04\x01\x00\x4c\x10\xb5" +
401
"\x00\x00\x26\x25\x73\x70\x65\x65\x78\x20\x73\x72\x3d\x31" +
402
"\x36\x30\x30\x30\x3b\x6d\x6f\x64\x65\x3d\x36\x3b\x76\x62" +
403
"\x72\x3d\x6f\x66\x66\x3b\x63\x6e\x67\x3d\x6f\x66\x66\x80" +
404
"\x12\x1c\x40\x01\x00" +
405
Rex::Socket.addr_aton(caller_host) +
406
"\x13\xc6\x00" +
407
Rex::Socket.addr_aton(caller_host) +
408
"\x13\xc7\x90\x3c\x00\x00\x64\x0c\x10\xb5\x00\x00\x26\x25" +
409
"\x73\x70\x65\x65\x78\x20\x73\x72\x3d\x31\x36\x30\x30\x30" +
410
"\x3b\x6d\x6f\x64\x65\x3d\x36\x3b\x76\x62\x72\x3d\x6f\x66" +
411
"\x66\x3b\x63\x6e\x67\x3d\x6f\x66\x66\x80\x0b\x0d\x40\x01" +
412
"\x00" +
413
Rex::Socket.addr_aton(caller_host) +
414
"\x13\xc7\x48\x31\x40\x00\x00\x06\x04\x01\x00\x4c\x10\x09" +
415
"\x00\x00\x3d\x0f\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20" +
416
"\x57\x69\x64\x65\x36\x80\x12\x1c\x40\x01\x00" +
417
Rex::Socket.addr_aton(caller_host) +
418
"\x13\xc6\x00" +
419
Rex::Socket.addr_aton(caller_host) +
420
"\x13\xc7\xa0\x26\x00\x00\x65\x0c\x10\x09\x00\x00\x3d\x0f" +
421
"\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20\x57\x69\x64\x65" +
422
"\x36\x80\x0b\x0d\x40\x01\x00" +
423
Rex::Socket.addr_aton(caller_host) +
424
"\x13\xc7\x50\x1d\x40\x00\x00\x06\x04\x01\x00\x4c\x60\x13" +
425
"\x80\x11\x1c\x00\x01\x00" +
426
Rex::Socket.addr_aton(caller_host) +
427
"\x13\xc6\x00" +
428
Rex::Socket.addr_aton(caller_host) +
429
"\x13\xc7\x13\x00\x00\x66\x0c\x60\x13\x80\x0b\x0d\x00\x01" +
430
"\x00" +
431
Rex::Socket.addr_aton(caller_host) +
432
"\x13\xc7\x00\x1d\x40\x00\x00\x06\x04\x01\x00\x4c\x20\x13" +
433
"\x80\x11\x1c\x00\x01\x00" +
434
Rex::Socket.addr_aton(caller_host) +
435
"\x13\xc6\x00" +
436
Rex::Socket.addr_aton(caller_host) +
437
"\x13\xc7\x13\x00\x00\x67\x0c\x20\x13\x80\x0b\x0d\x00\x01" +
438
"\x00" +
439
Rex::Socket.addr_aton(caller_host) +
440
"\x13\xc7\x00\x23\x40\x00\x00\x06\x04\x01\x00\x48\x78\x00" +
441
"\x4a\xff\x00\x80\x01\x00\x80\x11\x1c\x00\x02\x00" +
442
Rex::Socket.addr_aton(caller_host) +
443
"\x13\xc8\x00" +
444
Rex::Socket.addr_aton(caller_host) +
445
"\x13\xc9\x19\x00\x00\x68\x08\x78\x00\x4a\xff\x00\x80\x01" +
446
"\x00\x80\x0b\x0d\x00\x02\x00" +
447
Rex::Socket.addr_aton(caller_host) +
448
"\x13\xc9\x00\x22\x40\x00\x00\x06\x04\x01\x00\x48\x68\x4a" +
449
"\xff\x00\x80\x01\x00\x80\x11\x1c\x00\x02\x00" +
450
Rex::Socket.addr_aton(caller_host) +
451
"\x13\xc8\x00" +
452
Rex::Socket.addr_aton(caller_host) +
453
"\x13\xc9\x18\x00\x00\x69\x08\x68\x4a\xff\x00\x80\x01\x00" +
454
"\x80\x0b\x0d\x00\x02\x00" +
455
Rex::Socket.addr_aton(caller_host) +
456
"\x13\xc9\x00\x22\x40\x00\x00\x06\x04\x01\x00\x48\x70\x4a" +
457
"\xff\x00\x80\x01\x00\x80\x11\x1c\x00\x02\x00" +
458
Rex::Socket.addr_aton(caller_host) +
459
"\x13\xc8\x00" +
460
Rex::Socket.addr_aton(caller_host) +
461
"\x13\xc9\x18\x00\x00\x6a\x08\x70\x4a\xff\x00\x80\x01\x00" +
462
"\x80\x0b\x0d\x00\x02\x00" +
463
Rex::Socket.addr_aton(caller_host) +
464
"\x13\xc9\x00\x2c\x40\x00\x00\x06\x04\x01\x00\x48\xee\x00" +
465
"\x00\x20\x9f\xff\x20\x50\x40\x01\x00\x80\x17\x1c\x20\x02" +
466
"\x00" +
467
Rex::Socket.addr_aton(caller_host) +
468
"\x13\xc8\x00" +
469
Rex::Socket.addr_aton(caller_host) +
470
"\x13\xc9\x80\x04\x48\x08\x8d\x44\x22\x00\x00\x6b\x08\xee" +
471
"\x00\x00\x20\x9f\xff\x20\x50\x40\x01\x00\x80\x11\x0d\x20" +
472
"\x02\x00" +
473
Rex::Socket.addr_aton(caller_host) +
474
"\x13\xc9\x40\x00\x04\x48\x08\x8d\x44\x01\x00\x01\x00\x01" +
475
"\x00\x01\x00\x80\xfa\x02\x80\xef\x02\x70\x01\x06\x00\x08" +
476
"\x81\x75\x00\x0d\x80\x1a\x80\x01\xf4\x00\x01\x00\x00\x01" +
477
"\x00\x00\x01\x00\x04\x02\x05\x00\x48\x08\x8d\x44\x06\x60" +
478
"\x01\x00\x01\x80\x0b\x80\x00\x00\x20\x20\xb5\x00\x00\x26" +
479
"\x25\x73\x70\x65\x65\x78\x20\x73\x72\x3d\x31\x36\x30\x30" +
480
"\x30\x3b\x6d\x6f\x64\x65\x3d\x36\x3b\x76\x62\x72\x3d\x6f" +
481
"\x66\x66\x3b\x63\x6e\x67\x3d\x6f\x66\x66\x80\x00\x01\x20" +
482
"\x20\x09\x00\x00\x3d\x0f\x53\x70\x65\x65\x78\x20\x62\x73" +
483
"\x34\x20\x57\x69\x64\x65\x36\x80\x00\x02\x20\xc0\xef\x80" +
484
"\x00\x03\x20\x40\xef\x80\x00\x04\x08\xf0\x00\x4a\xff\x00" +
485
"\x80\x01\x00\x80\x00\x05\x08\xd0\x4a\xff\x00\x80\x01\x00" +
486
"\x80\x00\x06\x08\xe0\x4a\xff\x00\x80\x01\x00\x80\x00\x07" +
487
"\x09\xdc\x00\x00\x40\x9f\xff\x20\x50\x40\x01\x00\x80\x00" +
488
"\x08\x83\x01\x50\x80\x00\x09\x83\x01\x10\x80\x00\x0a\x83" +
489
"\x01\x40\x80\x00\x0b\x8a\x0c\x14\x0a\x30\x2d\x31\x36\x2c" +
490
"\x33\x32\x2c\x33\x36\x00\x80\x01\x03\x03\x00\x00\x00\x01" +
491
"\x00\x02\x00\x03\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00" +
492
"\x00\x08\x02\x00\x09\x00\x0a\x00\x0b\x07\x01\x00\x32\x80" +
493
"\x96\x61\x41\x02\x80\x01\x80"
494
495
buff
496
end
497
498
def create_user_release_info(call_guid)
499
"\x05" +
500
"\x25\x80\x06\x00\x08\x91\x4a\x00\x05\x01\x11\x00" +
501
call_guid +
502
"\x02\x80\x01\x00"
503
end
504
505
def h323_release_call(opts = {})
506
caller_name = opts[:caller_name]
507
call_guid = opts[:call_guid]
508
509
encap_tpkt(3,
510
encap_q225_release(
511
create_ie_display(caller_name) +
512
create_ie_user_user(
513
create_user_release_info(call_guid)
514
)
515
))
516
end
517
518
def h323_setup_call(opts = {})
519
caller_name = opts[:caller_name]
520
h323_id = opts[:h323_id]
521
vendor_id = opts[:vendor_id]
522
callee_host = opts[:callee_host]
523
callee_port = opts[:callee_port]
524
caller_host = opts[:caller_host]
525
caller_port = opts[:caller_port]
526
conf_guid = opts[:conf_guid]
527
call_guid = opts[:call_guid]
528
529
encap_tpkt(3,
530
encap_q225_setup(
531
create_ie_bearer_capability() +
532
create_ie_display(caller_name) +
533
create_ie_user_user(
534
create_user_info({
535
:h323_id => h323_id,
536
:vendor_id => vendor_id,
537
:callee_host => callee_host,
538
:callee_port => callee_port,
539
:caller_host => caller_host,
540
:caller_port => caller_port,
541
:conf_guid => conf_guid,
542
:call_guid => call_guid
543
})
544
)
545
))
546
end
547
end
548
549