`##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::Udp
include Msf::Auxiliary::UDPScanner
include Msf::Auxiliary::NTP
include Msf::Auxiliary::DRDoS
def initialize
super(
'Name' => 'NTP Monitor List Scanner',
'Description' => %q{
This module identifies NTP servers which permit "monlist" queries and
obtains the recent clients list. The monlist feature allows remote
attackers to cause a denial of service (traffic amplification)
via spoofed requests. The more clients there are in the list, the
greater the amplification.
},
'References' =>
[
['CVE', '2013-5211'],
['URL', 'https://www.cisa.gov/uscert/ncas/alerts/TA14-013A'],
['URL', 'https://support.ntp.org/bin/view/Main/SecurityNotice'],
['URL', 'https://nmap.org/nsedoc/scripts/ntp-monlist.html'],
],
'Author' => 'hdm',
'License' => MSF_LICENSE
)
register_options(
[
OptInt.new('RETRY', [false, "Number of tries to query the NTP server", 3]),
OptBool.new('SHOW_LIST', [false, 'Show the recent clients list', false])
])
register_advanced_options(
[
OptBool.new('StoreNTPClients', [true, 'Store NTP clients as host records in the database', false])
])
end
# Called for each response packet
def scanner_process(data, shost, sport)
@results[shost] ||= { messages: [], peers: [] }
@results[shost][:messages] << Rex::Proto::NTP::NTPPrivate.new.read(data).to_binary_s
@results[shost][:peers] << extract_peer_tuples(data)
end
# Called before the scan block
def scanner_prescan(batch)
@results = {}
@aliases = {}
@probe = Rex::Proto::NTP.ntp_private(datastore['VERSION'], datastore['IMPLEMENTATION'], 42, "\0" * 40).to_binary_s
end
# Called after the scan block
def scanner_postscan(batch)
@results.keys.each do |k|
response_map = { @probe => @results[k][:messages] }
peer = "#{k}:#{rport}"
# TODO: check to see if any of the responses are actually NTP before reporting
report_service(
:host => k,
:proto => 'udp',
:port => rport,
:name => 'ntp'
)
peers = @results[k][:peers].flatten(1)
unless peers.empty?
print_good("#{peer} NTP monlist request permitted (#{peers.length} entries)")
# store the peers found from the monlist
report_note(
:host => k,
:proto => 'udp',
:port => rport,
:type => 'ntp.monlist',
:data => {:monlist => peers}
)
# print out peers if desired
if datastore['SHOW_LIST']
peers.each do |ntp_peer|
print_status("#{peer} #{ntp_peer}")
end
end
# store any aliases for our target
report_note(
:host => k,
:proto => 'udp',
:port => rport,
:type => 'ntp.addresses',
:data => {:addresses => peers.map { |p| p.last }.sort.uniq }
)
if (datastore['StoreNTPClients'])
print_status("#{peer} Storing #{peers.length} NTP client hosts in the database...")
peers.each do |r|
maddr,mport,mserv = r
next if maddr == '127.0.0.1' # some NTP servers peer with themselves..., but we can't store loopback
report_note(
:host => maddr,
:type => 'ntp.client.history',
:data => {
:address => maddr,
:port => mport,
:server => mserv
}
)
end
end
end
vulnerable, proof = prove_amplification(response_map)
what = 'NTP Mode 7 monlist DRDoS (CVE-2013-5211)'
if vulnerable
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
report_vuln({
:host => k,
:port => rport,
:proto => 'udp',
:name => what,
:refs => self.references
})
else
vprint_status("#{peer} - Not vulnerable to #{what}: #{proof}")
end
end
end
# Examine the monlist response +data+ and extract all peer tuples (saddd, dport, daddr)
def extract_peer_tuples(data)
return [] if data.length < 76
# NTP headers 8 bytes
ntp_flags, ntp_auth, ntp_vers, ntp_code = data.slice!(0,4).unpack('C*')
pcnt, plen = data.slice!(0,4).unpack('nn')
return [] if plen != 72
idx = 0
peer_tuples = []
1.upto(pcnt) do
# u_int32 firsttime; /* first time we received a packet */
# u_int32 lasttime; /* last packet from this host */
# u_int32 restr; /* restrict bits (was named lastdrop) */
# u_int32 count; /* count of packets received */
# u_int32 addr; /* host address V4 style */
# u_int32 daddr; /* destination host address */
# u_int32 flags; /* flags about destination */
# u_short port; /* port number of last reception */
_,_,_,_,saddr,daddr,_,dport = data[idx, 30].unpack("NNNNNNNn")
peer_tuples << [ Rex::Socket.addr_itoa(saddr), dport, Rex::Socket.addr_itoa(daddr) ]
idx += plen
end
peer_tuples
end
end
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation