Parent

Class/Module Index [+]

Quicksearch

Rex::Parser::AppscanDocument

Attributes

parse_warning[R]

If name resolution of the host fails out completely, you will not be able to import that Scan task. Other scan tasks in the same report should be unaffected.

resolv_cache[R]

The resolver prefers your local /etc/hosts (or windows equiv), but will fall back to regular DNS. It retains a cache for the import to avoid spamming your network with DNS requests.

Public Instance Methods

check_for_existing_service(address,port) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 298
def check_for_existing_service(address,port)
        db.get_service(@args[:wspace],address,"tcp",port)
end
collect_entity(attrs) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 98
def collect_entity(attrs)
        return unless in_issue
        return unless @state[:issue].kind_of? Hash
        ent_hash = attr_hash(attrs)
        return unless ent_hash
        return unless ent_hash["Type"].to_s.downcase == "parameter"
        @state[:issue][:vuln_param] = ent_hash["Name"]
end
collect_issue(attrs) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 256
def collect_issue(attrs)
        return unless in_issue
        @state[:issue] = {}
        @state[:issue].merge! attr_hash(attrs)
end
end_element(name=nil) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 40
def end_element(name=nil)
        block = @block
        case name
        when "Issue" # Wrap it up
                record_issue
                # Reset the state once we close an issue
                @state = @state.select do
                        |k| [:current_tag, :web_sites].include? k
                end
        when "Url" # Populates @state[:web_site]
                @state[:has_text] = false
                record_url
                @text = nil
                report_web_site(&block)
                handle_parse_warnings(&block)
        when "Severity"
                @state[:has_text] = false
                record_risk
                @text = nil
        when "OriginalHttpTraffic" # Request and response
                @state[:has_text] = false
                record_request_and_response
                report_service_info
                page_info = report_web_page(&block)
                if page_info
                        form_info = report_web_form(page_info,&block)
                        if form_info
                                report_web_vuln(form_info,&block)
                        end
                end
                @text = nil
        end
        @state[:current_tag].delete name
end
handle_parse_warnings(&block) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 334
def handle_parse_warnings(&block)
        return if @parse_warnings.empty?
        @parse_warnings.each do |pwarn|
                db.emit(:warning, pwarn, &block) if block
        end
end
has_text() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 356
def has_text
        return false unless @text
        return false if @text.strip.empty?
        @text = @text.strip
end
in_issue() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 349
def in_issue
        return false unless in_tag("Issue")
        return false unless in_tag("Issues")
        return false unless in_tag("XmlReport")
        return true
end
map_severity_to_risk() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 239
def map_severity_to_risk
        case @text.to_s.downcase
        when "high"   ; 5
        when "medium" ; 3
        when "low"    ; 1
        else          ; 0
        end
end
parse_params(request_body) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 130
def parse_params(request_body)
        return unless request_body
        pairs = request_body.split(/&/)
        params = []
        pairs.each do |pair|
                param,value = pair.split("=",2)
                params << [param,""] # Can't tell what's default
        end
        params
end
record_issue() click to toggle source

TODO

# File lib/rex/parser/appscan_nokogiri.rb, line 249
def record_issue
        return unless in_issue
        return unless @report_data[:issue].kind_of? Hash
        return unless @state[:web_site]
        return if @state[:issue]["Noise"].to_s.downcase == "true"
end
record_request_and_response() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 187
def record_request_and_response
        return unless(in_issue && has_text)
        return unless @state[:web_site]
        really_original_traffic = unindent_and_crlf(@text)
        split_traffic = really_original_traffic.split(/\r\n\r\n/)
        request_headers_text = split_traffic.first
        content_length = 0
        if request_headers_text =~ /\ncontent-length:\s+([0-9]+)/ni
                content_length = $1.to_i
        end
        if(content_length > 0) and (split_traffic[1].to_s.size >= content_length)
                request_body_text = split_traffic[1].to_s[0,content_length]
        else
                request_body_text = nil
        end
        response_headers_text = split_traffic[1].to_s[content_length,split_traffic[1].to_s.size].lstrip
        request = request_headers_text
        return unless(request && response_headers_text)
        response_body_text = split_traffic[2]
        req_header = Rex::Proto::Http::Packet::Header.new
        res_header = Rex::Proto::Http::Packet::Header.new
        req_header.from_s request_headers_text.dup
        res_header.from_s response_headers_text.dup
        @state[:request_headers] = req_header
        @state[:request_body] = request_body_text
        @state[:response_headers] = res_header
        @state[:response_body] = response_body_text
