First pass at an import, still missing a few items to call this done

git-svn-id: file:///home/svn/framework3/trunk@13390 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2011-07-28 21:17:30 +00:00
parent d58d061735
commit 9f8cbc4145
2 changed files with 229 additions and 0 deletions

View File

@ -7,6 +7,7 @@ require 'rex/parser/mbsa_nokogiri'
require 'rex/parser/acunetix_nokogiri'
require 'rex/parser/appscan_nokogiri'
require 'rex/parser/burp_session_nokogiri'
require 'rex/parser/ci_nokogiri'
# Legacy XML parsers -- these will be converted some day
@ -2135,6 +2136,11 @@ class DBManager
when /AppScanInfo/ # Actually the second line
@import_filedata[:type] = "Appscan"
return :appscan_xml
when "entities"
if line =~ /creator.*\x43\x4f\x52\x45\x20\x49\x4d\x50\x41\x43\x54/i
@import_filedata[:type] = "CI"
return :ci_xml
end
else
# Give up if we haven't hit the root tag in the first few lines
break if line_count > 10
@ -4493,6 +4499,26 @@ class DBManager
end
end
def import_ci_xml(args={}, &block)
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
wspace = args[:wspace] || workspace
if Rex::Parser.nokogiri_loaded
parser = "Nokogiri v#{::Nokogiri::VERSION}"
noko_args = args.dup
noko_args[:blacklist] = bl
noko_args[:wspace] = wspace
if block
yield(:parser, parser)
import_ci_noko_stream(noko_args) {|type, data| yield type,data}
else
import_ci_noko_stream(noko_args)
end
return true
else # Sorry
raise DBImportError.new("Could not import due to missing Nokogiri parser. Try 'gem install nokogiri'.")
end
end
def import_acunetix_noko_stream(args={},&block)
if block
doc = Rex::Parser::AcunetixDocument.new(args,framework.db) {|type, data| yield type,data }
@ -5011,6 +5037,17 @@ class DBManager
end
end
def import_ci_noko_stream(args, &block)
if block
doc = Rex::Parser::CIDocument.new(args,framework.db) {|type, data| yield type,data }
else
doc = Rex::Parser::CI.new(args,self)
end
parser = ::Nokogiri::XML::SAX::Parser.new(doc)
parser.parse(args[:data])
end
def unserialize_object(xml_elem, allow_yaml = false)
return nil unless xml_elem
string = xml_elem.text.to_s.strip

View File

@ -0,0 +1,192 @@
require File.join(File.expand_path(File.dirname(__FILE__)),"nokogiri_doc_mixin")
require 'msf/core'
module Rex
module Parser
# If Nokogiri is available, define the document class.
load_nokogiri && class CIDocument < Nokogiri::XML::SAX::Document
include NokogiriDocMixin
attr_reader :text
def initialize(*args)
super(*args)
@state[:has_text] = true
end
# Triggered every time a new element is encountered. We keep state
# ourselves with the @state variable, turning things on when we
# get here (and turning things off when we exit in end_element()).
def start_element(name=nil,attrs=[])
attrs = normalize_attrs(attrs)
block = @block
r = { :e => name }
attrs.each { |pair| r[pair[0]] = pair[1] }
if @state[:path]
@state[:path].push r
end
case name
when "entity"
@state[:path] = [ r ]
record_device(r)
when "property"
return if not @state[:address]
return if not @state[:props]
@state[:props] << [ r["type"], r["key"]]
end
end
# When we exit a tag, this is triggered.
def end_element(name=nil)
block = @block
case name
when "entity" # Wrap it up
if @state[:address]
host_object = report_host &block
report_services(host_object)
report_vulns(host_object)
end
# Reset the state once we close a host
@report_data = {:wspace => @args[:wspace]}
@state[:root] = {}
when "property"
if @state[:props]
@text.strip! if @text
process_property
@state[:props].pop
end
end
@state[:path].pop
@text = nil
end
def record_device(info)
if info["class"] and info["class"] == "host" and info["name"]
address = info["name"].to_s.gsub(/^.*\//, '')
return if address !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/
@state[:address] = address
@state[:props] = []
end
end
def process_property
return if not @state[:props]
return if not @state[:props].length > 0
@state[:root] ||= {}
@cobj = @state[:root]
property_parser(0)
end
def property_parser(idx)
return if not @state[:props][idx]
case @state[:props][idx][0]
when "container", "ports", "entity", "properties"
@cobj[ @state[:props][idx][1] ] ||= {}
@cobj = @cobj[ @state[:props][idx][1] ]
else
@cobj[ state[:props][idx][1] ] = @text
end
property_parser(idx + 1)
end
def report_host(&block)
@report_data = {
:ports => [:ignore],
:state => Msf::HostState::Alive,
:host => @state[:address]
}
if @state[:root]["dns names"] and @state[:root]["dns names"].keys.length > 0
@report_data[:name] = @state[:root]["dns names"].keys.first
end
if host_is_okay
@report_data.delete(:ports)
db.emit(:address, @report_data[:host],&block) if block
host_object = db_report(:host, @report_data.merge(
:workspace => @args[:wspace] ) )
if host_object
db.report_import_note(host_object.workspace, host_object)
end
host_object
end
end
def report_services(host_object)
return unless host_object.kind_of? ::Msf::DBManager::Host
snames = {}
( @state[:root]["services"] || {} ).each_pair do |sname, sinfo|
sinfo.each_pair do |pinfo,pdata|
snames[pinfo] = sname.dup
end
end
reported = []
if @state[:root]["tcp_ports"]
@state[:root]["tcp_ports"].each_pair do |pn, ps|
ps = "open" if ps == "listen"
svc = { :port => pn.to_i, :state => ps, :proto => 'tcp'}
if @state[:root]["Banners"] and @state[:root]["Banners"][pn.to_s]
svc[:info] = @state[:root]["Banners"][pn.to_s]
end
svc[:name] = snames["#{pn}-tcp"] if snames["#{pn}-tcp"]
reported << db_report(:service, svc.merge(:host => host_object))
end
end
if @state[:root]["udp_ports"]
@state[:root]["udp_ports"].each_pair do |pn, ps|
ps = "open" if ps == "listen"
svc = { :port => pn.to_i, :state => ps, :proto => 'udp'}
svc[:name] = snames["#{pn}-udp"] if snames["#{pn}-tcp"]
reported << db_report(:service, svc.merge(:host => host_object))
end
end
( @state[:root]["services"] || {} ).each_pair do |sname, sinfo|
sinfo.each_pair do |pinfo,pdata|
sport,sproto = pinfo.split("-")
db_report(:note, {
:host => host_object,
:port => sport.to_i,
:proto => sproto,
:ntype => "ci.#{sname}.fingerprint",
:data => pdata
})
end
end
reported
end
def report_vulns(host_object)
vuln_count = 0
block = @block
return unless host_object.kind_of? Msf::DBManager::Host
return unless @state[:root]["Vulnerabilities"]
@state[:root]["Vulnerabilities"].each_pair do |cve, vinfo|
vinfo.each_pair do |vname, vdesc|
data = {
:workspace => host_object.workspace,
:host => host_object,
:name => vname,
:info => vdesc,
:refs => [ cve ]
}
db_report(:vuln, data)
end
end
end
end
end
end