dockscan 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE +340 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/dockscan.gemspec +27 -0
- data/docs/dockscan.png +0 -0
- data/exe/dockscan +107 -0
- data/lib/dockscan/modules/audit/container-filesystem-diff.rb +41 -0
- data/lib/dockscan/modules/audit/container-filesystem-shadow.rb +37 -0
- data/lib/dockscan/modules/audit/container-number-process.rb +36 -0
- data/lib/dockscan/modules/audit/container-sshd-process.rb +33 -0
- data/lib/dockscan/modules/audit/docker-experimental-build.rb +27 -0
- data/lib/dockscan/modules/audit/docker-insecure-registries.rb +53 -0
- data/lib/dockscan/modules/audit/docker-limits.rb +34 -0
- data/lib/dockscan/modules/audit/docker-networking-forwarding.rb +27 -0
- data/lib/dockscan/modules/audit/docker-registry-mirror.rb +41 -0
- data/lib/dockscan/modules/audit/docker-storage-driver-aufs.rb +28 -0
- data/lib/dockscan/modules/audit.rb +32 -0
- data/lib/dockscan/modules/discover/get-containers.rb +14 -0
- data/lib/dockscan/modules/discover/get-docker-info.rb +17 -0
- data/lib/dockscan/modules/discover/get-docker-version.rb +14 -0
- data/lib/dockscan/modules/discover/get-images.rb +16 -0
- data/lib/dockscan/modules/discover/get-run-containers.rb +14 -0
- data/lib/dockscan/modules/discover.rb +16 -0
- data/lib/dockscan/modules/genmodule.rb +17 -0
- data/lib/dockscan/modules/report/html.rb +182 -0
- data/lib/dockscan/modules/report/stdout.rb +36 -0
- data/lib/dockscan/modules/report/txt.rb +36 -0
- data/lib/dockscan/modules/report.rb +75 -0
- data/lib/dockscan/scan/issue.rb +18 -0
- data/lib/dockscan/scan/manage.rb +172 -0
- data/lib/dockscan/scan/plugin.rb +14 -0
- data/lib/dockscan/version.rb +3 -0
- data/lib/dockscan.rb +7 -0
- metadata +141 -0
@@ -0,0 +1,182 @@
|
|
1
|
+
class ReportHTML < Dockscan::Modules::ReportModule
|
2
|
+
|
3
|
+
def info
|
4
|
+
return 'This plugin produces HTML reports'
|
5
|
+
end
|
6
|
+
|
7
|
+
def file_extension
|
8
|
+
return ".html"
|
9
|
+
end
|
10
|
+
|
11
|
+
def format
|
12
|
+
return "html"
|
13
|
+
end
|
14
|
+
|
15
|
+
def htmlhead
|
16
|
+
htmlout = ""
|
17
|
+
htmlout << "<HTML><HEAD><TITLE>dockscan Report</TITLE>\n"
|
18
|
+
htmlout << '<style>'
|
19
|
+
htmlout << '.Vulnerability {
|
20
|
+
margin:0px;padding:0px;
|
21
|
+
width:100%;
|
22
|
+
border:0px solid #000000;
|
23
|
+
|
24
|
+
-moz-border-radius-bottomleft:0px;
|
25
|
+
-webkit-border-bottom-left-radius:0px;
|
26
|
+
border-bottom-left-radius:0px;
|
27
|
+
|
28
|
+
-moz-border-radius-bottomright:0px;
|
29
|
+
-webkit-border-bottom-right-radius:0px;
|
30
|
+
border-bottom-right-radius:0px;
|
31
|
+
|
32
|
+
-moz-border-radius-topright:0px;
|
33
|
+
-webkit-border-top-right-radius:0px;
|
34
|
+
border-top-right-radius:0px;
|
35
|
+
|
36
|
+
-moz-border-radius-topleft:0px;
|
37
|
+
-webkit-border-top-left-radius:0px;
|
38
|
+
border-top-left-radius:0px;
|
39
|
+
}.Vulnerability table{
|
40
|
+
border-collapse: collapse;
|
41
|
+
border-spacing: 0;
|
42
|
+
width:100%;
|
43
|
+
height:100%;
|
44
|
+
margin:0px;padding:0px;
|
45
|
+
}.Vulnerability tr:last-child td:last-child {
|
46
|
+
-moz-border-radius-bottomright:0px;
|
47
|
+
-webkit-border-bottom-right-radius:0px;
|
48
|
+
border-bottom-right-radius:0px;
|
49
|
+
}
|
50
|
+
.Vulnerability table tr:first-child td:first-child {
|
51
|
+
-moz-border-radius-topleft:0px;
|
52
|
+
-webkit-border-top-left-radius:0px;
|
53
|
+
border-top-left-radius:0px;
|
54
|
+
}
|
55
|
+
.Vulnerability table tr:first-child td:last-child {
|
56
|
+
-moz-border-radius-topright:0px;
|
57
|
+
-webkit-border-top-right-radius:0px;
|
58
|
+
border-top-right-radius:0px;
|
59
|
+
}.Vulnerability tr:last-child td:first-child{
|
60
|
+
-moz-border-radius-bottomleft:0px;
|
61
|
+
-webkit-border-bottom-left-radius:0px;
|
62
|
+
border-bottom-left-radius:0px;
|
63
|
+
}.Vulnerability tr:hover td{
|
64
|
+
background-color:#ffffff;
|
65
|
+
}
|
66
|
+
.Vulnerability td{
|
67
|
+
vertical-align:middle;
|
68
|
+
|
69
|
+
background-color:#ffffff;
|
70
|
+
|
71
|
+
border:0px solid #000000;
|
72
|
+
border-width:0px 1px 1px 0px;
|
73
|
+
text-align:left;
|
74
|
+
padding:7px;
|
75
|
+
font-size:10px;
|
76
|
+
font-family:Arial;
|
77
|
+
font-weight:normal;
|
78
|
+
color:#000000;
|
79
|
+
}.Vulnerability tr:last-child td{
|
80
|
+
border-width:0px 0px 0px 0px;
|
81
|
+
}.Vulnerability tr td:last-child{
|
82
|
+
border-width:0px 0px 0px 0px;
|
83
|
+
}.Vulnerability tr:last-child td:last-child{
|
84
|
+
border-width:0px 0px 0px 0px;
|
85
|
+
}
|
86
|
+
.Vulnerability tr:first-child td{
|
87
|
+
border:0px solid #000000;
|
88
|
+
text-align:left;
|
89
|
+
border-width:0px 0px 0px 0px;
|
90
|
+
font-size:14px;
|
91
|
+
font-family:Arial;
|
92
|
+
font-weight:bold;
|
93
|
+
color:#000000;
|
94
|
+
}
|
95
|
+
.Vulnerability tr:first-child:hover td{
|
96
|
+
}
|
97
|
+
.Vulnerability tr:first-child td:first-child{
|
98
|
+
border-width:0px 0px 0px 0px;
|
99
|
+
}
|
100
|
+
.Vulnerability tr:first-child td:last-child{
|
101
|
+
border-width:0px 0px 0px 0px;
|
102
|
+
}
|
103
|
+
|
104
|
+
.VulnerabilityBLACK tr:first-child td{
|
105
|
+
background-color:#000000;
|
106
|
+
color:#FFFFFF;
|
107
|
+
}
|
108
|
+
|
109
|
+
.VulnerabilityRED tr:first-child td{
|
110
|
+
background-color:#ff0000;
|
111
|
+
color:#ffffff;
|
112
|
+
}
|
113
|
+
|
114
|
+
.VulnerabilityORANGE tr:first-child td{
|
115
|
+
background-color:#ff9966;
|
116
|
+
color:#000000;
|
117
|
+
}
|
118
|
+
|
119
|
+
.VulnerabilityYELLOW tr:first-child td{
|
120
|
+
background-color:#ffff00;
|
121
|
+
color:#000000;
|
122
|
+
}
|
123
|
+
|
124
|
+
.VulnerabilityGRAY tr:first-child td{
|
125
|
+
background-color:#d0d0d0;
|
126
|
+
color:#000000;
|
127
|
+
}
|
128
|
+
'
|
129
|
+
htmlout << '</style>'
|
130
|
+
htmlout << "</HEAD>\n"
|
131
|
+
htmlout << "<BODY>\n"
|
132
|
+
htmlout << '<img width="220" height="169" title="" alt="" src="data:image/png;base64,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" />'
|
133
|
+
return htmlout
|
134
|
+
end
|
135
|
+
|
136
|
+
def htmlfoot
|
137
|
+
htmlout = ""
|
138
|
+
htmlout << "</BODY>\n"
|
139
|
+
htmlout << "</HTML>\n"
|
140
|
+
return htmlout
|
141
|
+
end
|
142
|
+
|
143
|
+
def report(opts)
|
144
|
+
output=""
|
145
|
+
output << htmlhead
|
146
|
+
output << "<h2>dockscan Report<h2>"
|
147
|
+
issues = sortvulns
|
148
|
+
7.downto(3) do |sev|
|
149
|
+
if issues.key?(sev)
|
150
|
+
output << "<h3>" << sev2word(sev) << " vulnerabilities</h3>\n"
|
151
|
+
issues[sev].each do |v|
|
152
|
+
if sev >= 7 then
|
153
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityBLACK">'
|
154
|
+
elsif sev == 6 then
|
155
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityRED">'
|
156
|
+
elsif sev == 5
|
157
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityORANGE">'
|
158
|
+
elsif sev == 4
|
159
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityYELLOW">'
|
160
|
+
elsif sev == 3
|
161
|
+
output << '<TABLE CLASS="Vulnerability VulnerabilityGRAY">'
|
162
|
+
else
|
163
|
+
output << '<TABLE CLASS="Vulnerability">'
|
164
|
+
end
|
165
|
+
output << "<TR>\n"
|
166
|
+
output << "<TD COLSPAN=2>" << v.vuln.title << "</TD>\n"
|
167
|
+
output << "<TD>" << sev2word(v.vuln.severity) << "</TD>\n"
|
168
|
+
output << "</TR>\n"
|
169
|
+
output << "<TR><TD COLSPAN=3>" << v.vuln.description << "</TD></TR>\n"
|
170
|
+
output << "<TR><TD COLSPAN=3><PRE>" << v.output << "</PRE></TD></TR>\n"
|
171
|
+
output << "<TR><TD COLSPAN=3>" << v.vuln.solution << "</TD></TR>\n"
|
172
|
+
output << "<TR><TD>CVSS: " << getkey(v.vuln.risk,"cvss").to_s << "</TD><TD>State: " << v.state << "</TD><TD></TD></TR>\n"
|
173
|
+
output << "</TABLE>\n\n"
|
174
|
+
end
|
175
|
+
output << "<P></P>\n"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
return output
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ReportStdout < Dockscan::Modules::ReportModule
|
2
|
+
|
3
|
+
def info
|
4
|
+
return 'This plugin produces brief stdout reports'
|
5
|
+
end
|
6
|
+
|
7
|
+
def format
|
8
|
+
return "stdout"
|
9
|
+
end
|
10
|
+
|
11
|
+
def file_extension
|
12
|
+
return "-stdout.txt"
|
13
|
+
end
|
14
|
+
|
15
|
+
def report(opts)
|
16
|
+
output=""
|
17
|
+
output << "Dockscan Report\n\n"
|
18
|
+
|
19
|
+
issues = sortvulns
|
20
|
+
7.downto(3) do |sev|
|
21
|
+
if issues.key?(sev)
|
22
|
+
output << sev2word(sev) << "\n"
|
23
|
+
issues[sev].each do |v|
|
24
|
+
# output << k << ": "
|
25
|
+
output << v.vuln.title << ": "
|
26
|
+
output << v.vuln.solution
|
27
|
+
# output << v.output
|
28
|
+
output << "\n"
|
29
|
+
end
|
30
|
+
output << "\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return output
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ReportText < Dockscan::Modules::ReportModule
|
2
|
+
|
3
|
+
def info
|
4
|
+
return 'This plugin produces text reports'
|
5
|
+
end
|
6
|
+
|
7
|
+
def format
|
8
|
+
return "txt"
|
9
|
+
end
|
10
|
+
|
11
|
+
def file_extension
|
12
|
+
return ".txt"
|
13
|
+
end
|
14
|
+
|
15
|
+
def report(opts)
|
16
|
+
output=""
|
17
|
+
output << "Dockscan Report\n\n"
|
18
|
+
|
19
|
+
issues = sortvulns
|
20
|
+
7.downto(3) do |sev|
|
21
|
+
if issues.key?(sev)
|
22
|
+
output << "-[ " << sev2word(sev) << " ]-\n"
|
23
|
+
issues[sev].each do |v|
|
24
|
+
output << "=" << v.vuln.title << "=\n"
|
25
|
+
output << "Description:\n" << v.vuln.description << "\n"
|
26
|
+
output << "Output:\n" << v.output << "\n"
|
27
|
+
output << "Solution:\n" << v.vuln.solution << "\n"
|
28
|
+
output << "\n"
|
29
|
+
end
|
30
|
+
output << "\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return output
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Dockscan
|
2
|
+
module Modules
|
3
|
+
|
4
|
+
class ReportModule < GenericModule
|
5
|
+
attr_accessor :scandata
|
6
|
+
|
7
|
+
def info
|
8
|
+
raise "#{self.class.name} doesn't implement `handle_command`!"
|
9
|
+
end
|
10
|
+
|
11
|
+
def desc(item)
|
12
|
+
if item.vuln.description
|
13
|
+
return item.vuln.description
|
14
|
+
else
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def sortvulns
|
20
|
+
severity_sorted=Hash.new
|
21
|
+
scandata.each do |classname,scanissue|
|
22
|
+
if scanissue.state == "vulnerable" or scanissue.state=="info" then
|
23
|
+
severity_sorted[scanissue.vuln.severity] ||= []
|
24
|
+
severity_sorted[scanissue.vuln.severity] << scanissue
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return severity_sorted
|
28
|
+
end
|
29
|
+
|
30
|
+
def format
|
31
|
+
return "unknown"
|
32
|
+
end
|
33
|
+
|
34
|
+
def file_extension
|
35
|
+
return ".unknown"
|
36
|
+
end
|
37
|
+
|
38
|
+
def getkey(hsh,hkey)
|
39
|
+
if hsh.has_key?(hkey) then
|
40
|
+
return hsh[hkey]
|
41
|
+
else
|
42
|
+
return ''
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def sev2word(sev)
|
47
|
+
case sev
|
48
|
+
when 7
|
49
|
+
return "Critical"
|
50
|
+
when 6
|
51
|
+
return "High"
|
52
|
+
when 5
|
53
|
+
return "Medium"
|
54
|
+
when 4
|
55
|
+
return "Low"
|
56
|
+
when 3
|
57
|
+
return "Info"
|
58
|
+
when 2
|
59
|
+
return "Verbose"
|
60
|
+
when 1
|
61
|
+
return "Inspect"
|
62
|
+
when 0
|
63
|
+
return "Debug"
|
64
|
+
else
|
65
|
+
return "DebugMiss"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def report(opts)
|
70
|
+
raise "#{self.class.name} doesn't implement `handle_command`!"
|
71
|
+
end
|
72
|
+
end # Class
|
73
|
+
|
74
|
+
end # Module
|
75
|
+
end # Dockscan
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Dockscan
|
2
|
+
module Scan
|
3
|
+
class Issue
|
4
|
+
attr_accessor :severity, :description, :solution, :title, :tags, :references, :risk, :reflinks
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
severity=0
|
8
|
+
description="Forgot to add description"
|
9
|
+
solution="Information only."
|
10
|
+
title="Forgot to add title"
|
11
|
+
tags=Hash.new
|
12
|
+
references=Hash.new
|
13
|
+
risk=Hash.new
|
14
|
+
reflinks=Hash.new
|
15
|
+
end
|
16
|
+
end # Issue
|
17
|
+
end # Scan
|
18
|
+
end # Dockscan
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'docker'
|
2
|
+
|
3
|
+
require 'dockscan/modules/genmodule'
|
4
|
+
require 'dockscan/modules/discover'
|
5
|
+
require 'dockscan/modules/audit'
|
6
|
+
require 'dockscan/modules/report'
|
7
|
+
|
8
|
+
require 'dockscan/scan/plugin'
|
9
|
+
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
module Dockscan
|
13
|
+
module Scan
|
14
|
+
class Manage
|
15
|
+
|
16
|
+
attr_accessor :log
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@auditoutput=Hash.new
|
20
|
+
@log=Logger.new MultiDelegator.delegate(:write, :close).to(STDERR)
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_connection
|
24
|
+
@log.info("Validating version specified: "+Docker.url)
|
25
|
+
begin
|
26
|
+
Docker.validate_version!
|
27
|
+
rescue
|
28
|
+
@log.error("Error connecting or validating Docker version")
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
def scan (url, opts, logger)
|
35
|
+
failed=Array.new
|
36
|
+
|
37
|
+
if url != nil then
|
38
|
+
Docker.url = url
|
39
|
+
end
|
40
|
+
|
41
|
+
@log=logger
|
42
|
+
|
43
|
+
if not check_connection then
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
moduledirs=Array.new
|
48
|
+
if moduledirs.empty? then
|
49
|
+
moduledirs.push File.expand_path("../modules", File.dirname(__FILE__))
|
50
|
+
end
|
51
|
+
|
52
|
+
@log.info("Loading discovery modules...")
|
53
|
+
moduledirs.each do |moduledir|
|
54
|
+
@log.debug("Loading dir: #{moduledir}")
|
55
|
+
Dir["#{moduledir}/discover/*.rb"].each do |f|
|
56
|
+
@log.info("Loading discovery module: #{f}")
|
57
|
+
begin
|
58
|
+
require f
|
59
|
+
rescue SyntaxError => se
|
60
|
+
@log.info("Error loading audit module: #{f}")
|
61
|
+
@log.debug("Error executing audit module: #{se.backtrace}")
|
62
|
+
failed << f
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@log.info("Running discovery modules...")
|
68
|
+
Dockscan::Modules::DiscoverModule.modules.each do |modclass|
|
69
|
+
@log.info("Running discovery module: #{modclass.name}")
|
70
|
+
begin
|
71
|
+
mod=modclass.new
|
72
|
+
mod.scandata=@auditoutput
|
73
|
+
@auditoutput[mod.class.name]=mod.run
|
74
|
+
rescue Exception => e
|
75
|
+
@log.info("Error executing audit module: #{modclass.name}")
|
76
|
+
@log.debug("Error executing audit module: #{e.backtrace}")
|
77
|
+
failed << modclass.name
|
78
|
+
end
|
79
|
+
# pp @auditoutput[mod.class.name]
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
@log.info("Loading audit modules...")
|
84
|
+
moduledirs.each do |moduledir|
|
85
|
+
@log.debug("Loading dir: #{moduledir}")
|
86
|
+
Dir["#{moduledir}/audit/*.rb"].each do |f|
|
87
|
+
@log.info("Loading audit module: #{f}")
|
88
|
+
begin
|
89
|
+
require f
|
90
|
+
rescue SyntaxError => se
|
91
|
+
@log.info("Error loading audit module: #{f}")
|
92
|
+
@log.debug("Error executing audit module: #{se.backtrace}")
|
93
|
+
failed << f
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
@log.info("Running audit modules...")
|
99
|
+
Dockscan::Modules::AuditModule.modules.each do |modclass|
|
100
|
+
@log.info("Running audit module: #{modclass.name}")
|
101
|
+
begin
|
102
|
+
mod=modclass.new
|
103
|
+
mod.scandata=@auditoutput
|
104
|
+
@auditoutput[mod.class.name]=mod.check('test')
|
105
|
+
rescue Exception => e
|
106
|
+
@log.info("Error executing audit module: #{modclass.name}")
|
107
|
+
@log.debug("Error executing audit module: #{e.to_s} #{e.backtrace}")
|
108
|
+
failed << modclass.name
|
109
|
+
end
|
110
|
+
# pp @auditoutput[mod.class.name]
|
111
|
+
end
|
112
|
+
|
113
|
+
@log.info("Loading report modules...")
|
114
|
+
moduledirs.each do |moduledir|
|
115
|
+
Dir["#{moduledir}/report/*.rb"].each do |f|
|
116
|
+
@log.info("Loading report #{f}")
|
117
|
+
begin
|
118
|
+
require f
|
119
|
+
rescue SyntaxError => se
|
120
|
+
@log.info("Error loading report module: #{f}")
|
121
|
+
@log.debug("Error executing report module: #{se.backtrace}")
|
122
|
+
failed << f
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
@log.info("Running report modules...")
|
128
|
+
Dockscan::Modules::ReportModule.modules.each do |modclass|
|
129
|
+
@log.info("Running report module: #{modclass.name}")
|
130
|
+
mod=modclass.new
|
131
|
+
if opts.key?("report") then
|
132
|
+
formats=opts["report"].split(",")
|
133
|
+
else
|
134
|
+
formats=['stdout']
|
135
|
+
end
|
136
|
+
formats.each do |fmt|
|
137
|
+
if fmt==mod.format then
|
138
|
+
begin
|
139
|
+
mod.scandata=@auditoutput
|
140
|
+
output=mod.report(nil)
|
141
|
+
if opts.key?("output") then
|
142
|
+
reportfilename = opts["output"]
|
143
|
+
reportfilename << mod.file_extension
|
144
|
+
File.open(reportfilename, 'w') { |file| file.write(output) }
|
145
|
+
else
|
146
|
+
puts output
|
147
|
+
end
|
148
|
+
rescue Exception => e
|
149
|
+
@log.info("Error executing report module: #{modclass.name}")
|
150
|
+
@log.debug("Error executing report module: #{e.to_s} #{e.backtrace}")
|
151
|
+
failed << modclass.name
|
152
|
+
end
|
153
|
+
@log.debug(output)
|
154
|
+
else
|
155
|
+
@log.debug("Skipping report module: #{modclass.name}");
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
if failed.count > 0
|
161
|
+
failedstr=""
|
162
|
+
failed.each do |f|
|
163
|
+
failedstr = f + " "
|
164
|
+
end
|
165
|
+
@log.warn("Following modules failed: #{failedstr}")
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end # Class
|
170
|
+
end # Scan
|
171
|
+
end # Dockscan
|
172
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'dockscan/scan/issue'
|
2
|
+
|
3
|
+
module Dockscan
|
4
|
+
module Scan
|
5
|
+
class Plugin
|
6
|
+
attr_accessor :state, :output, :obj, :vuln, :cname
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
state="untested"
|
10
|
+
vuln = Dockscan::Scan::Issue.new
|
11
|
+
end
|
12
|
+
end # Plugin
|
13
|
+
end # Scan
|
14
|
+
end # Dockscan
|