Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix xpath and add stubbed mappings manager in specs #62

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v4.14.0 (Month 2024)
aapomm marked this conversation as resolved.
Show resolved Hide resolved
- Fix HTML importer associating issues in the wrong node

v4.13.0 (July 2024)
- No changes

Expand Down
2 changes: 1 addition & 1 deletion lib/dradis/plugins/burp/html/importer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def process_html_evidence(html_evidence, issue)
evidence_id = html_evidence.attr('id').value
logger.info { "Processing evidence #{evidence_id}" }

host_td = html_evidence.xpath("//td[starts-with(.,'Host:')]").first
host_td = html_evidence.xpath(".//td[starts-with(.,'Host:')]").first
aapomm marked this conversation as resolved.
Show resolved Hide resolved
host_label = host_td.next_element.text.split('//').last
host = content_service.create_node(label: host_label, type: :host)

Expand Down
69 changes: 69 additions & 0 deletions spec/html/importer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
require 'spec_helper'
require 'ostruct'

describe 'Burp upload plugin' do
describe Dradis::Plugins::Burp::Html::Importer do
before(:each) do
# Stub mappings service
allow(Dradis::Plugins::MappingService).to receive(:new).and_return(
StubbedMappingService.new
)

# Init services
plugin = Dradis::Plugins::Burp::Html

@content_service = Dradis::Plugins::ContentService::Base.new(
logger: Logger.new(STDOUT),
plugin: plugin
)

@importer = plugin::Importer.new(
content_service: @content_service,
)

# Stub dradis-plugins methods
#
# They return their argument hashes as objects mimicking
# Nodes, Issues, etc
allow(@content_service).to receive(:create_node) do |args|
obj = OpenStruct.new(args)
obj.define_singleton_method(:set_property) { |_, __| }
obj
end
allow(@content_service).to receive(:create_issue) do |args|
OpenStruct.new(args)
end
allow(@content_service).to receive(:create_evidence) do |args|
OpenStruct.new(args)
end
end

it 'creates nodes, issues, and evidence as needed' do
# Host node
#
# create_node should be called once for each issue in the xml,
# but ContentService knows it's already created and NOOPs
expect(@content_service).to receive(:create_node)
.with(hash_including label: 'github.com/dradis/dradis-burp')
.exactly(1).times

# # create_issue should be called once for each issue in the xml
expect(@content_service).to receive(:create_issue) do |args|
expect(args[:text]).to include("Strict transport security not enforced")
expect(args[:text]).to include('*application*', '@Wi-Fi@')
expect(args[:id]).to eq(16777984)
OpenStruct.new(args)
end.once
aapomm marked this conversation as resolved.
Show resolved Hide resolved
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
expect(args[:content]).to include("http://1.1.1.1/dradis/sessions")
expect(args[:issue].text).to include("Strict transport security not enforced")
expect(args[:issue].text).to include('*application*', '@Wi-Fi@')
expect(args[:node].label).to eq('github.com/dradis/dradis-burp')
end.once

# Run the import
@importer.import(file: 'spec/fixtures/files/burp.html')
end
end
end
9 changes: 9 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,12 @@

RSpec.configure do |config|
end

class StubbedMappingService
aapomm marked this conversation as resolved.
Show resolved Hide resolved
def apply_mapping(args)
processor = Dradis::Plugins::Burp::FieldProcessor.new(data: args[:data])
Dradis::Plugins::Burp::Mapping::SOURCE_FIELDS[args[:source].to_sym].map do |field|
processor.value(field: field)
end.join("\n")
end
end
118 changes: 24 additions & 94 deletions spec/burp_upload_spec.rb → spec/xml/importer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
require 'ostruct'

describe 'Burp upload plugin' do

describe Burp::Xml::Issue do
it 'handles invalid utf-8 bytes' do
doc = Nokogiri::XML(File.read('spec/fixtures/files/invalid-utf-issue.xml'))
Expand All @@ -15,10 +14,10 @@

describe Dradis::Plugins::Burp::Xml::Importer do
before(:each) do
# Stub template service
templates_dir = File.expand_path('../../templates', __FILE__)
expect_any_instance_of(Dradis::Plugins::TemplateService)
.to receive(:default_templates_dir).and_return(templates_dir)
# Stub mappings service
allow(Dradis::Plugins::MappingService).to receive(:new).and_return(
StubbedMappingService.new
)

# Init services
plugin = Dradis::Plugins::Burp::Xml
Expand Down Expand Up @@ -50,7 +49,6 @@
end

it 'creates nodes, issues, and evidence as needed' do

# Host node
#
# create_node should be called once for each issue in the xml,
Expand All @@ -61,49 +59,49 @@

# create_issue should be called once for each issue in the xml
expect(@content_service).to receive(:create_issue) do |args|
expect(args[:text]).to include("#[Title]#\nIssue 1")
expect(args[:text]).to include("Issue 1")
expect(args[:id]).to eq(8781630)
OpenStruct.new(args)
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include('Lorem ipsum dolor sit amet')
expect(args[:issue].text).to include("#[Title]#\nIssue 1")
expect(args[:issue].text).to include("Issue 1")
expect(args[:node].label).to eq('10.0.0.1')
end.once

expect(@content_service).to receive(:create_issue) do |args|
expect(args[:text]).to include("#[Title]#\nIssue 2")
expect(args[:text]).to include("Issue 2")
expect(args[:id]).to eq(8781631)
OpenStruct.new(args)
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include('Lorem ipsum dolor sit amet')
expect(args[:issue].text).to include("#[Title]#\nIssue 2")
expect(args[:issue].text).to include("Issue 2")
expect(args[:node].label).to eq('10.0.0.1')
end.once

