Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/scanner/discovery/udp_sweep.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'openssl'67class MetasploitModule < Msf::Auxiliary8include Msf::Auxiliary::Report9include Msf::Auxiliary::UDPScanner1011def initialize12super(13'Name' => 'UDP Service Sweeper',14'Description' => 'Detect interesting UDP services',15'Author' => 'hdm',16'License' => MSF_LICENSE17)1819register_advanced_options(20[21OptBool.new('RANDOMIZE_PORTS', [false, 'Randomize the order the ports are probed', true])22])2324# RPORT is required by UDPScanner but not used in this module since it25# works with multiple ports.26# TODO: update this module to simply use Scanner or update UDPScanner to support27# multiple ports.28deregister_options('RPORT')2930# Initialize the probes array31@probes = []3233# Add the UDP probe method names34@probes << 'probe_pkt_dns'35@probes << 'probe_pkt_netbios'36@probes << 'probe_pkt_portmap'37@probes << 'probe_pkt_mssql'38@probes << 'probe_pkt_ntp'39@probes << 'probe_pkt_snmp1'40@probes << 'probe_pkt_snmp2'41@probes << 'probe_pkt_sentinel'42@probes << 'probe_pkt_db2disco'43@probes << 'probe_pkt_citrix'44@probes << 'probe_pkt_pca_st'45@probes << 'probe_pkt_pca_nq'46@probes << 'probe_chargen'47end4849def setup50super5152if datastore['RANDOMIZE_PORTS']53@probes = @probes.sort_by { rand }54end55end5657def scanner_prescan(batch)58print_status("Sending #{@probes.length} probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")59@results = {}60end6162def scan_host(ip)63@probes.each do |probe|64data, port = self.send(probe, ip)65scanner_send(data, ip, port)66end67end6869def scanner_postscan(batch)70@results.each_key do |k|71next if not @results[k].respond_to?('keys')72data = @results[k]7374conf = {75:host => data[:host],76:port => data[:port],77:proto => 'udp',78:name => data[:app],79:info => data[:info]80}8182if data[:hname]83conf[:host_name] = data[:hname].downcase84end8586if data[:mac]87conf[:mac] = data[:mac].downcase88end8990report_service(conf)91print_good("Discovered #{data[:app]} on #{k} (#{data[:info]})")92end93end949596def scanner_process(data, shost, sport)9798hkey = "#{shost}:#{sport}"99app = 'unknown'100inf = ''101maddr = nil102hname = nil103104# Work with protocols that return different data in different packets105# These are reported at the end of the scanning loop to build state106case sport107when 5632108109@results[hkey] ||= {}110data = @results[hkey]111data[:app] = "pcAnywhere_stat"112data[:port] = sport113data[:host] = shost114115case data116117when /^NR(........................)(........)/118name = $1.dup119caps = $2.dup120name = name.gsub(/_+$/, '').gsub("\x00", '').strip121caps = caps.gsub(/_+$/, '').gsub("\x00", '').strip122data[:name] = name123data[:caps] = caps124125when /^ST(.+)/126buff = $1.dup127stat = 'Unknown'128129if buff[2,1].unpack("C")[0] == 67130stat = "Available"131end132133if buff[2,1].unpack("C")[0] == 11134stat = "Busy"135end136137data[:stat] = stat138end139140if data[:name]141inf << "Name: #{data[:name]} "142end143144if data[:stat]145inf << "- #{data[:stat]} "146end147148if data[:caps]149inf << "( #{data[:caps]} ) "150end151data[:info] = inf152end153154# Ignore duplicates155return if @results[hkey]156157case sport158159when 19160app = 'chargen'161ver = nil162return unless chargen_parse(data)163@results[hkey] = true164165when 53166app = 'DNS'167ver = nil168169if (not ver and data =~ /([6789]\.[\w\.\-_\:\(\)\[\]\/\=\+\|\{\}]+)/i)170ver = 'BIND ' + $1171end172173ver = 'Microsoft DNS' if (not ver and data[2,4] == "\x81\x04\x00\x01")174ver = 'TinyDNS' if (not ver and data[2,4] == "\x81\x81\x00\x01")175176ver = data.unpack('H*')[0] if not ver177inf = ver if ver178179@results[hkey] = true180181when 137182app = 'NetBIOS'183184buff = data.dup185186head = buff.slice!(0,12)187188xid, flags, quests, answers, auths, adds = head.unpack('n6')189return if quests != 0190return if answers == 0191192qname = buff.slice!(0,34)193rtype,rclass,rttl,rlen = buff.slice!(0,10).unpack('nnNn')194bits = buff.slice!(0,rlen)195196names = []197198case rtype199when 0x21200rcnt = bits.slice!(0,1).unpack("C")[0]2011.upto(rcnt) do202tname = bits.slice!(0,15).gsub(/\x00.*/, '').strip203ttype = bits.slice!(0,1).unpack("C")[0]204tflag = bits.slice!(0,2).unpack('n')[0]205names << [ tname, ttype, tflag ]206end207maddr = bits.slice!(0,6).unpack("C*").map{|c| "%.2x" % c }.join(":")208209names.each do |name|210inf << name[0]211inf << ":<%.2x>" % name[1]212if (name[2] & 0x8000 == 0)213inf << ":U :"214else215inf << ":G :"216end217end218inf << maddr219220if(names.length > 0)221hname = names[0][0]222end223end224225@results[hkey] = true226227when 111228app = 'Portmap'229buf = data230inf = ""231hed = buf.slice!(0,24)232svc = []233while(buf.length >= 20)234rec = buf.slice!(0,20).unpack("N5")235svc << "#{rec[1]} v#{rec[2]} #{rec[3] == 0x06 ? "TCP" : "UDP"}(#{rec[4]})"236report_service(237:host => shost,238:port => rec[4],239:proto => (rec[3] == 0x06 ? "tcp" : "udp"),240:name => "sunrpc",241:info => "#{rec[1]} v#{rec[2]}",242:state => "open"243)244end245inf = svc.join(", ")246247@results[hkey] = true248249when 123250app = 'NTP'251ver = nil252ver = data.unpack('H*')[0]253ver = 'NTP v3' if (ver =~ /^1c06|^1c05/)254ver = 'NTP v4' if (ver =~ /^240304/)255ver = 'NTP v4 (unsynchronized)' if (ver =~ /^e40/)256ver = 'Microsoft NTP' if (ver =~ /^dc00|^dc0f/)257inf = ver if ver258259@results[hkey] = true260261when 1434262app = 'MSSQL'263mssql_ping_parse(data).each_pair { |k,v|264inf += k+'='+v+' '265}266267@results[hkey] = true268269when 161270app = 'SNMP'271asn = OpenSSL::ASN1.decode(data) rescue nil272return if not asn273274snmp_error = asn.value[0].value rescue nil275snmp_comm = asn.value[1].value rescue nil276snmp_data = asn.value[2].value[3].value[0] rescue nil277snmp_oid = snmp_data.value[0].value rescue nil278snmp_info = snmp_data.value[1].value rescue nil279280return if not (snmp_error and snmp_comm and snmp_data and snmp_oid and snmp_info)281snmp_info = snmp_info.to_s.gsub(/\s+/, ' ')282283inf = snmp_info284com = snmp_comm285286@results[hkey] = true287288when 5093289app = 'Sentinel'290@results[hkey] = true291292when 523293app = 'ibm-db2'294inf = db2disco_parse(data)295@results[hkey] = true296297when 1604298app = 'citrix-ica'299return unless citrix_parse(data)300@results[hkey] = true301302end303304report_service(305:host => shost,306:mac => (maddr and maddr != '00:00:00:00:00:00') ? maddr : nil,307:host_name => (hname) ? hname.downcase : nil,308:port => sport,309:proto => 'udp',310:name => app,311:info => inf,312:state => "open"313)314315print_status("Discovered #{app} on #{shost}:#{sport} (#{inf})")316end317318#319# Validate a chargen packet.320#321def chargen_parse(data)322data =~ /ABCDEFGHIJKLMNOPQRSTUVWXYZ|0123456789/i323end324325#326# Parse a db2disco packet.327#328def db2disco_parse(data)329res = data.split("\x00")330"#{res[2]}_#{res[1]}"331end332333#334# Validate this is truly Citrix ICA; returns true or false.335#336def citrix_parse(data)337server_response = "\x30\x00\x02\x31\x02\xfd\xa8\xe3\x02\x00\x06\x44" # Server hello response338data =~ /^#{server_response}/339end340341#342# Parse a 'ping' response and format as a hash343#344def mssql_ping_parse(data)345res = {}346var = nil347idx = data.index('ServerName')348return res if not idx349350data[idx, data.length-idx].split(';').each do |d|351if (not var)352var = d353else354if (var.length > 0)355res[var] = d356var = nil357end358end359end360361return res362end363364#365# The probe definitions366#367368def probe_chargen(ip)369pkt = Rex::Text.rand_text_alpha_lower(1)370return [pkt, 19]371end372373def probe_pkt_dns(ip)374data = [rand(0xffff)].pack('n') +375"\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00"+376"\x07"+ "VERSION"+377"\x04"+ "BIND"+378"\x00\x00\x10\x00\x03"379380return [data, 53]381end382383def probe_pkt_netbios(ip)384data =385[rand(0xffff)].pack('n')+386"\x00\x00\x00\x01\x00\x00\x00\x00"+387"\x00\x00\x20\x43\x4b\x41\x41\x41"+388"\x41\x41\x41\x41\x41\x41\x41\x41"+389"\x41\x41\x41\x41\x41\x41\x41\x41"+390"\x41\x41\x41\x41\x41\x41\x41\x41"+391"\x41\x41\x41\x00\x00\x21\x00\x01"392393return [data, 137]394end395396def probe_pkt_portmap(ip)397data =398[399rand(0xffffffff), # XID4000, # Type4012, # RPC Version402100000, # Program ID4032, # Program Version4044, # Procedure4050, 0, # Credentials4060, 0, # Verifier407].pack('N*')408409return [data, 111]410end411412def probe_pkt_mssql(ip)413return ["\x02", 1434]414end415416def probe_pkt_ntp(ip)417data =418"\xe3\x00\x04\xfa\x00\x01\x00\x00\x00\x01\x00\x00\x00" +419"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +420"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +421"\x00\xc5\x4f\x23\x4b\x71\xb1\x52\xf3"422return [data, 123]423end424425426def probe_pkt_sentinel(ip)427return ["\x7a\x00\x00\x00\x00\x00", 5093]428end429430def probe_pkt_snmp1(ip)431version = 1432data = OpenSSL::ASN1::Sequence([433OpenSSL::ASN1::Integer(version - 1),434OpenSSL::ASN1::OctetString("public"),435OpenSSL::ASN1::Set.new([436OpenSSL::ASN1::Integer(rand(0x80000000)),437OpenSSL::ASN1::Integer(0),438OpenSSL::ASN1::Integer(0),439OpenSSL::ASN1::Sequence([440OpenSSL::ASN1::Sequence([441OpenSSL::ASN1.ObjectId("1.3.6.1.2.1.1.1.0"),442OpenSSL::ASN1.Null(nil)443])444]),445], 0, :IMPLICIT)446]).to_der447[data, 161]448end449450def probe_pkt_snmp2(ip)451version = 2452data = OpenSSL::ASN1::Sequence([453OpenSSL::ASN1::Integer(version - 1),454OpenSSL::ASN1::OctetString("public"),455OpenSSL::ASN1::Set.new([456OpenSSL::ASN1::Integer(rand(0x80000000)),457OpenSSL::ASN1::Integer(0),458OpenSSL::ASN1::Integer(0),459OpenSSL::ASN1::Sequence([460OpenSSL::ASN1::Sequence([461OpenSSL::ASN1.ObjectId("1.3.6.1.2.1.1.1.0"),462OpenSSL::ASN1.Null(nil)463])464]),465], 0, :IMPLICIT)466]).to_der467[data, 161]468end469470def probe_pkt_db2disco(ip)471data = "DB2GETADDR\x00SQL05000\x00"472[data, 523]473end474475def probe_pkt_citrix(ip) # Server hello packet from citrix_published_bruteforce476data =477"\x1e\x00\x01\x30\x02\xfd\xa8\xe3\x00\x00\x00\x00\x00" +478"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +479"\x00\x00\x00\x00"480return [data, 1604]481end482483def probe_pkt_pca_st(ip)484return ["ST", 5632]485end486487def probe_pkt_pca_nq(ip)488return ["NQ", 5632]489end490end491492493