module Burp
module Html
# This class represents each of the issue elements in the Burp
# Scanner HTML document: all elemennts from a span.BODH0 until the next
# span.BODH0 (the next one excluded).
#
# It provides a convenient way to access the information scattered all over
# the HTML.
class Issue < ::Burp::Issue
# Accepts a Nokogiri::XML::NodeSet
def initialize(html)
@html = Nokogiri::HTML(html.to_s)
end
# List of supported tags
def supported_tags
[
# tags with contents retrieved from inside the span header
:name, :type,
# tags with contents retrieved following the span header
:background, :detail, :location,
:references, :remediation_background, :remediation_detail,
:request, :request_1, :request_2, :request_3,
:response, :response_1, :response_2, :response_3,
:vulnerability_classifications
] + summary_table_tags
end
def header
@header ||= @html.at_css('span')
end
def name
@name ||= header.text.gsub(/^\d+\.\S/, '')
end
# Link looks like: https://portswigger.net/kb/issues/00200400_flash-cross-domain-policy
# We use that 00200400 as type since in that page it calls it 'Type index'
def type
@type ||=
if header_link = header.at_css('a')
header_link.attr('href').to_s[/\/([0-9a-f]+)_.*/, 1].to_i(16)
else
nil
end
end
# This method is invoked by Ruby when a method that is not defined in this
# instance is called.
#
# In our case we inspect the @method@ parameter and try to find the
# corresponding header in our HTML, then return the following text.
def method_missing(method, *args)
# We could remove this check and return nil for any non-recognized tag.
# The problem would be that it would make tricky to debug problems with
# typos. For instance: <>.potr would return nil instead of raising an
# exception
unless supported_tags.include?(method)
super
return
end
# First we try the h2 headers.
translations_table = {
background: ['Issue background', 'Issue description'],
detail: 'Issue detail',
references: 'References',
remediation_background: ['Remediation background', 'Issue remediation'],
remediation_detail: 'Remediation detail',
request: 'Request',
request_1: 'Request 1',
request_2: 'Request 2',
request_3: 'Request 3',
response: 'Response',
response_1: 'Response 1',
response_2: 'Response 2',
response_3: 'Response 3',
serial_number: 'Serial number',
vulnerability_classifications: 'Vulnerability classifications'
}
# look for the h2 headers in the html fragment
method_names = translations_table.fetch(method, method.to_s)
method_names = [method_names].flatten
# Process the Location field
if method.to_s == 'location'
location = @html.at_xpath('/html/body/span[contains(@class, "BODH1")]')&.text
if location
# Remove the header number from the text.
# E.g. 1.1. /sample/text/
return location.split(/[[:space:]]/).drop(1).join(' ')
else
return 'n/a'
end
end
h2 = nil
method_names.each do |method_name|
h2 = @html.xpath("//h2[text()='#{method_name}']").first
break if h2
end
if h2
content =
if h2.text =~ /^(Request|Response)/
cleanup_request_response_html(h2.next_element.inner_html)
else
cleanup_html(h2.next_element.inner_html)
end
return content
end
# look inside the summary table in the html fragment
summary[method]
end
private
# In Request/Response html snippets we don't want to cleanup the whole
# html as we ususally do. The snippets may contain html code to be displayed,
# and we don't want to convert that to textile.
def cleanup_request_response_html(source)
result = source.dup
# Highlight code
result.gsub!(/(.+?)<\/span>/, '$${{\1}}$$')
result.gsub!(/(.*?)<\/b>/, '\1')
result.gsub!(/
|<\/br>/){"\n"}
result.gsub!(//, '')
result.gsub!(/<\/span>/, '')
result.gsub!(/"/, '"')
result.gsub!(/&/, '&')
result.gsub!(/</, '<')
result.gsub!(/>/, '>')
result.gsub!(/ /, ' ')
result
end
# Returns the summary table in the HTML fragment as a Hash
def summary
@summary ||= begin
@summary = {}
h2 = @html.search("h2[text()='Summary']").first
return @summary if h2.nil?
table = h2.next_element
summary_table_tags.each do |tag|
td = table.xpath("//td[starts-with(.,'#{tag.to_s.capitalize}:')]").first
@summary[tag] = td.next_element.text
end
@summary
end
end
# List of supported tags to obtain from the summary html table
def summary_table_tags
[
:confidence, :host, :path, :severity
]
end
end
end
end