# Issue 3 is an Extension finding so we need to confirm
# that it triggers process_extension_issues instead of process_burp_issues
# and the plugin_id is not set to the Type (134217728)
expect(@content_service).to receive(:create_issue) do |args|
expect(args[:text]).to include("#[Title]#\nIssue 3")
expect(args[:text]).to include("Issue 3")
expect(args[:id]).to eq('Issue3')
OpenStruct.new(args)
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include('Lorem ipsum dolor sit amet')
expect(args[:issue].text).to include("#[Title]#\nIssue 3")
expect(args[:issue].text).to include("Issue 3")
expect(args[:node].label).to eq('10.0.0.1')
end.once

expect(@content_service).to receive(:create_issue) do |args|
expect(args[:text]).to include("#[Title]#\nIssue 4")
expect(args[:text]).to include("Issue 4")
expect(args[:id]).to eq(8781633)
OpenStruct.new(args)
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include('Lorem ipsum dolor sit amet')
expect(args[:issue].text).to include("#[Title]#\nIssue 4")
expect(args[:issue].text).to include("Issue 4")
expect(args[:node].label).to eq('10.0.0.1')
end.once

Expand All @@ -112,110 +110,42 @@
end

it 'returns the highest <severity> at the Issue level' do

expect(@content_service).to receive(:create_issue) do |args|
expect(args[:id]).to eq(8781630)
expect(args[:text]).to include("#[Title]#\nIssue 1")
expect(args[:text]).to include("#[Severity]#\nInformation")
expect(args[:text]).to include("Issue 1")
expect(args[:text]).to include("Information")
OpenStruct.new(args)
end

expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include("#[Severity]#\nInformation")
expect(args[:issue].text).to include("#[Title]#\nIssue 1")
expect(args[:content]).to include("Information")
expect(args[:issue].text).to include("Issue 1")
expect(args[:node].label).to eq('10.0.0.1')
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include("#[Severity]#\nHigh")
expect(args[:issue].text).to include("#[Title]#\nIssue 2")
expect(args[:content]).to include("High")
expect(args[:issue].text).to include("Issue 2")
expect(args[:node].label).to eq('10.0.0.1')
OpenStruct.new(args)
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include("#[Severity]#\nMedium")
expect(args[:issue].text).to include("#[Title]#\nIssue 3")
expect(args[:content]).to include("Medium")
expect(args[:issue].text).to include("Issue 3")
expect(args[:node].label).to eq('10.0.0.1')
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include("#[Severity]#\nHigh")
expect(args[:issue].text).to include("#[Title]#\nIssue 4")
expect(args[:content]).to include("High")
expect(args[:issue].text).to include("Issue 4")
expect(args[:node].label).to eq('10.0.0.1')
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include("#[Severity]#\nLow")
expect(args[:issue].text).to include("#[Title]#\nIssue 5")
expect(args[:content]).to include("Low")
expect(args[:issue].text).to include("Issue 5")
expect(args[:node].label).to eq('10.0.0.1')
end.once

# Run the import
@importer.import(file: 'spec/fixtures/files/burp_issue_severity.xml')
end
end

describe Dradis::Plugins::Burp::Html::Importer do
before(:each) do
# Stub template service
templates_dir = File.expand_path('../../templates', __FILE__)
expect_any_instance_of(Dradis::Plugins::TemplateService)
.to receive(:default_templates_dir).and_return(templates_dir)

# Init services
plugin = Dradis::Plugins::Burp::Html

@content_service = Dradis::Plugins::ContentService::Base.new(
logger: Logger.new(STDOUT),
plugin: plugin
)

@importer = plugin::Importer.new(
content_service: @content_service,
)

# Stub dradis-plugins methods
#
# They return their argument hashes as objects mimicking
# Nodes, Issues, etc
allow(@content_service).to receive(:create_node) do |args|
obj = OpenStruct.new(args)
obj.define_singleton_method(:set_property) { |_, __| }
obj
end
allow(@content_service).to receive(:create_issue) do |args|
OpenStruct.new(args)
end
allow(@content_service).to receive(:create_evidence) do |args|
OpenStruct.new(args)
end
end

it 'creates nodes, issues, and evidence as needed' do

# Host node
#
# create_node should be called once for each issue in the xml,
# but ContentService knows it's already created and NOOPs
expect(@content_service).to receive(:create_node)
.with(hash_including label: 'github.com/dradis/dradis-burp')
.exactly(1).times

# # create_issue should be called once for each issue in the xml
expect(@content_service).to receive(:create_issue) do |args|
expect(args[:text]).to include("#[Title]#\nStrict transport security not enforced")
expect(args[:text]).to include('*application*', '@Wi-Fi@')
expect(args[:id]).to eq(16777984)
OpenStruct.new(args)
end.once
expect(@content_service).to receive(:create_evidence) do |args|
expect(args[:content]).to include('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
expect(args[:content]).to include("#[Location]#\nhttp://1.1.1.1/dradis/sessions")
expect(args[:issue].text).to include("#[Title]#\nStrict transport security not enforced")
expect(args[:issue].text).to include('*application*', '@Wi-Fi@')
expect(args[:node].label).to eq('github.com/dradis/dradis-burp')
end.once

# Run the import
@importer.import(file: 'spec/fixtures/files/burp.html')
end

end
end