odle-m 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/odle-m +38 -0
- data/lib/model/data.rb +18 -0
- data/lib/odle-m.rb +11 -0
- data/lib/parsers/burp.rb +57 -0
- data/lib/parsers/burp2.rb +55 -0
- data/lib/parsers/msfv5.rb +32 -0
- data/lib/parsers/nessus.rb +54 -0
- data/lib/parsers/nmap.rb +70 -0
- metadata +54 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 800485a35d15ab752e25eb7674789d55d5088b426b81d8ade19e9208d9ad5f96
|
|
4
|
+
data.tar.gz: 5a6c62f31f4b151915d0956664af7266d8f027ed52343b26109936f3f449013d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bdd83324fd4da125739552100bcb71711aec892ac7aef948d8a3817075090eaea9921adb7fccf3db38efd0761d7c6b4dc554dd294bc59e2c593555ca5339cd1d
|
|
7
|
+
data.tar.gz: 63fd19799c46cc92643b877454104cf2e1eb21b509bc7bc3a4820bf2db00165c6ca8bc337baf115b54a32dcf4e597a3ea666b57bce1299ff8f2cd47ab48d78e7
|
data/bin/odle-m
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'odle-m'
|
|
3
|
+
|
|
4
|
+
def list_types()
|
|
5
|
+
return ["","--burp","--burp2","--nessus","--msf","--nmap"].join("\n")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# data flags are required
|
|
9
|
+
flags = ARGV.shift
|
|
10
|
+
|
|
11
|
+
unless flags
|
|
12
|
+
puts "[!] A data type is required e.g.\n cat MYDATA_FILE | odle --burp \n\n Available types:"+list_types()
|
|
13
|
+
exit(0)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# flags come in the form --type or --type,arg1=val1,arg2=val2
|
|
17
|
+
if flags =~ /,/
|
|
18
|
+
# complicated flags, not implemented yet
|
|
19
|
+
all = flags.gsub("--","").split(",")
|
|
20
|
+
|
|
21
|
+
type = all[0]
|
|
22
|
+
else
|
|
23
|
+
type = flags.gsub("--","")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if type.downcase == "burp"
|
|
27
|
+
puts Burp.new().parse(ARGF.read,"0")
|
|
28
|
+
elsif type.downcase == "burp2"
|
|
29
|
+
puts Burp2.new().parse(ARGF.read,"0")
|
|
30
|
+
elsif type.downcase == "nessus"
|
|
31
|
+
puts Nessus.new().parse(ARGF.read,"0")
|
|
32
|
+
elsif type.downcase == "msf"
|
|
33
|
+
puts Metasploit.new().parse(ARGF.read,"0")
|
|
34
|
+
elsif type.downcase == "nmap"
|
|
35
|
+
puts Nmap.new().parse(ARGF.read,"0")
|
|
36
|
+
else
|
|
37
|
+
puts "[!] Unknown data type \n\n Available types:"+list_types()
|
|
38
|
+
end
|
data/lib/model/data.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
class Host
|
|
4
|
+
attr_accessor :ip, :port
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class Finding
|
|
8
|
+
attr_accessor :title,:id,:description,:effort,:type,:dread_total,:overview,:poc,:remediation,:notes,:assessment_type,:references,:risk,:damage,:reproducability,:exploitability,:affected_users,:discoverability,:av,:ac,:au,:c,:i,:a,:e,:rl,:rc,:cdp,:td,:cr,:ir,:ar,:cvss_base,:cvss_impact,:cvss_exploitability,:cvss_temporal,:cvss_environmental,:cvss_modified_impact,:cvss_total,:ease,:c2_vs,:attack_vector,:attack_complexity,:privileges_required,:user_interaction,:scope_cvss,:confidentiality,:integrity,:availability,:exploit_maturity,:remeditation_level,:report_confidence,:confidentiality_requirement,:integrity_requirement,:availability_requirement,:mod_attack_vector,:mod_attack_complexity,:mod_privileges_required,:mod_user_interaction,:mod_scope,:mod_confidentiality,:mod_integrity,:mod_availability,:cvss_base_score,:cvss_impact_score,:cvss_mod_impact_score,:c3_vs,:severity,:likelihood,:severity_rationale,:likelihood_rationale,:affected_hosts
|
|
9
|
+
|
|
10
|
+
def to_hash
|
|
11
|
+
hash = {}
|
|
12
|
+
self.instance_variables.each do |var|
|
|
13
|
+
#p var.to_s.gsub("@","")
|
|
14
|
+
hash[var.to_s.gsub("@","").gsub("\"","")] = self.instance_variable_get var
|
|
15
|
+
end
|
|
16
|
+
return hash
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/odle-m.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Odle
|
|
5
|
+
# load the parsers
|
|
6
|
+
Dir[File.join(File.dirname(__FILE__), "parsers", "*.rb")].each { |lib| require lib }
|
|
7
|
+
|
|
8
|
+
# load the data model
|
|
9
|
+
Dir[File.join(File.dirname(__FILE__), "model", "*.rb")].each { |lib| require lib }
|
|
10
|
+
|
|
11
|
+
end
|
data/lib/parsers/burp.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
class Burp
|
|
4
|
+
|
|
5
|
+
def parse(xml,threshold)
|
|
6
|
+
vulns = Hash.new
|
|
7
|
+
findings = Array.new
|
|
8
|
+
vulns["findings"] = []
|
|
9
|
+
|
|
10
|
+
doc = Nokogiri::XML(xml)
|
|
11
|
+
doc.css('//issues/issue').each do |issue|
|
|
12
|
+
if issue.css('severity').text
|
|
13
|
+
# create a temporary finding object
|
|
14
|
+
finding = Finding.new()
|
|
15
|
+
finding.title = issue.css('name').text.to_s()
|
|
16
|
+
puts "#{finding.title}"
|
|
17
|
+
finding.overview = issue.css('issueBackground').text.to_s()+issue.css('issueDetail').text.to_s()
|
|
18
|
+
finding.remediation = issue.css('remediationBackground').text.to_s() + issue.css('remediationDetail').text.to_s()
|
|
19
|
+
finding.references=issue.css('references').text.to_s() + issue.css('vulnerabilityClassifications').text.to_s()
|
|
20
|
+
|
|
21
|
+
if issue.css('severity').text == 'Low'
|
|
22
|
+
finding.risk = 1
|
|
23
|
+
elsif issue.css('severity').text == 'Medium'
|
|
24
|
+
finding.risk = 2
|
|
25
|
+
elsif issue.css('severity').text =='High'
|
|
26
|
+
finding.risk = 3
|
|
27
|
+
else
|
|
28
|
+
finding.risk = 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
finding.type = "Web Application"
|
|
33
|
+
|
|
34
|
+
findings << finding
|
|
35
|
+
|
|
36
|
+
host = issue.css('host').text
|
|
37
|
+
ip = issue.css('host').attr('ip')
|
|
38
|
+
id = issue.css('type').text
|
|
39
|
+
hostname = "#{host}"
|
|
40
|
+
|
|
41
|
+
finding.affected_hosts = "#{host}" + issue.css('location').text.to_s()
|
|
42
|
+
|
|
43
|
+
finding.id = id
|
|
44
|
+
if vulns[hostname]
|
|
45
|
+
vulns[hostname] << finding.to_hash
|
|
46
|
+
else
|
|
47
|
+
vulns[hostname] = []
|
|
48
|
+
vulns[hostname] << finding.to_hash
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
#vulns["findings"] = uniq_findings(findings)
|
|
54
|
+
return vulns.to_json
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
class Burp2
|
|
4
|
+
|
|
5
|
+
def parse(xml,threshold)
|
|
6
|
+
vulns = Hash.new
|
|
7
|
+
findings = Array.new
|
|
8
|
+
vulns["findings"] = []
|
|
9
|
+
|
|
10
|
+
doc = Nokogiri::XML(xml)
|
|
11
|
+
doc.css('//issues/issue').each do |issue|
|
|
12
|
+
if issue.css('severity').text
|
|
13
|
+
# create a temporary finding object
|
|
14
|
+
finding = Finding.new()
|
|
15
|
+
finding.title = issue.css('name').text.to_s()
|
|
16
|
+
finding.overview = issue.css('issueBackground').text.to_s()+issue.css('issueDetail').text.to_s()
|
|
17
|
+
finding.remediation = issue.css('remediationBackground').text.to_s() + issue.css('remediationDetail').text.to_s()
|
|
18
|
+
finding.references=issue.css('references').text.to_s()
|
|
19
|
+
if issue.css('severity').text == 'Low'
|
|
20
|
+
finding.risk = 1
|
|
21
|
+
elsif issue.css('severity').text == 'Medium'
|
|
22
|
+
finding.risk = 2
|
|
23
|
+
elsif issue.css('severity').text =='High'
|
|
24
|
+
finding.risk = 3
|
|
25
|
+
else
|
|
26
|
+
finding.risk = 1
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
finding.type = "Web Application"
|
|
31
|
+
|
|
32
|
+
findings << finding
|
|
33
|
+
|
|
34
|
+
host = issue.css('host').text
|
|
35
|
+
ip = issue.css('host').attr('ip')
|
|
36
|
+
id = issue.css('type').text
|
|
37
|
+
hostname = "#{host}"
|
|
38
|
+
|
|
39
|
+
finding.affected_hosts = "#{host}" + issue.css('location').text.to_s()
|
|
40
|
+
|
|
41
|
+
finding.id = id
|
|
42
|
+
if vulns[hostname]
|
|
43
|
+
vulns[hostname] << finding.to_hash
|
|
44
|
+
else
|
|
45
|
+
vulns[hostname] = []
|
|
46
|
+
vulns[hostname] << finding.to_hash
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#vulns["findings"] = uniq_findings(findings)
|
|
52
|
+
return vulns.to_json
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
class Metasploit
|
|
4
|
+
|
|
5
|
+
def parse(xml,threshold)
|
|
6
|
+
vulns = Hash.new
|
|
7
|
+
vulns["findings"] = []
|
|
8
|
+
|
|
9
|
+
doc = Nokogiri::XML(xml)
|
|
10
|
+
doc.css('//hosts/host').each do |hostnode|
|
|
11
|
+
findings = Array.new
|
|
12
|
+
|
|
13
|
+
host = hostnode.css('/name').text.to_s
|
|
14
|
+
|
|
15
|
+
hostnode.css('/vulns/vuln').each do |issue|
|
|
16
|
+
# create a temporary finding object
|
|
17
|
+
finding = Finding.new()
|
|
18
|
+
finding.title = issue.css('name').text.to_s()
|
|
19
|
+
finding.overview = issue.css('info').text.to_s()
|
|
20
|
+
finding.risk = 0 # this needs to be fixed
|
|
21
|
+
finding.remediation = ""
|
|
22
|
+
finding.id = issue.css('id').text.to_s()
|
|
23
|
+
findings << finding.to_hash
|
|
24
|
+
end
|
|
25
|
+
vulns[host] = findings
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
#vulns["findings"] = uniq_findings(findings)
|
|
29
|
+
return vulns.to_json
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
class Nessus
|
|
4
|
+
|
|
5
|
+
def parse(xml,threshold)
|
|
6
|
+
vulns = Hash.new
|
|
7
|
+
findings = Array.new
|
|
8
|
+
items = Array.new
|
|
9
|
+
|
|
10
|
+
doc = Nokogiri::XML(xml)
|
|
11
|
+
|
|
12
|
+
doc.css("//ReportHost").each do |hostnode|
|
|
13
|
+
host = hostnode['name'] unless hostnode['name'].nil?
|
|
14
|
+
host = " " unless host
|
|
15
|
+
vulns[host] = []
|
|
16
|
+
|
|
17
|
+
hostnode.css("ReportItem").each do |itemnode|
|
|
18
|
+
|
|
19
|
+
if (itemnode["port"].to_s != "0" && itemnode["severity"] >= threshold)
|
|
20
|
+
|
|
21
|
+
# create a temporary finding object
|
|
22
|
+
finding = Finding.new()
|
|
23
|
+
finding.title = itemnode['pluginName'].to_s()
|
|
24
|
+
finding.poc = itemnode.css("description").to_s()
|
|
25
|
+
finding.remediation = itemnode.css("solution").to_s()
|
|
26
|
+
|
|
27
|
+
finding.cvss_total = itemnode.css("cvss3_base_score").to_s()
|
|
28
|
+
finding.c3_vs=itemnode.css("cvss3_vector").to_s()
|
|
29
|
+
finding.description = itemnode.css("synopsis").to_s()
|
|
30
|
+
|
|
31
|
+
# can this be inherited from an import properly?
|
|
32
|
+
finding.type = "Imported"
|
|
33
|
+
finding.risk = itemnode["severity"]
|
|
34
|
+
if itemnode.css("plugin_output")
|
|
35
|
+
finding.notes = hostnode["name"]+" ("+itemnode["protocol"]+ " port " + itemnode["port"]+"):"+itemnode.css("plugin_output").to_s()
|
|
36
|
+
finding.affected_hosts = hostnode["name"] + " [" + itemnode["port"] + "/" +itemnode["protocol"] + "]"
|
|
37
|
+
finding.references = itemnode.css("cvss3_vector").to_s() + " " + itemnode.css("see_also").to_s
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
finding.id = itemnode['pluginID'].to_s()
|
|
41
|
+
|
|
42
|
+
vulns[host] << finding.to_hash
|
|
43
|
+
items << itemnode['pluginID'].to_s()
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# vulns[host] = findings
|
|
48
|
+
items = []
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
return vulns.to_json
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
data/lib/parsers/nmap.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
class Nmap
|
|
4
|
+
|
|
5
|
+
def parse(xml,threshold)
|
|
6
|
+
vulns = Hash.new
|
|
7
|
+
findings = Array.new
|
|
8
|
+
items = Array.new
|
|
9
|
+
|
|
10
|
+
doc = Nokogiri::XML(xml)
|
|
11
|
+
|
|
12
|
+
#p doc
|
|
13
|
+
doc.css("//host").each do |hostnode|
|
|
14
|
+
address = hostnode.css("address")
|
|
15
|
+
host = address.attr("addr")
|
|
16
|
+
host = " " unless host
|
|
17
|
+
vulns[host] = []
|
|
18
|
+
affected_hosts = ""
|
|
19
|
+
|
|
20
|
+
hostnode.css("/hostnames").each do |hname|
|
|
21
|
+
hostname = hname.attr("hostname")
|
|
22
|
+
|
|
23
|
+
hname.traverse do |x|
|
|
24
|
+
if x.values[0]
|
|
25
|
+
if affected_hosts == ""
|
|
26
|
+
affected_hosts = x.values[0]
|
|
27
|
+
else
|
|
28
|
+
affected_hosts = affected_hosts + " " + x.values[0]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# finding is one per host
|
|
34
|
+
finding = Finding.new()
|
|
35
|
+
finding.affected_hosts = affected_hosts
|
|
36
|
+
vulns[host] << finding.to_hash
|
|
37
|
+
|
|
38
|
+
# finding is one per open port
|
|
39
|
+
hostnode.css("/ports/port").each do |port|
|
|
40
|
+
proto = port.attr("protocol")
|
|
41
|
+
portid = port.attr("portid")
|
|
42
|
+
state = port.css("/state").attr("state").value
|
|
43
|
+
service = port.css("/service").attr("name").value
|
|
44
|
+
|
|
45
|
+
# iterate the state
|
|
46
|
+
finding = Finding.new()
|
|
47
|
+
finding.affected_hosts = affected_hosts
|
|
48
|
+
|
|
49
|
+
# if a script was run, grab the results
|
|
50
|
+
if port.css("/script").size > 0
|
|
51
|
+
finding.title = "Script Scan:"+port.css("/script").attr("id").value+" [#{state} #{portid} (#{service})]"
|
|
52
|
+
finding.overview = port.css("/script").attr("output").value
|
|
53
|
+
vulns[host] << finding.to_hash
|
|
54
|
+
else
|
|
55
|
+
if state == "open"
|
|
56
|
+
finding.title = "Open port [#{state} #{portid} (#{service})]"
|
|
57
|
+
vulns[host] << finding.to_hash
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
items = []
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
return vulns.to_json
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: odle-m
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Shyam Ganesh
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2022-11-05 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: An easy to use security data parsing tool. Takes in data from different
|
|
14
|
+
tools and outputs standardized JSON with extra parsing
|
|
15
|
+
email: ''
|
|
16
|
+
executables:
|
|
17
|
+
- odle-m
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- bin/odle-m
|
|
22
|
+
- lib/model/data.rb
|
|
23
|
+
- lib/odle-m.rb
|
|
24
|
+
- lib/parsers/burp.rb
|
|
25
|
+
- lib/parsers/burp2.rb
|
|
26
|
+
- lib/parsers/msfv5.rb
|
|
27
|
+
- lib/parsers/nessus.rb
|
|
28
|
+
- lib/parsers/nmap.rb
|
|
29
|
+
homepage: http://rubygems.org/gems/odle
|
|
30
|
+
licenses:
|
|
31
|
+
- BSD-3-Clause-Attribution
|
|
32
|
+
metadata: {}
|
|
33
|
+
post_install_message:
|
|
34
|
+
rdoc_options: []
|
|
35
|
+
require_paths:
|
|
36
|
+
- lib
|
|
37
|
+
- lib/parsers
|
|
38
|
+
- lib/model
|
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
requirements: []
|
|
50
|
+
rubygems_version: 3.1.6
|
|
51
|
+
signing_key:
|
|
52
|
+
specification_version: 4
|
|
53
|
+
summary: odle-m
|
|
54
|
+
test_files: []
|