Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/ntp/ntp_monlist.rb
19515 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::Auxiliary::Report
8
include Msf::Exploit::Remote::Udp
9
include Msf::Auxiliary::UDPScanner
10
include Msf::Auxiliary::NTP
11
include Msf::Auxiliary::DRDoS
12
13
def initialize
14
super(
15
'Name' => 'NTP Monitor List Scanner',
16
'Description' => %q{
17
This module identifies NTP servers which permit "monlist" queries and
18
obtains the recent clients list. The monlist feature allows remote
19
attackers to cause a denial of service (traffic amplification)
20
via spoofed requests. The more clients there are in the list, the
21
greater the amplification.
22
},
23
'References' => [
24
['CVE', '2013-5211'],
25
['URL', 'https://www.cisa.gov/uscert/ncas/alerts/TA14-013A'],
26
['URL', 'https://support.ntp.org/bin/view/Main/SecurityNotice'],
27
['URL', 'https://nmap.org/nsedoc/scripts/ntp-monlist.html'],
28
],
29
'Author' => 'hdm',
30
'License' => MSF_LICENSE
31
)
32
33
register_options(
34
[
35
OptInt.new('RETRY', [false, "Number of tries to query the NTP server", 3]),
36
OptBool.new('SHOW_LIST', [false, 'Show the recent clients list', false])
37
]
38
)
39
40
register_advanced_options(
41
[
42
OptBool.new('StoreNTPClients', [true, 'Store NTP clients as host records in the database', false])
43
]
44
)
45
end
46
47
# Called for each response packet
48
def scanner_process(data, shost, sport)
49
@results[shost] ||= { messages: [], peers: [] }
50
@results[shost][:messages] << Rex::Proto::NTP::NTPPrivate.new.read(data).to_binary_s
51
@results[shost][:peers] << extract_peer_tuples(data)
52
end
53
54
# Called before the scan block
55
def scanner_prescan(batch)
56
@results = {}
57
@aliases = {}
58
@probe = Rex::Proto::NTP.ntp_private(datastore['VERSION'], datastore['IMPLEMENTATION'], 42, "\0" * 40).to_binary_s
59
end
60
61
# Called after the scan block
62
def scanner_postscan(batch)
63
@results.keys.each do |k|
64
response_map = { @probe => @results[k][:messages] }
65
peer = "#{k}:#{rport}"
66
67
# TODO: check to see if any of the responses are actually NTP before reporting
68
report_service(
69
:host => k,
70
:proto => 'udp',
71
:port => rport,
72
:name => 'ntp'
73
)
74
75
peers = @results[k][:peers].flatten(1)
76
unless peers.empty?
77
print_good("#{peer} NTP monlist request permitted (#{peers.length} entries)")
78
# store the peers found from the monlist
79
report_note(
80
:host => k,
81
:proto => 'udp',
82
:port => rport,
83
:type => 'ntp.monlist',
84
:data => { :monlist => peers }
85
)
86
# print out peers if desired
87
if datastore['SHOW_LIST']
88
peers.each do |ntp_peer|
89
print_status("#{peer} #{ntp_peer}")
90
end
91
end
92
# store any aliases for our target
93
report_note(
94
:host => k,
95
:proto => 'udp',
96
:port => rport,
97
:type => 'ntp.addresses',
98
:data => { :addresses => peers.map { |p| p.last }.sort.uniq }
99
)
100
101
if (datastore['StoreNTPClients'])
102
print_status("#{peer} Storing #{peers.length} NTP client hosts in the database...")
103
peers.each do |r|
104
maddr, mport, mserv = r
105
next if maddr == '127.0.0.1' # some NTP servers peer with themselves..., but we can't store loopback
106
107
report_note(
108
:host => maddr,
109
:type => 'ntp.client.history',
110
:data => {
111
:address => maddr,
112
:port => mport,
113
:server => mserv
114
}
115
)
116
end
117
end
118
end
119
120
vulnerable, proof = prove_amplification(response_map)
121
what = 'NTP Mode 7 monlist DRDoS (CVE-2013-5211)'
122
if vulnerable
123
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
124
report_vuln({
125
:host => k,
126
:port => rport,
127
:proto => 'udp',
128
:name => what,
129
:refs => self.references
130
})
131
else
132
vprint_status("#{peer} - Not vulnerable to #{what}: #{proof}")
133
end
134
end
135
end
136
137
# Examine the monlist response +data+ and extract all peer tuples (saddd, dport, daddr)
138
def extract_peer_tuples(data)
139
return [] if data.length < 76
140
141
# NTP headers 8 bytes
142
ntp_flags, ntp_auth, ntp_vers, ntp_code = data.slice!(0, 4).unpack('C*')
143
pcnt, plen = data.slice!(0, 4).unpack('nn')
144
return [] if plen != 72
145
146
idx = 0
147
peer_tuples = []
148
1.upto(pcnt) do
149
# u_int32 firsttime; /* first time we received a packet */
150
# u_int32 lasttime; /* last packet from this host */
151
# u_int32 restr; /* restrict bits (was named lastdrop) */
152
# u_int32 count; /* count of packets received */
153
# u_int32 addr; /* host address V4 style */
154
# u_int32 daddr; /* destination host address */
155
# u_int32 flags; /* flags about destination */
156
# u_short port; /* port number of last reception */
157
158
_, _, _, _, saddr, daddr, _, dport = data[idx, 30].unpack("NNNNNNNn")
159
160
peer_tuples << [ Rex::Socket.addr_itoa(saddr), dport, Rex::Socket.addr_itoa(daddr) ]
161
idx += plen
162
end
163
peer_tuples
164
end
165
end
166
167