module Msf class DBManager class Host < ActiveRecord::Base include DBSave belongs_to :workspace has_and_belongs_to_many :tags, :join_table => :hosts_tags has_many :services, :dependent => :destroy has_many :clients, :dependent => :destroy has_many :vulns, :dependent => :destroy has_many :notes, :dependent => :destroy has_many :loots, :dependent => :destroy, :order => "loots.created_at desc" has_many :sessions, :dependent => :destroy, :order => "sessions.opened_at" has_many :service_notes, :through => :services has_many :web_sites, :through => :services has_many :creds, :through => :services has_many :exploited_hosts, :dependent => :destroy validates_exclusion_of :address, :in => ['127.0.0.1'] validates_uniqueness_of :address, :scope => :workspace_id def attribute_locked?(attr) n = notes.find_by_ntype("host.updated.#{attr}") n && n.data[:locked] end # Determine if the fingerprint data is readable. If not, it nearly always # means that there was a problem with the YAML or the Marshal'ed data, # so let's log that for later investigation. def validate_fingerprint_data(fp) if fp.data.kind_of?(Hash) and !fp.data.empty? return true else dlog("Could not validate fingerprint data: #{fp.inspect}") return false end end # # Normalize the operating system fingerprints provided by various scanners # (nmap, nexpose, retina, nessus, etc). # # These are stored as notes (instead of directly in the os_* fields) # specifically for this purpose. # def normalize_os host = self wname = {} # os_name == Linux, Windows, Mac OS X, VxWorks wtype = {} # purpose == server, client, device wflav = {} # os_flavor == Ubuntu, Debian, 2003, 10.5, JetDirect wvers = {} # os_sp == 9.10, SP2, 10.5.3, 3.05 warch = {} # arch == x86, PPC, SPARC, MIPS, '' wlang = {} # os_lang == English, '' whost = {} # hostname wtype = {} # purpose # Note that we're already restricting the query to this host by using # host.notes instead of Note, so don't need a host_id in the # conditions. fingers = host.notes.find(:all, :conditions => [ "ntype like '%%fingerprint'" ] ) fingers.each do |fp| next if not validate_fingerprint_data(fp) norm = normalize_scanner_fp(fp) wvers[norm[:os_sp]] = wvers[norm[:os_sp]].to_i + (100 * norm[:certainty]) wname[norm[:os_name]] = wname[norm[:os_name]].to_i + (100 * norm[:certainty]) wflav[norm[:os_flavor]] = wflav[norm[:os_flavor]].to_i + (100 * norm[:certainty]) warch[norm[:arch]] = warch[norm[:arch]].to_i + (100 * norm[:certainty]) whost[norm[:name]] = whost[norm[:name]].to_i + (100 * norm[:certainty]) wtype[norm[:type]] = wtype[norm[:type]].to_i + (100 * norm[:certainty]) end # Grab service information and assign scores. Some services are # more trustworthy than others. If more services agree than not, # than that should be considered as well. # Each service has a starting number of points. Services that # are more difficult to fake are awarded more points. The points # represent a running total, not a fixed score. # XXX: This needs to be refactored in a big way. Tie-breaking is # pretty arbitrary, it would be nice to explicitly believe some # services over others, but that means recording which service # has an opinion and which doesn't. It would also be nice to # identify "impossible" combinations of services and alert that # something funny is going on. host.services.each do |s| next if not s.info points = 0 case s.name when 'smb' points = 210 case s.info when /\.el([23456])(\s+|$)/ # Match Samba 3.0.33-0.30.el4 as RHEL4 wname['Linux'] = wname['Linux'].to_i + points wflav["RHEL" + $1] = wflav["RHEL" + $1].to_i + points wtype['server'] = wtype['server'].to_i + points when /(ubuntu|debian|fedora|red ?hat|rhel)/i wname['Linux'] = wname['Linux'].to_i + points wflav[$1.capitalize] = wflav[$1.capitalize].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Windows/ win_sp = nil win_flav = nil win_lang = nil ninfo = s.info ninfo.gsub!('(R)', '') ninfo.gsub!('(TM)', '') ninfo.gsub!(/\s+/, ' ') ninfo.gsub!('No Service Pack', 'Service Pack 0') # Windows (R) Web Server 2008 6001 Service Pack 1 (language: Unknown) (name:PG-WIN2008WEB) (domain:WORKGROUP) # Windows XP Service Pack 3 (language: English) (name:EGYPT-B3E55BF3C) (domain:EGYPT-B3E55BF3C) # Windows 7 Ultimate (Build 7600) (language: Unknown) (name:WIN7) (domain:WORKGROUP) # Windows 2003 No Service Pack (language: Unknown) (name:VMWIN2003) (domain:PWNME) #if ninfo =~ /^Windows ([^\s]+)(.*)(Service Pack |\(Build )([^\(]+)\(/ if ninfo =~ /^Windows (.*)(Service Pack [^\s]+|\(Build [^\)]+\))/ win_flav = $1.strip win_sp = ($2).strip win_sp.gsub!(/with.*/, '') win_sp.gsub!('Service Pack', 'SP') win_sp.gsub!('Build', 'b') win_sp.gsub!(/\s+/, '') win_sp.tr!("()", '') else if ninfo =~ /^Windows ([^\s+]+)([^\(]+)\(/ win_flav = $2.strip end end if ninfo =~ /name: ([^\)]+)\)/ hostname = $1.strip end if ninfo =~ /language: ([^\)]+)\)/ win_lang = $1.strip end win_lang = nil if win_lang =~ /unknown/i win_vers = win_sp wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points wlang[win_lang] = wlang[win_lang].to_i + points if win_lang wflav[win_flav] = wflav[win_flav].to_i + points if win_flav wvers[win_vers] = wvers[win_vers].to_i + points if win_vers whost[hostname] = whost[hostname].to_i + points if hostname case win_flav when /NT|2003|2008/ win_type = 'server' else win_type = 'client' end wtype[win_type] = wtype[win_type].to_i + points end when 'ssh' points = 104 case s.info when /honeypot/i # Never trust this nil when /ubuntu/i # This needs to be above /debian/ becuase the ubuntu banner contains both, e.g.: # SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu6 wname['Linux'] = wname['Linux'].to_i + points wflav['Ubuntu'] = wflav['Ubuntu'].to_i + points wtype['server'] = wtype['server'].to_i + points when /debian/i wname['Linux'] = wname['Linux'].to_i + points wflav['Debian'] = wflav['Debian'].to_i + points wtype['server'] = wtype['server'].to_i + points when /FreeBSD/ wname['FreeBSD'] = wname['FreeBSD'].to_i + points wtype['server'] = wtype['server'].to_i + points when /sun_ssh/i wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points wtype['server'] = wtype['server'].to_i + points when /vshell|remotelyanywhere|freessh/i wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points wtype['server'] = wtype['server'].to_i + points when /radware/i wname['RadWare'] = wname['RadWare'].to_i + points wtype['device'] = wtype['device'].to_i + points when /dropbear/i wname['Linux'] = wname['Linux'].to_i + points wtype['device'] = wtype['device'].to_i + points when /netscreen/i wname['NetScreen'] = wname['NetScreen'].to_i + points wtype['device'] = wtype['device'].to_i + points when /vpn3/ wname['Cisco VPN 3000'] = wname['Cisco VPN 3000'].to_i + points wtype['device'] = wtype['device'].to_i + points when /cisco/i wname['Cisco IOS'] = wname['Cisco IOS'].to_i + points wtype['device'] = wtype['device'].to_i + points when /mpSSH/ wname['HP iLO'] = wname['HP iLO'].to_i + points wtype['server'] = wtype['server'].to_i + points end when 'http' points = 99 case s.info when /iSeries/ wname['IBM iSeries'] = wname['IBM iSeries'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Mandrake/i wname['Linux'] = wname['Linux'].to_i + points wflav['Mandrake'] = wflav['Mandrake'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Mandriva/i wname['Linux'] = wname['Linux'].to_i + points wflav['Mandrake'] = wflav['Mandrake'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Ubuntu/i wname['Linux'] = wname['Linux'].to_i + points wflav['Ubuntu'] = wflav['Ubuntu'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Debian/i wname['Linux'] = wname['Linux'].to_i + points wflav['Debian'] = wflav['Debian'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Fedora/i wname['Linux'] = wname['Linux'].to_i + points wflav['Fedora'] = wflav['Fedora'].to_i + points wtype['server'] = wtype['server'].to_i + points when /CentOS/i wname['Linux'] = wname['Linux'].to_i + points wflav['CentOS'] = wflav['CentOS'].to_i + points wtype['server'] = wtype['server'].to_i + points when /RHEL/i wname['Linux'] = wname['Linux'].to_i + points wflav['RHEL'] = wflav['RHEL'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Red.?Hat/i wname['Linux'] = wname['Linux'].to_i + points wflav['Red Hat'] = wflav['Red Hat'].to_i + points wtype['server'] = wtype['server'].to_i + points when /SuSE/i wname['Linux'] = wname['Linux'].to_i + points wflav['SUSE'] = wflav['SUSE'].to_i + points wtype['server'] = wtype['server'].to_i + points when /TurboLinux/i wname['Linux'] = wname['Linux'].to_i + points wflav['TurboLinux'] = wflav['TurboLinux'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Gentoo/i wname['Linux'] = wname['Linux'].to_i + points wflav['Gentoo'] = wflav['Gentoo'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Conectiva/i wname['Linux'] = wname['Linux'].to_i + points wflav['Conectiva'] = wflav['Conectiva'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Asianux/i wname['Linux'] = wname['Linux'].to_i + points wflav['Asianux'] = wflav['Asianux'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Trustix/i wname['Linux'] = wname['Linux'].to_i + points wflav['Trustix'] = wflav['Trustix'].to_i + points wtype['server'] = wtype['server'].to_i + points when /White Box/ wname['Linux'] = wname['Linux'].to_i + points wflav['White Box'] = wflav['White Box'].to_i + points wtype['server'] = wtype['server'].to_i + points when /UnitedLinux/ wname['Linux'] = wname['Linux'].to_i + points wflav['UnitedLinux'] = wflav['UnitedLinux'].to_i + points wtype['server'] = wtype['server'].to_i + points when /PLD\/Linux/ wname['Linux'] = wname['Linux'].to_i + points wflav['PLD/Linux'] = wflav['PLD/Linux'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Vine\/Linux/ wname['Linux'] = wname['Linux'].to_i + points wflav['Vine/Linux'] = wflav['Vine/Linux'].to_i + points wtype['server'] = wtype['server'].to_i + points when /rPath/ wname['Linux'] = wname['Linux'].to_i + points wflav['rPath'] = wflav['rPath'].to_i + points wtype['server'] = wtype['server'].to_i + points when /StartCom/ wname['Linux'] = wname['Linux'].to_i + points wflav['StartCom'] = wflav['StartCom'].to_i + points wtype['server'] = wtype['server'].to_i + points when /linux/i wname['Linux'] = wname['Linux'].to_i + points wtype['server'] = wtype['server'].to_i + points when /PalmOS/ wname['PalmOS'] = wname['PalmOS'].to_i + points wtype['device'] = wtype['device'].to_i + points when /Microsoft[\x20\x2d]IIS\/[234]\.0/ wname['Microsoft Windows NT 4.0'] = wname['Microsoft Windows NT 4.0'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Microsoft[\x20\x2d]IIS\/5\.0/ wname['Microsoft Windows 2000'] = wname['Microsoft Windows 2000'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Microsoft[\x20\x2d]IIS\/5\.1/ wname['Microsoft Windows XP'] = wname['Microsoft Windows XP'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Microsoft[\x20\x2d]IIS\/6\.0/ wname['Microsoft Windows 2003'] = wname['Microsoft Windows 2003'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Microsoft[\x20\x2d]IIS\/7\.0/ wname['Microsoft Windows 2008'] = wname['Microsoft Windows 2008'].to_i + points wtype['server'] = wtype['server'].to_i + points when /Win32/i wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points wtype['server'] = wtype['server'].to_i + points when /DD\-WRT ([^\s]+) /i wname['Linux'] = wname['Linux'].to_i + points wflav['DD-WRT'] = wflav['DD-WRT'].to_i + points wvers[$1.strip] = wvers[$1.strip].to_i + points wtype['server'] = wtype['server'].to_i + points when /Darwin/ wname['Apple Mac OS X'] = wname['Apple Mac OS X'].to_i + points when /FreeBSD/i wname['FreeBSD'] = wname['FreeBSD'].to_i + points when /OpenBSD/i wname['OpenBSD'] = wname['OpenBSD'].to_i + points when /NetBSD/i wname['NetBSD'] = wname['NetBSD'].to_i + points when /NetWare/i wname['Novell NetWare'] = wname['Novell NetWare'].to_i + points when /OpenVMS/i wname['OpenVMS'] = wname['OpenVMS'].to_i + points when /SunOS|Solaris/i wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points when /HP.?UX/i wname['HP-UX'] = wname['HP-UX'].to_i + points end when 'snmp' points = 103 case s.info when /^Sun SNMP Agent/ wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points wtype['server'] = wtype['server'].to_i + points when /^SunOS ([^\s]+) ([^\s]+) / # XXX 1/2 XXX what does this comment mean i wonder wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Linux ([^\s]+) ([^\s]+) / whost[$1] = whost[$1].to_i + points wname['Linux ' + $2] = wname['Linux ' + $2].to_i + points wvers[$2] = wvers[$2].to_i + points arch = get_arch_from_string(s.info) warch[arch] = warch[arch].to_i + points if arch wtype['server'] = wtype['server'].to_i + points when /^Novell NetWare ([^\s]+)/ wname['Novell NetWare ' + $1] = wname['Novell NetWare ' + $1].to_i + points wvers[$1] = wvers[$1].to_i + points arch = "x86" warch[arch] = warch[arch].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Novell UnixWare ([^\s]+)/ wname['Novell UnixWare ' + $1] = wname['Novell UnixWare ' + $1].to_i + points wvers[$1] = wvers[$1].to_i + points arch = "x86" warch[arch] = warch[arch].to_i + points wtype['server'] = wtype['server'].to_i + points when /^HP-UX ([^\s]+) ([^\s]+) / # XXX wname['HP-UX ' + $2] = wname['HP-UX ' + $2].to_i + points wvers[$1] = wvers[$1].to_i + points wtype['server'] = wtype['server'].to_i + points when /^IBM PowerPC.*Base Operating System Runtime AIX version: (\d+\.\d+)/ wname['IBM AIX ' + $1] = wname['IBM AIX ' + $1].to_i + points wvers[$1] = wvers[$1].to_i + points wtype['server'] = wtype['server'].to_i + points when /^SCO TCP\/IP Runtime Release ([^\s]+)/ wname['SCO UnixWare ' + $1] = wname['SCO UnixWare ' + $1].to_i + points wvers[$1] = wvers[$1].to_i + points wtype['server'] = wtype['server'].to_i + points when /.* IRIX version ([^\s]+)/ wname['SGI IRIX ' + $1] = wname['SGI IRIX ' + $1].to_i + points wvers[$1] = wvers[$1].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Unisys ([^\s]+) version ([^\s]+) kernel/ wname['Unisys ' + $2] = wname['Unisys ' + $2].to_i + points wvers[$2] = wvers[$2].to_i + points whost[$1] = whost[$1].to_i + points wtype['server'] = wtype['server'].to_i + points when /.*OpenVMS V([^\s]+) / # XXX wname['OpenVMS ' + $1] = wname['OpenVMS ' + $1].to_i + points wvers[$1] = wvers[$1].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Hardware:.*Software: Windows NT Version ([^\s]+) / wname['Microsoft Windows NT ' + $1] = wname['Microsoft Windows NT ' + $1].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Hardware:.*Software: Windows 2000 Version 5\.0/ wname['Microsoft Windows 2000'] = wname['Microsoft Windows 2000'].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Hardware:.*Software: Windows 2000 Version 5\.1/ wname['Microsoft Windows XP'] = wname['Microsoft Windows XP'].to_i + points wtype['server'] = wtype['server'].to_i + points when /^Hardware:.*Software: Windows Version 5\.2/ wname['Microsoft Windows 2003'] = wname['Microsoft Windows 2003'].to_i + points wtype['server'] = wtype['server'].to_i + points # XXX: TODO 2008, Vista, Windows 7 when /^Microsoft Windows CE Version ([^\s]+)+/ wname['Microsoft Windows CE ' + $1] = wname['Microsoft Windows CE ' + $1].to_i + points wtype['client'] = wtype['client'].to_i + points when /^IPSO ([^\s]+) ([^\s]+) / whost[$1] = whost[$1].to_i + points wname['Nokia IPSO ' + $2] = wname['Nokia IPSO ' + $2].to_i + points wvers[$2] = wvers[$2].to_i + points arch = get_arch_from_string(s.info) warch[arch] = warch[arch].to_s + points if arch wtype['device'] = wtype['device'].to_i + points when /^Sun StorEdge/ wname['Sun StorEdge'] = wname['Sun StorEdge'].to_i + points wtype['device'] = wtype['device'].to_i + points when /^HP StorageWorks/ wname['HP StorageWorks'] = wname['HP StorageWorks'].to_i + points wtype['device'] = wtype['device'].to_i + points when /^Network Storage/ # XXX wname['Network Storage Router'] = wname['Network Storage Router'].to_i + points wtype['device'] = wtype['device'].to_i + points when /Cisco Internetwork Operating System.*Version ([^\s]+)/ vers = $1.split(/[,^\s]/)[0] wname['Cisco IOS ' + vers] = wname['Cisco IOS ' + vers].to_i + points wvers[vers] = wvers[vers].to_i + points wtype['device'] = wtype['device'].to_i + points when /Cisco Catalyst.*Version ([^\s]+)/ vers = $1.split(/[,^\s]/)[0] wname['Cisco CatOS ' + vers] = wname['Cisco CatOS ' + vers].to_i + points wvers[vers] = wvers[vers].to_i + points wtype['device'] = wtype['device'].to_i + points when /Cisco 761.*Version ([^\s]+)/ vers = $1.split(/[,^\s]/)[0] wname['Cisco 761 ' + vers] = wname['Cisco 761 ' + vers].to_i + points wvers[vers] = wvers[vers].to_i + points wtype['device'] = wtype['device'].to_i + points when /Network Analysis Module.*Version ([^\s]+)/ vers = $1.split(/[,^\s]/)[0] wname['Cisco NAM ' + vers] = wname['Cisco NAM ' + vers].to_i + points wvers[vers] = wvers[vers].to_i + points wtype['device'] = wtype['device'].to_i + points when /VPN 3000 Concentrator Series Version ([^\s]+)/ vers = $1.split(/[,^\s]/)[0] wname['Cisco VPN 3000 ' + vers] = wname['Cisco VPN 3000 ' + vers].to_i + points wvers[vers] = wvers[vers].to_i + points wtype['device'] = wtype['device'].to_i + points when /ProCurve.*Switch/ wname['3Com ProCurve Switch'] = wname['3Com ProCurve Switch'].to_i + points wtype['device'] = wtype['device'].to_i + points when /ProCurve.*Access Point/ wname['3Com Access Point'] = wname['3Com Access Point'].to_i + points wtype['device'] = wtype['device'].to_i + points when /3Com.*Access Point/i wname['3Com Access Point'] = wname['3Com Access Point'].to_i + points wtype['device'] = wtype['device'].to_i + points when /ShoreGear/ wname['ShoreTel Appliance'] = wname['ShoreTel Appliance'].to_i + points wtype['device'] = wtype['device'].to_i + points when /firewall/i wname['Unknown Firewall'] = wname['Unknown Firewall'].to_i + points wtype['device'] = wtype['device'].to_i + points when /phone/i wname['Unknown Phone'] = wname['Unknown Phone'].to_i + points wtype['device'] = wtype['device'].to_i + points when /router/i wname['Unknown Router'] = wname['Unknown Router'].to_i + points wtype['device'] = wtype['device'].to_i + points when /switch/i wname['Unknown Switch'] = wname['Unknown Switch'].to_i + points wtype['device'] = wtype['device'].to_i + points # # Printer Signatures # when /^HP ETHERNET MULTI-ENVIRONMENT/ wname['HP Printer'] = wname['HP Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Canon/i wname['Canon Printer'] = wname['Canon Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Epson/i wname['Epson Printer'] = wname['Epson Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /ExtendNet/i wname['ExtendNet Printer'] = wname['ExtendNet Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Fiery/i wname['Fiery Printer'] = wname['Fiery Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Konica/i wname['Konica Printer'] = wname['Konica Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Lanier/i wname['Lanier Printer'] = wname['Lanier Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Lantronix/i wname['Lantronix Printer'] = wname['Lantronix Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Lexmark/i wname['Lexmark Printer'] = wname['Lexmark Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Magicolor/i wname['Magicolor Printer'] = wname['Magicolor Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Minolta/i wname['Minolta Printer'] = wname['Minolta Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /NetJET/i wname['NetJET Printer'] = wname['NetJET Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /OKILAN/i wname['OKILAN Printer'] = wname['OKILAN Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Phaser/i wname['Phaser Printer'] = wname['Phaser Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /PocketPro/i wname['PocketPro Printer'] = wname['PocketPro Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Ricoh/i wname['Ricoh Printer'] = wname['Ricoh Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Savin/i wname['Savin Printer'] = wname['Savin Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /SHARP AR/i wname['SHARP Printer'] = wname['SHARP Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Star Micronix/i wname['Star Micronix Printer'] = wname['Star Micronix Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Source Tech/i wname['Source Tech Printer'] = wname['Source Tech Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Xerox/i wname['Xerox Printer'] = wname['Xerox Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /^Brother/i wname['Brother Printer'] = wname['Brother Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /^Axis.*Network Print/i wname['Axis Printer'] = wname['Axis Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /^Prestige/i wname['Prestige Printer'] = wname['Prestige Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /^ZebraNet/i wname['ZebraNet Printer'] = wname['ZebraNet Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /e\-STUDIO/i wname['eStudio Printer'] = wname['eStudio Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /^Gestetner/i wname['Gestetner Printer'] = wname['Gestetner Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /IBM.*Print/i wname['IBM Printer'] = wname['IBM Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /HP (Color|LaserJet|InkJet)/i wname['HP Printer'] = wname['HP Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Dell (Color|Laser|Ink)/i wname['Dell Printer'] = wname['Dell Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points when /Print/i wname['Unknown Printer'] = wname['Unknown Printer'].to_i + points wtype['printer'] = wtype['printer'].to_i + points end # End of s.info for SNMP when 'telnet' points = 105 case s.info when /IRIX/ wname['SGI IRIX'] = wname['SGI IRIX'].to_i + points when /AIX/ wname['IBM AIX'] = wname['IBM AIX'].to_i + points when /(FreeBSD|OpenBSD|NetBSD)\/(.*) / wname[$1] = wname[$1].to_i + points arch = get_arch_from_string($2) warch[arch] = warch[arch].to_i + points when /Ubuntu (\d+(\.\d+)+)/ wname['Linux'] = wname['Linux'].to_i + points wflav['Ubuntu'] = wflav['Ubuntu'].to_i + points wvers[$1] = wvers[$1].to_i + points when /User Access Verification/ wname['Cisco IOS'] = wname['Cisco IOS'].to_i + points when /Microsoft/ wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points end # End of s.info for TELNET wtype['server'] = wtype['server'].to_i + points when 'smtp' points = 103 case s.info when /ESMTP.*SGI\.8/ wname['SGI IRIX'] = wname['SGI IRIX'].to_i + points wtype['server'] = wtype['server'].to_i + points end # End of s.info for SMTP when 'netbios' points = 201 case s.info when /W2K3/i wname['Microsoft Windows 2003'] = wname['Microsoft Windows 2003'].to_i + points wtype['server'] = wtype['server'].to_i + points when /W2K8/i wname['Microsoft Windows 2008'] = wname['Microsoft Windows 2008'].to_i + points wtype['server'] = wtype['server'].to_i + points end # End of s.info for NETBIOS when 'dns' points = 101 case s.info when 'Microsoft DNS' wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points wtype['server'] = wtype['server'].to_i + points end # End of s.info for DNS end # End of s.name case # End of Services end # # Report the best match here # best_match = {} best_match[:os_name] = wname.keys.sort{|a,b| wname[b] <=> wname[a]}[0] best_match[:purpose] = wtype.keys.sort{|a,b| wtype[b] <=> wtype[a]}[0] best_match[:os_flavor] = wflav.keys.sort{|a,b| wflav[b] <=> wflav[a]}[0] best_match[:os_sp] = wvers.keys.sort{|a,b| wvers[b] <=> wvers[a]}[0] best_match[:arch] = warch.keys.sort{|a,b| warch[b] <=> warch[a]}[0] best_match[:name] = whost.keys.sort{|a,b| whost[b] <=> whost[a]}[0] best_match[:os_lang] = wlang.keys.sort{|a,b| wlang[b] <=> wlang[a]}[0] best_match[:os_flavor] ||= "" if best_match[:os_name] # Handle cases where the flavor contains the base name # Don't use gsub!() here because the string was a hash key in a # previously life and gets frozen on 1.9.1, see #4128 best_match[:os_flavor] = best_match[:os_flavor].gsub(best_match[:os_name], '') end best_match[:os_name] ||= 'Unknown' best_match[:purpose] ||= 'device' [:os_name, :purpose, :os_flavor, :os_sp, :arch, :name, :os_lang].each do |host_attr| next if host.attribute_locked? host_attr if best_match[host_attr] host[host_attr] = Rex::Text.ascii_safe_hex(best_match[host_attr]) end end host.save if host.changed? end protected # # Convert a host.os.*_fingerprint Note into a hash containing the standard os_* fields # # Also includes a :certainty which is a float from 0 - 1.00 indicating the # scanner's confidence in its fingerprint. If the particular scanner does # not provide such information, defaults to 0.80. # # TODO: This whole normalize scanner procedure needs to be shoved off to its own # mixin. It's far too long and convoluted, has a ton of repeated code, and is # a massive hassle to update with new fingerprints. def normalize_scanner_fp(fp) return {} if not validate_fingerprint_data(fp) ret = {} data = fp.data case fp.ntype when 'host.os.session_fingerprint' # These come from meterpreter sessions' client.sys.config.sysinfo case data[:os] when /Windows/ ret.update(parse_windows_os_str(data[:os])) when /Linux ([^[:space:]]*) ([^[:space:]]*) .* (\(.*\))/ ret[:os_name] = "Linux" ret[:name] = $1 ret[:os_sp] = $2 ret[:arch] = get_arch_from_string($3) else ret[:os_name] = data[:os] end ret[:arch] = data[:arch] if data[:arch] ret[:name] = data[:name] if data[:name] when 'host.os.nmap_fingerprint', 'host.os.mbsa_fingerprint' # :os_vendor=>"Microsoft" :os_family=>"Windows" :os_version=>"2000" :os_accuracy=>"94" # # :os_match=>"Microsoft Windows Vista SP0 or SP1, Server 2008, or Windows 7 Ultimate (build 7000)" # :os_vendor=>"Microsoft" :os_family=>"Windows" :os_version=>"7" :os_accuracy=>"100" ret[:certainty] = data[:os_accuracy].to_f / 100.0 if (data[:os_vendor] == data[:os_family]) ret[:os_name] = data[:os_family] else ret[:os_name] = data[:os_vendor] + " " + data[:os_family] end ret[:os_flavor] = data[:os_version] ret[:name] = data[:hostname] if data[:hostname] when 'host.os.nexpose_fingerprint' # :family=>"Windows" :certainty=>"0.85" :vendor=>"Microsoft" :product=>"Windows 7 Ultimate Edition" # :family=>"Linux" :certainty=>"0.64" :vendor=>"Linux" :product=>"Linux" # :family=>"Linux" :certainty=>"0.80" :vendor=>"Ubuntu" :product=>"Linux" # :family=>"IOS" :certainty=>"0.80" :vendor=>"Cisco" :product=>"IOS" # :family=>"embedded" :certainty=>"0.61" :vendor=>"Linksys" :product=>"embedded" ret[:certainty] = data[:certainty].to_f case data[:family] when /AIX|ESX|Mac OS X|OpenSolaris|Solaris|IOS|Linux/ if data[:vendor] == data[:family] ret[:os_name] = data[:vendor] else # family often contains the vendor string, so rip it out to # avoid useless duplication ret[:os_name] = data[:vendor].to_s + " " + data[:family].to_s.gsub(data[:vendor].to_s, '').strip end when "Windows" ret[:os_name] = "Microsoft Windows" if data[:product] if data[:product][/2008/] && data[:version].to_i == 7 ret[:os_flavor] = "Windows 7" ret[:type] = "client" else ret[:os_flavor] = data[:product].gsub("Windows", '').strip ret[:os_sp] = data[:version] if data[:version] if data[:product] ret[:type] = "server" if data[:product][/Server/] ret[:type] = "client" if data[:product][/^(XP|ME)$/] end end end when "embedded" ret[:os_name] = data[:vendor] else ret[:os_name] = data[:vendor] end ret[:arch] = get_arch_from_string(data[:arch]) if data[:arch] ret[:arch] ||= get_arch_from_string(data[:desc]) if data[:desc] when 'host.os.retina_fingerprint' # :os=>"Windows Server 2003 (X64), Service Pack 2" case data[:os] when /Windows/ ret.update(parse_windows_os_str(data[:os])) else # No idea what this looks like if it isn't windows. Just store # the whole thing and hope for the best. XXX: Ghetto. =/ ret[:os_name] = data[:os] end when 'host.os.nessus_fingerprint' # :os=>"Microsoft Windows 2000 Advanced Server (English)" # :os=>"Microsoft Windows 2000\nMicrosoft Windows XP" # :os=>"Linux Kernel 2.6" # :os=>"Sun Solaris 8" # :os=>"IRIX 6.5" # Nessus sometimes jams multiple OS names together with a newline. oses = data[:os].split(/\n/) if oses.length > 1 # Multiple fingerprints means Nessus wasn't really sure, reduce # the certainty accordingly ret[:certainty] = 0.5 else ret[:certainty] = 0.8 end # Since there is no confidence associated with them, the best we # can do is just take the first one. case oses.first when /Windows/ ret.update(parse_windows_os_str(data[:os])) when /(2\.[46]\.\d+[-a-zA-Z0-9]+)/ # Linux kernel version ret[:os_name] = "Linux" ret[:os_sp] = $1 when /(.*)?((\d+\.)+\d+)$/ # Then we don't necessarily know what the os is, but this # fingerprint has some version information at the end, pull it # off. # When Nessus doesn't know what kind of linux it has, it gives an os like # "Linux Kernel 2.6" # The "Kernel" string is useless, so cut it off. ret[:os_name] = $1.gsub("Kernel", '').strip ret[:os_sp] = $2 else ret[:os_name] = oses.first end ret[:name] = data[:hname] when 'host.os.qualys_fingerprint' # :os=>"Microsoft Windows 2000" # :os=>"Windows 2003" # :os=>"Microsoft Windows XP Professional SP3" # :os=>"Ubuntu Linux" # :os=>"Cisco IOS 12.0(3)T3" case data[:os] when /Windows/ ret.update(parse_windows_os_str(data[:os])) else parts = data[:os].split(/\s+/, 3) ret[:os_name] = "" ret[:os_name] = parts[0] if parts[0] ret[:os_name] << " " + parts[1] if parts[1] ret[:os_sp] = parts[2] if parts[2] end # XXX: We should really be using smb_version's stored fingerprints # instead of parsing the service info manually. Disable for now so we # don't count smb twice. #when 'smb.fingerprint' # # smb_version is kind enough to store everything we need directly # ret.merge(fp.data) # # If it's windows, this should be a pretty high-confidence # # fingerprint. Otherwise, it's samba which doesn't give us much of # # anything in most cases. # ret[:certainty] = 1.0 if fp.data[:os_name] =~ /Windows/ else # If you've fallen through this far, you've hit a generalized # pass-through fingerprint parser. ret[:os_name] = data[:os_name] || data[:os] || data[:os_fingerprint] || "" ret[:type] = data[:os_purpose] if data[:os_purpose] ret[:arch] = data[:os_arch] if data[:os_arch] ret[:certainty] = data[:os_certainty] || 0.5 end ret[:certainty] ||= 0.8 ret end # # Take a windows version string and return a hash with fields suitable for # Host this object's version fields. # # A few example strings that this will have to parse: # sessions # Windows XP (Build 2600, Service Pack 3). # Windows .NET Server (Build 3790). # Windows 2008 (Build 6001, Service Pack 1). # retina # Windows Server 2003 (X64), Service Pack 2 # nessus # Microsoft Windows 2000 Advanced Server (English) # qualys # Microsoft Windows XP Professional SP3 # Windows 2003 # # Note that this list doesn't include nexpose or nmap, since they are # both kind enough to give us the various strings in seperate pieces # that we don't have to parse out manually. # def parse_windows_os_str(str) ret = {} ret[:os_name] = "Microsoft Windows" arch = get_arch_from_string(str) ret[:arch] = arch if arch if str =~ /(Service Pack|SP) ?(\d+)/ ret[:os_sp] = "SP#{$2}" end # Flavor case str when /\.NET Server/ ret[:os_flavor] = "2003" when /(XP|2000 Advanced Server|2000|2003|2008|SBS|Vista|7 .* Edition|7)/ ret[:os_flavor] = $1 else # If we couldn't pull out anything specific for the flavor, just cut # off the stuff we know for sure isn't it and hope for the best ret[:os_flavor] ||= str.gsub(/(Microsoft )?Windows|(Service Pack|SP) ?(\d+)/, '').strip end if str =~ /NT|2003|2008|SBS|Server/ ret[:type] = 'server' else ret[:type] = 'client' end ret end # A case switch to return a normalized arch based on a given string. def get_arch_from_string(str) case str when /x64|amd64|x86_64/i "x64" when /x86|i[3456]86/i "x86" when /PowerPC|PPC|POWER|ppc/ "ppc" when /SPARC/i "sparc" when /MIPS/i "mips" when /ARM/i "arm" else nil end end end end end