diff --git a/lib/msf/core/db.rb b/lib/msf/core/db.rb index 17812d6d6d..0ec45e809f 100644 --- a/lib/msf/core/db.rb +++ b/lib/msf/core/db.rb @@ -8,6 +8,7 @@ require 'rex/parser/acunetix_nokogiri' require 'rex/parser/appscan_nokogiri' require 'rex/parser/burp_session_nokogiri' require 'rex/parser/ci_nokogiri' +require 'rex/parser/wapiti_nokogiri' # Legacy XML parsers -- these will be converted some day @@ -2443,6 +2444,7 @@ class DBManager line_count = 0 data.each_line { |line| line =~ /<([a-zA-Z0-9\-\_]+)[ >]/ + case $1 when "niktoscan" @import_filedata[:type] = "Nikto XML" @@ -2462,6 +2464,9 @@ class DBManager when "SCAN" @import_filedata[:type] = "Qualys Scan XML" return :qualys_scan_xml + when "report" + @import_filedata[:type] = "Wapiti XML" + return :wapiti_xml when "ASSET_DATA_REPORT" @import_filedata[:type] = "Qualys Asset XML" return :qualys_asset_xml @@ -2594,6 +2599,27 @@ class DBManager end end + def import_wapiti_xml_file(args={}) + filename = args[:filename] + wspace = args[:wspace] || workspace + + data = "" + ::File.open(filename, 'rb') do |f| + data = f.read(f.stat.size) + end + import_wapiti_xml(args.merge(:data => data)) + end + + def import_wapiti_xml(args={}, &block) + if block + doc = Rex::Parser::WapitiDocument.new(args,framework.db) {|type, data| yield type,data } + else + doc = Rex::Parser::WapitiDocument.new(args,self) + end + parser = ::Nokogiri::XML::SAX::Parser.new(doc) + parser.parse(args[:data]) + end + def import_libpcap_file(args={}) filename = args[:filename] wspace = args[:wspace] || workspace diff --git a/lib/rex/parser/wapiti_nokogiri.rb b/lib/rex/parser/wapiti_nokogiri.rb new file mode 100644 index 0000000000..4acb93a0cc --- /dev/null +++ b/lib/rex/parser/wapiti_nokogiri.rb @@ -0,0 +1,104 @@ +require "rex/parser/nokogiri_doc_mixin" + +module Rex + module Parser + + load_nokogiri && class WapitiDocument < Nokogiri::XML::SAX::Document + + include NokogiriDocMixin + + def start_element(name=nil,attrs=[]) + attrs = normalize_attrs(attrs) + block = @block + @state[:current_tag][name] = true + + case name + when "timestamp" + @state[:has_text] = true + when "url" + @state[:has_text] = true + when "addr" + @state[:has_text] = true + when "port" + @state[:has_text] = true + when "parameter" + @state[:has_text] = true + when "info" + @state[:has_text] = true + when "description" + @state[:has_text] = true + when "solution" + @state[:has_text] = true + when "title" + @state[:has_text] = true + end + end + + def end_element(name=nil) + block = @block + case name + when "timestamp" + @state[:timestamp] = @text.strip + @text = nil + when "url" + @state[:url] = @text.strip + @text = nil + when "addr" + @state[:host] = @text.strip + @text = nil + when "port" + @state[:port] = @text.strip + @text = nil + when "parameter" + @state[:parameter] = @text.strip + @text = nil + when "info" + @state[:info] = @text.strip + @text = nil + when "bug" + report_vuln + end + end + + def report_vuln(&block) + proto = @state[:url].split(":")[0] + path = '/' + (@state[:url].split("/")[3..(@state[:url].split("/").length - 1)].join('/')) + + web_vuln_info = {} + web_vuln_info[:web_site] = proto + "://" + @state[:host] + ":" + @state[:port] + web_vuln_info[:path] = path + web_vuln_info[:query] = @state[:url].split("?")[1] + + #if the URL contains the parameter found to be vulnerable, it is probably a GET + #if it does not contains the parameter, it is probably a POST + if @state[:url].index(@state[:parameter]) + web_vuln_info[:method] = "GET" + else + web_vuln_info[:method] = "POST" + end + + @state[:parameter].split("&").each do |param| + if param.index("%27") #apostrophe + web_vuln_info[:pname] = param.split('=')[0] #sql injection + break + elsif param.index("alert") + web_vuln_info[:pname] = param.split('=')[0] #xss + end + end + + web_vuln_info[:host] = @state[:host] + web_vuln_info[:port] = @state[:port] + web_vuln_info[:ssl] = (proto =~ /https/) + web_vuln_info[:proof] = "" + web_vuln_info[:risk] = "" + web_vuln_info[:params] = @state[:parameter] + web_vuln_info[:category] = "imported" + web_vuln_info[:confidence] = 90 + web_vuln_info[:name] = @state[:info] + + db.emit(:web_vuln, web_vuln_info[:name], &block) if block + vuln = db_report(:web_vuln, web_vuln_info) + end + end +end +end