end
record_risk() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 233
def record_risk
        return unless(in_issue && has_text)
        @state[:issue] ||= {}
        @state[:issue][:risk] = map_severity_to_risk
end
record_url() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 341
def record_url
        return unless in_issue
        return unless has_text
        uri = URI.parse(@text) rescue nil
        return unless uri
        @state[:uri] = uri
end
report_service_info() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 170
def report_service_info
        return unless(in_issue && has_text)
        return unless @state[:web_site]
        return unless @state[:response_headers]
        banner = @state[:response_headers]["server"]
        return unless banner
        service = @state[:web_site].service
        return unless service.info.to_s.empty?
        service_info = {
                :host => service.host,
                :port => service.port,
                :proto => service.proto,
                :info => banner
        }
        db_report(:service, service_info)
end
report_web_form(page_info,&block) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 107
def report_web_form(page_info,&block)
        return unless(in_issue && has_text)
        return unless page_info.kind_of? Hash
        return unless @state[:request_body]
        return if @state[:request_body].strip.empty?
        web_form_info = {}
        web_form_info[:web_site] = page_info[:web_site]
        web_form_info[:path] = page_info[:path]
        web_form_info[:query] = page_info[:query]
        web_form_info[:method] = @state[:request_headers].cmd_string.split(/\s+/)[0]
        parsed_params = parse_params(@state[:request_body])
        return unless parsed_params
        return if parsed_params.empty?
        web_form_info[:params] = parsed_params
        web_form = db_report(:web_form, web_form_info)
        @state[:web_forms] ||= []
        unless @state[:web_forms].include? web_form
                db.emit(:web_form, @state[:uri].to_s, &block) if block
                @state[:web_forms] << web_form
        end
        web_form_info
end
report_web_page(&block) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 141
def report_web_page(&block)
        return unless(in_issue && has_text)
        return unless @state[:web_site]
        return unless @state[:response_headers]
        return unless @state[:uri]
        web_page_info = {}
        web_page_info[:web_site] = @state[:web_site]
        web_page_info[:path] = @state[:uri].path
        web_page_info[:body] = @state[:response_body].to_s
        web_page_info[:query] = @state[:uri].query
        code = @state[:response_headers].cmd_string.split(/\s+/)[1]
        return unless code
        web_page_info[:code] = code
        parsed_headers = {}
        @state[:response_headers].each do |k,v|
                parsed_headers[k.to_s.downcase] ||= []
                parsed_headers[k.to_s.downcase] << v
        end
        return if parsed_headers.empty?
        web_page_info[:headers] = parsed_headers
        web_page = db_report(:web_page, web_page_info)
        @state[:web_pages] ||= []
        unless @state[:web_pages].include? web_page
                db.emit(:web_page, @state[:uri].to_s, &block) if block
                @state[:web_pages] << web_page
        end
        web_page_info
end
report_web_site(&block) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 262
def report_web_site(&block)
        return unless @state[:uri]
        uri = @state[:uri]
        hostname = uri.host # Assume the first one is the real hostname
        address = resolve_issue_url_address(uri)
        return unless address
        unless @resolv_cache.values.include? address
                db.emit(:address, address, &block) if block
        end
        port = resolve_port(uri)
        return unless port
        scheme = uri.scheme
        return unless scheme
        web_site_info = {:workspace => @args[:wspace]}
        web_site_info[:vhost] = hostname
        service_obj = check_for_existing_service(address,port)
        if service_obj
                web_site_info[:service] = service_obj
        else
                web_site_info[:host] = address
                web_site_info[:port] = port
                web_site_info[:ssl] = scheme == "https"
        end
        web_site_obj = db_report(:web_site, web_site_info)
        @state[:web_sites] ||= []
        unless @state[:web_sites].include? web_site_obj
                url = "#{uri.scheme}://#{uri.host}:#{uri.port}"
                db.emit(:web_site, url, &block) if block
                db.report_import_note(@args[:wspace], web_site_obj.service.host)
                @state[:web_sites] << web_site_obj
        end
        @state[:service] = service_obj || web_site_obj.service
        @state[:host] = (service_obj || web_site_obj.service).host
        @state[:web_site] = web_site_obj
