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/lib/rex/parser/nokogiri_doc_mixin.rb
Views: 11623
# -*- coding: binary -*-1module Rex2module Parser34# Determines if Nokogiri is available and if it's a minimum5# acceptable version.6def self.load_nokogiri7@nokogiri_loaded = false8begin9require 'nokogiri'10major,minor = Nokogiri::VERSION.split(".")[0,2]11if major.to_i >= 112if minor.to_i >= 413@nokogiri_loaded = true14end15end16rescue LoadError => e17@nokogiri_loaded = false18@nokogiri_error = e19end20@nokogiri_loaded21end2223def self.nokogiri_loaded24!!@nokogiri_loaded25end2627# Useful during development, shouldn't be used in normal operation.28def self.reload(fname)29$stdout.puts "Reloading #{fname}..."30load __FILE__31load File.join(File.expand_path(File.dirname(__FILE__)),fname)32end3334end35end3637module Rex38module Parser3940load_nokogiri && module NokogiriDocMixin4142# Set up the getters and instance variables for the document43eval("attr_reader :args, :db, :state, :block, :report_data")4445def initialize(args,db,&block)46@args = args47@db = db48@state = {}49@state[:current_tag] = {}50@block = block if block51@report_data = {:workspace => args[:workspace]}52@nx_console_id = args[:nx_console_id]53super()54end5556# Turn XML attribute pairs in to more workable hashes (there57# are better Enumerable tricks in Ruby 1.9, but ignoring for now)58def attr_hash(attrs)59h = {}60attrs.each {|k,v| h[k] = v}61h62end6364def valid_ip(addr)65valid = false66valid = ::Rex::Socket::RangeWalker.new(addr).valid? rescue false67!!valid68end6970def normalize_ref(ref_type, ref_value)71return if ref_type.nil? || ref_type.empty? || ref_value.nil? || ref_value.empty?72ref_value = ref_value.strip73ref_type = ref_type.strip.upcase7475ret = case ref_type76when "CVE"77ref_value.gsub("CAN", "CVE")78when "MS"79if ref_value =~ /^MS[0-9]/80"MSB-#{ref_value}"81else82"MSB-MS#{ref_value}"83end84when "URL", "BID"85"#{ref_type}-#{ref_value}"86when "APPLE"87ref_value88when "XF"89if ref_value =~ /\((\d+)\)$/90"#{ref_type}-#{$1}"91else92"#{ref_type}-#{ref_value}"93end94when "CB"95ref_value96when "DFN-CERT"97ref_value98else # Handle others?99"#{ref_type}-#{ref_value}"100end101return ret102end103104def normalize_references(orig_refs)105return [] unless orig_refs106refs = []107orig_refs.each do |ref_hash|108109ref_hash_sym = Hash[ref_hash.map {|k, v| [k.to_sym, v] }]110ref_type = ref_hash_sym[:source].to_s.strip.upcase111ref_value = ref_hash_sym[:value].to_s.strip112refs << normalize_ref(ref_type, ref_value)113end114return refs.compact.uniq115end116117def in_tag(tagname)118@state[:current_tag].keys.include? tagname119end120121# If there's an address, it's not on the blacklist,122# it has ports, and the port list isn't123# empty... it's okay.124def host_is_okay125return false unless @report_data[:host]126return false unless valid_ip(@report_data[:host])127return false unless @report_data[:state] == Msf::HostState::Alive128if @args[:blacklist]129return false if @args[:blacklist].include?(@report_data[:host])130end131return true132end133134# XXX: Document classes ought to define this135def determine_port_state(v)136return v137end138139# Circumvent the unknown attribute logging by the various reporters. They140# seem to be there just for debugging anyway.141def db_report(table, data)142raise "Data should be a hash" unless data.kind_of? Hash143nonempty_data = data.compact144valid_attrs = db_valid_attributes(table)145raise "Unknown table `#{table}'" if valid_attrs.empty?146case table147when :note, :web_site, :web_page, :web_form, :web_vuln148just_the_facts = nonempty_data149else150just_the_facts = nonempty_data.select {|k,v| valid_attrs.include? k.to_s.to_sym}151end152return nil if just_the_facts.empty?153just_the_facts[:task] = @args[:task]154just_the_facts[:workspace] = @args[:workspace] # workspace context is a required `fact`155db.send("report_#{table}", just_the_facts)156end157158# XXX: It would be better to either have a single registry of acceptable159# keys if we're going to alert on bad ones, or to be more forgiving if160# the caller is this thing. There is basically no way to tell if161# report_host()'s tastes are going to change with this scheme.162def db_valid_attributes(table)163case table.to_s.to_sym164when :host165::Mdm::Host.new.attribute_names.map {|x| x.to_sym} |166[:host, :workspace]167when :service168::Mdm::Service.new.attribute_names.map {|x| x.to_sym} |169[:host, :host_name, :mac, :workspace]170when :vuln171::Mdm::Vuln.new.attribute_names.map {|x| x.to_sym} |172[:host, :refs, :workspace, :port, :proto, :details, :exploited_at]173when :vuln_details174::Mdm::VulnDetails.new.attribute_names.map {|x| x.to_sym} | [ :key ]175when :host_details176::Mdm::HostDetails.new.attribute_names.map {|x| x.to_sym} | [ :key ]177when :note, :web_site, :web_page, :web_form, :web_vuln178# These guys don't complain179[:anything]180else181[]182end183end184185# Nokogiri 1.4.4 (and presumably beyond) generates attrs as pairs,186# like [["value1","foo"],["value2","bar"]] (but not hashes for some187# reason). 1.4.3.1 (and presumably 1.4.3.x and prior) generates attrs188# as a flat array of strings. We want array_pairs.189def normalize_attrs(attrs)190attr_pairs = []191case attrs.first192when Array, NilClass193attr_pairs = attrs194when String195attrs.each_index {|i|196next if i % 2 == 0197attr_pairs << [attrs[i-1],attrs[i]]198}199else # Wow, yet another format! It's either from the distant past or distant future.200raise ::Msf::DBImportError.new("Unknown format for XML attributes. Please check your Nokogiri version.")201end202return attr_pairs203end204205# Removes HTML from a string206def strip_html_tags(text)207return text.gsub!(/(<[^>]*>)|\n|\t/s) {" "}208end209210# This breaks xml-encoded characters, so need to append.211# It's on the end_element tag name to turn the appending212# off and clear out the data.213def characters(text)214return unless @state[:has_text]215@text ||= ""216@text << text217end218219# Effectively the same as characters()220def cdata_block(text)221return unless @state[:has_text]222@text ||= ""223@text << text224end225226def end_document227block = @block228return unless @report_type_ok229unless @state[:current_tag].empty?230missing_ends = @state[:current_tag].keys.map {|x| "'#{x}'"}.join(", ")231msg = "Warning, the provided file is incomplete, and there may be missing\n"232msg << "data. The following tags were not closed: #{missing_ends}."233db.emit(:warning,msg,&block) if block234end235end236237end238239end240end241242243