Path: blob/master/modules/auxiliary/scanner/ntp/ntp_monlist.rb
19516 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::Udp8include Msf::Auxiliary::UDPScanner9include Msf::Auxiliary::NTP10include Msf::Auxiliary::DRDoS1112def initialize13super(14'Name' => 'NTP Monitor List Scanner',15'Description' => %q{16This module identifies NTP servers which permit "monlist" queries and17obtains the recent clients list. The monlist feature allows remote18attackers to cause a denial of service (traffic amplification)19via spoofed requests. The more clients there are in the list, the20greater the amplification.21},22'References' => [23['CVE', '2013-5211'],24['URL', 'https://www.cisa.gov/uscert/ncas/alerts/TA14-013A'],25['URL', 'https://support.ntp.org/bin/view/Main/SecurityNotice'],26['URL', 'https://nmap.org/nsedoc/scripts/ntp-monlist.html'],27],28'Author' => 'hdm',29'License' => MSF_LICENSE30)3132register_options(33[34OptInt.new('RETRY', [false, "Number of tries to query the NTP server", 3]),35OptBool.new('SHOW_LIST', [false, 'Show the recent clients list', false])36]37)3839register_advanced_options(40[41OptBool.new('StoreNTPClients', [true, 'Store NTP clients as host records in the database', false])42]43)44end4546# Called for each response packet47def scanner_process(data, shost, sport)48@results[shost] ||= { messages: [], peers: [] }49@results[shost][:messages] << Rex::Proto::NTP::NTPPrivate.new.read(data).to_binary_s50@results[shost][:peers] << extract_peer_tuples(data)51end5253# Called before the scan block54def scanner_prescan(batch)55@results = {}56@aliases = {}57@probe = Rex::Proto::NTP.ntp_private(datastore['VERSION'], datastore['IMPLEMENTATION'], 42, "\0" * 40).to_binary_s58end5960# Called after the scan block61def scanner_postscan(batch)62@results.keys.each do |k|63response_map = { @probe => @results[k][:messages] }64peer = "#{k}:#{rport}"6566# TODO: check to see if any of the responses are actually NTP before reporting67report_service(68:host => k,69:proto => 'udp',70:port => rport,71:name => 'ntp'72)7374peers = @results[k][:peers].flatten(1)75unless peers.empty?76print_good("#{peer} NTP monlist request permitted (#{peers.length} entries)")77# store the peers found from the monlist78report_note(79:host => k,80:proto => 'udp',81:port => rport,82:type => 'ntp.monlist',83:data => { :monlist => peers }84)85# print out peers if desired86if datastore['SHOW_LIST']87peers.each do |ntp_peer|88print_status("#{peer} #{ntp_peer}")89end90end91# store any aliases for our target92report_note(93:host => k,94:proto => 'udp',95:port => rport,96:type => 'ntp.addresses',97:data => { :addresses => peers.map { |p| p.last }.sort.uniq }98)99100if (datastore['StoreNTPClients'])101print_status("#{peer} Storing #{peers.length} NTP client hosts in the database...")102peers.each do |r|103maddr, mport, mserv = r104next if maddr == '127.0.0.1' # some NTP servers peer with themselves..., but we can't store loopback105106report_note(107:host => maddr,108:type => 'ntp.client.history',109:data => {110:address => maddr,111:port => mport,112:server => mserv113}114)115end116end117end118119vulnerable, proof = prove_amplification(response_map)120what = 'NTP Mode 7 monlist DRDoS (CVE-2013-5211)'121if vulnerable122print_good("#{peer} - Vulnerable to #{what}: #{proof}")123report_vuln({124:host => k,125:port => rport,126:proto => 'udp',127:name => what,128:refs => self.references129})130else131vprint_status("#{peer} - Not vulnerable to #{what}: #{proof}")132end133end134end135136# Examine the monlist response +data+ and extract all peer tuples (saddd, dport, daddr)137def extract_peer_tuples(data)138return [] if data.length < 76139140# NTP headers 8 bytes141ntp_flags, ntp_auth, ntp_vers, ntp_code = data.slice!(0, 4).unpack('C*')142pcnt, plen = data.slice!(0, 4).unpack('nn')143return [] if plen != 72144145idx = 0146peer_tuples = []1471.upto(pcnt) do148# u_int32 firsttime; /* first time we received a packet */149# u_int32 lasttime; /* last packet from this host */150# u_int32 restr; /* restrict bits (was named lastdrop) */151# u_int32 count; /* count of packets received */152# u_int32 addr; /* host address V4 style */153# u_int32 daddr; /* destination host address */154# u_int32 flags; /* flags about destination */155# u_short port; /* port number of last reception */156157_, _, _, _, saddr, daddr, _, dport = data[idx, 30].unpack("NNNNNNNn")158159peer_tuples << [ Rex::Socket.addr_itoa(saddr), dport, Rex::Socket.addr_itoa(daddr) ]160idx += plen161end162peer_tuples163end164end165166167