end
report_web_vuln(form_info,&block) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 75
def report_web_vuln(form_info,&block)
        return unless(in_issue && has_text)
        return unless form_info.kind_of? Hash
        return unless @state[:issue]
        return unless @state[:issue]["Noise"]
        return unless @state[:issue]["Noise"].to_s.downcase == "false"
        return unless @state[:issue][:vuln_param]
        web_vuln_info = {}
        web_vuln_info[:web_site] = form_info[:web_site]
        web_vuln_info[:path] = form_info[:path]
        web_vuln_info[:query] = form_info[:query]
        web_vuln_info[:method] = form_info[:method]
        web_vuln_info[:params] = form_info[:params]
        web_vuln_info[:pname] = @state[:issue][:vuln_param]
        web_vuln_info[:proof] = "" # TODO: pick this up from <Difference> maybe?
        web_vuln_info[:risk] = @state[:issue][:risk]
        web_vuln_info[:name] = @state[:issue]["IssueTypeID"]
        web_vuln_info[:category] = "imported"
        web_vuln_info[:confidence] = 100 # Seems pretty binary, noise or not
        db.emit(:web_vuln, web_vuln_info[:name], &block) if block
        web_vuln = db_report(:web_vuln, web_vuln_info)
end
resolve_address(host) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 310
def resolve_address(host)
        return @resolv_cache[host] if @resolv_cache[host]
        address = Rex::Socket.resolv_to_dotted(host) rescue nil
        @resolv_cache[host] = address
        if address
                block = @block
                db.emit(:address, address, &block) if block
        end
        return address
end
resolve_issue_url_address(uri) click to toggle source

Alias this

# File lib/rex/parser/appscan_nokogiri.rb, line 322
def resolve_issue_url_address(uri)
        if uri.host
                address = resolve_address(uri.host)
                unless address
                        @parse_warnings << "Could not resolve address for '#{uri.host}', skipping."
                end
        else
                @parse_warnings << "Could not determine a host for this import."
        end
        address
end
resolve_port(uri) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 302
def resolve_port(uri)
        @state[:port] = uri.port
        unless @state[:port]
                @parse_warnings << "Could not determine a port for '#{@state[:scan_name]}'"
        end
        return @state[:port]
end
start_document() click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 21
def start_document
        @parse_warnings = []
        @resolv_cache = {}
end
start_element(name=nil,attrs=[]) click to toggle source
# File lib/rex/parser/appscan_nokogiri.rb, line 26
def start_element(name=nil,attrs=[])
        attrs = normalize_attrs(attrs)
        block = @block
        @state[:current_tag][name] = true
        case name
        when "Issue" # Start of the stuff we want
                collect_issue(attrs)
        when "Entity" # Start of the stuff we want
                collect_entity(attrs)
        when "Severity", "Url", "OriginalHttpTraffic"
                @state[:has_text] = true
        end
end
unindent_and_crlf(text) click to toggle source

Appscan tab-indents which makes parsing a little difficult. They also don't record CRLFs, just LFs.

# File lib/rex/parser/appscan_nokogiri.rb, line 218
def unindent_and_crlf(text)
        second_line = text.split(/\r*\n/)[1]
        indent_level = second_line.size - second_line.lstrip.size
        unindented_text_lines = []
        text.split(/\r*\n/).each do |line|
                if line =~ /^\t{#{indent_level}}/
                        unindented_line = line[indent_level,line.size]
                        unindented_text_lines << unindented_line
                else
                        unindented_text_lines << line
                end
        end
        unindented_text_lines.join("\r\n")
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.