Skip to content

Commit 399a61d

Browse files
committed
Land rapid7#3946, ntp_readvar updates
2 parents 6ea5d20 + 8c8ccc1 commit 399a61d

File tree

1 file changed

+57
-36
lines changed

1 file changed

+57
-36
lines changed

modules/auxiliary/scanner/ntp/ntp_readvar.rb

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,62 +6,83 @@
66
require 'msf/core'
77

88
class Metasploit3 < Msf::Auxiliary
9-
10-
11-
include Msf::Exploit::Remote::Udp
129
include Msf::Auxiliary::Report
13-
include Msf::Auxiliary::Scanner
14-
10+
include Msf::Exploit::Remote::Udp
11+
include Msf::Auxiliary::UDPScanner
12+
include Msf::Auxiliary::NTP
13+
include Msf::Auxiliary::DRDoS
1514

1615
def initialize(info = {})
1716
super(update_info(info,
1817
'Name' => 'NTP Clock Variables Disclosure',
19-
'Description' => %q{
20-
This module reads the system internal NTP variables. These variables contain
18+
'Description' => %q(
19+
This module reads the system internal NTP variables. These variables contain
2120
potentially sensitive information, such as the NTP software version, operating
2221
system version, peers, and more.
23-
},
24-
'Author' => [ 'Ewerson Guimaraes(Crash) <crash[at]dclabs.com.br>' ],
22+
),
23+
'Author' =>
24+
[
25+
'Ewerson Guimaraes(Crash) <crash[at]dclabs.com.br>', # original Metasploit module
26+
'Jon Hart <jon_hart[at]rapid7.com>' # UDPScanner version for faster scans
27+
],
2528
'License' => MSF_LICENSE,
2629
'References' =>
2730
[
28-
[ 'URL','http://www.rapid7.com/vulndb/lookup/ntp-clock-variables-disclosure' ],
31+
[ 'URL', 'http://www.rapid7.com/vulndb/lookup/ntp-clock-variables-disclosure' ]
2932
]
3033
)
3134
)
32-
register_options(
33-
[
34-
Opt::RPORT(123)
35-
], self.class)
3635
end
3736

38-
def run_host(ip)
37+
def scanner_process(data, shost, _sport)
38+
@results[shost] ||= []
39+
@results[shost] << Rex::Proto::NTP::NTPControl.new(data)
40+
end
3941

40-
connect_udp
42+
def scan_host(ip)
43+
if spoofed?
44+
datastore['ScannerRecvWindow'] = 0
45+
scanner_spoof_send(@probe, ip, datastore['RPORT'], datastore['SRCIP'], datastore['NUM_REQUESTS'])
46+
else
47+
scanner_send(@probe, ip, datastore['RPORT'])
48+
end
49+
end
4150

42-
readvar = "\x16\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" #readvar command
43-
print_status("Connecting target #{rhost}:#{rport}...")
51+
def scanner_prescan(batch)
52+
@results = {}
53+
print_status("Sending NTP v2 READVAR probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
54+
@probe = Rex::Proto::NTP::NTPControl.new
55+
@probe.version = datastore['VERSION']
56+
@probe.operation = 2
57+
end
4458

45-
print_status("Sending command")
46-
udp_sock.put(readvar)
47-
reply = udp_sock.recvfrom(65535, 0.1)
48-
if not reply or reply[0].empty?
49-
print_error("#{rhost}:#{rport} - Couldn't read NTP variables")
50-
return
51-
end
52-
p_reply = reply[0].split(",")
53-
arr_count = 0
54-
while ( arr_count < p_reply.size)
55-
if arr_count == 0
56-
print_good("#{rhost}:#{rport} - #{p_reply[arr_count].slice(12,p_reply[arr_count].size)}") #12 is the adjustment of packet garbage
57-
arr_count = arr_count + 1
59+
def scanner_postscan(_batch)
60+
@results.keys.each do |k|
61+
# TODO: check to see if any of the responses are actually NTP before reporting
62+
report_service(
63+
host: k,
64+
proto: 'udp',
65+
port: rport,
66+
name: 'ntp',
67+
info: @results[k].map { |r| r.payload.slice(0,r.payload_size) }.join.inspect
68+
)
69+
70+
peer = "#{k}:#{rport}"
71+
response_map = { @probe => @results[k] }
72+
vulnerable, proof = prove_amplification(response_map)
73+
what = 'NTP Mode 6 READVAR DRDoS'
74+
if vulnerable
75+
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
76+
report_vuln(
77+
host: k,
78+
port: rport,
79+
proto: 'udp',
80+
name: what,
81+
refs: references
82+
)
5883
else
59-
print_good("#{rhost}:#{rport} - #{p_reply[arr_count].strip}")
60-
arr_count = arr_count + 1
84+
vprint_status("#{peer} - Not vulnerable to #{what}: #{proof}")
6185
end
6286
end
63-
disconnect_udp
64-
6587
end
66-
6788
end

0 commit comments

Comments
 (0)