owasp-glue 0.9.0

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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +27 -0
  3. data/FEATURES +19 -0
  4. data/README.md +117 -0
  5. data/bin/glue +67 -0
  6. data/lib/glue.rb +317 -0
  7. data/lib/glue/event.rb +14 -0
  8. data/lib/glue/filters.rb +41 -0
  9. data/lib/glue/filters/base_filter.rb +19 -0
  10. data/lib/glue/filters/jira_one_time_filter.rb +57 -0
  11. data/lib/glue/filters/remove_all_filter.rb +16 -0
  12. data/lib/glue/filters/zap_consdensing_filter.rb +76 -0
  13. data/lib/glue/finding.rb +52 -0
  14. data/lib/glue/mounters.rb +55 -0
  15. data/lib/glue/mounters/base_mounter.rb +31 -0
  16. data/lib/glue/mounters/docker_mounter.rb +44 -0
  17. data/lib/glue/mounters/filesystem_mounter.rb +20 -0
  18. data/lib/glue/mounters/git_mounter.rb +52 -0
  19. data/lib/glue/mounters/iso_mounter.rb +42 -0
  20. data/lib/glue/mounters/url_mounter.rb +28 -0
  21. data/lib/glue/options.rb +269 -0
  22. data/lib/glue/reporters.rb +50 -0
  23. data/lib/glue/reporters/base_reporter.rb +21 -0
  24. data/lib/glue/reporters/csv_reporter.rb +19 -0
  25. data/lib/glue/reporters/jira_reporter.rb +59 -0
  26. data/lib/glue/reporters/json_reporter.rb +20 -0
  27. data/lib/glue/reporters/text_reporter.rb +19 -0
  28. data/lib/glue/scanner.rb +28 -0
  29. data/lib/glue/tasks.rb +124 -0
  30. data/lib/glue/tasks/av.rb +42 -0
  31. data/lib/glue/tasks/base_task.rb +80 -0
  32. data/lib/glue/tasks/brakeman.rb +58 -0
  33. data/lib/glue/tasks/bundle-audit.rb +95 -0
  34. data/lib/glue/tasks/checkmarx.rb +60 -0
  35. data/lib/glue/tasks/dawnscanner.rb +55 -0
  36. data/lib/glue/tasks/eslint.rb +69 -0
  37. data/lib/glue/tasks/fim.rb +60 -0
  38. data/lib/glue/tasks/findsecbugs.rb +90 -0
  39. data/lib/glue/tasks/npm.rb +58 -0
  40. data/lib/glue/tasks/nsp.rb +65 -0
  41. data/lib/glue/tasks/owasp-dep-check.rb +117 -0
  42. data/lib/glue/tasks/patterns.json +394 -0
  43. data/lib/glue/tasks/pmd.rb +63 -0
  44. data/lib/glue/tasks/retirejs.rb +107 -0
  45. data/lib/glue/tasks/scanjs-eslintrc +106 -0
  46. data/lib/glue/tasks/scanjs.rb +31 -0
  47. data/lib/glue/tasks/sfl.rb +67 -0
  48. data/lib/glue/tasks/snyk.rb +81 -0
  49. data/lib/glue/tasks/test.rb +47 -0
  50. data/lib/glue/tasks/zap.rb +99 -0
  51. data/lib/glue/tracker.rb +47 -0
  52. data/lib/glue/util.rb +36 -0
  53. data/lib/glue/version.rb +3 -0
  54. metadata +294 -0
@@ -0,0 +1,42 @@
1
+ require 'glue/mounters/base_mounter'
2
+
3
+ class Glue::ISOMounter < Glue::BaseMounter
4
+
5
+ # THIS DOESN'T WORK SO DON'T REGISTER FOR NOW
6
+ # Glue::Mounters.add self
7
+
8
+ def initialize trigger, options
9
+ super(trigger)
10
+ @options = options
11
+ @name = "ISO"
12
+ @description = "Mount an iso image."
13
+ end
14
+
15
+ def mount target
16
+ base = @options[:working_dir]
17
+ working_target = base + "/" + target + "/"
18
+ Glue.notify "Cleaning directory: #{working_target}"
19
+
20
+ if ! working_target.match(/\A.*\/line\/tmp\/.*/)
21
+ Glue.notify "Bailing in case #{working_target} is malicious."
22
+ else
23
+ result = `rm -rf #{working_target}`
24
+ # puts result
25
+ result = `mkdir -p #{working_target}`
26
+ # puts result
27
+ Glue.notify "Mounting #{target} to #{working_target}"
28
+ result = `mount -t iso9660 #{target} #{working_target}`
29
+ # puts result
30
+ end
31
+ return working_target
32
+ end
33
+
34
+ def supports? target
35
+ last = target.slice(-4,target.length)
36
+ if last === ".iso"
37
+ return true
38
+ else
39
+ return false
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,28 @@
1
+ require 'glue/mounters/base_mounter'
2
+
3
+ class Glue::URLMounter < Glue::BaseMounter
4
+ Glue::Mounters.add self
5
+
6
+ def initialize trigger, options
7
+ super(trigger)
8
+ @options = options
9
+ @name = "URL"
10
+ @description = "Mount a url - typically for a live attack."
11
+ end
12
+
13
+ def mount target
14
+ return target
15
+ end
16
+
17
+ def supports? target
18
+ start = target.slice(0,4)
19
+ last = target.slice(-4,target.length)
20
+ if last === ".git"
21
+ return false
22
+ elsif start === "http"
23
+ return true
24
+ else
25
+ return false
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,269 @@
1
+ require 'optparse'
2
+ require 'set'
3
+
4
+ #Parses command line arguments for Brakeman
5
+ module Glue::Options
6
+
7
+ class << self
8
+
9
+ #Parse argument array
10
+ def parse args
11
+ get_options args
12
+ end
13
+
14
+ #Parse arguments and remove them from the array as they are matched
15
+ def parse! args
16
+ get_options args, true
17
+ end
18
+
19
+ #Return hash of options and the parser
20
+ def get_options args, destructive = false
21
+ options = {}
22
+
23
+ parser = OptionParser.new do |opts|
24
+ opts.banner = "Usage: Glue [options] image/root/path"
25
+
26
+ opts.separator ""
27
+ opts.separator "Glue is a swiss army knife of security analysis tools."
28
+ opts.separator "It has built in support for static analysis, AV, fim, and "
29
+ opts.separator "is being extended to be used for analyzing all kinds of "
30
+ opts.separator "projects, images or file systems."
31
+ opts.separator ""
32
+ opts.separator "Glue also features filters to perform deduplication "
33
+ opts.separator "and the abilty to handle false positives."
34
+ opts.separator ""
35
+ opts.separator "See also the docker image."
36
+ opts.separator ""
37
+
38
+ opts.separator "Control options:"
39
+
40
+ opts.on "-n", "--no-threads", "Run checks sequentially" do
41
+ options[:parallel_checks] = false
42
+ end
43
+
44
+ opts.on "--[no-]progress", "Show progress reports" do |progress|
45
+ options[:report_progress] = progress
46
+ end
47
+
48
+ opts.on "-T", "--target PATH", "Specify target" do |target|
49
+ options[:target] = path
50
+ end
51
+
52
+ opts.on "-q", "--[no-]quiet", "Suppress informational messages" do |quiet|
53
+ options[:quiet] = quiet
54
+ end
55
+
56
+ opts.on( "-z", "--exit-on-warn", "Exit code is non-zero if warnings found") do
57
+ options[:exit_on_warn] = true
58
+ end
59
+
60
+ opts.separator ""
61
+ opts.separator "Scanning options:"
62
+
63
+ opts.on "-A", "--run-all-checks", "Run all default and optional checks" do
64
+ options[:run_all_checks] = true
65
+ end
66
+
67
+ opts.on "-t", "--test Check1,Check2,etc", Array, "Only run the specified checks" do |checks|
68
+ options[:run_tasks] ||= Set.new
69
+ options[:run_tasks].merge checks
70
+ end
71
+
72
+ opts.on "-x", "--except Check1,Check2,etc", Array, "Skip the specified checks" do |skip|
73
+ skip.each do |s|
74
+
75
+ options[:skip_checks] ||= Set.new
76
+ options[:skip_checks] << s
77
+ end
78
+ end
79
+
80
+ opts.on "-a", "--appname NAME", "Override the inferred application name." do |appname|
81
+ options[:appname] = appname
82
+ end
83
+
84
+ opts.on "-r", "--revision REV", "Specify a revision of software to pass on to checkmarx" do |revision|
85
+ options[:revision] = revision
86
+ end
87
+
88
+ opts.on "-l", "--labels Label1,Label2,etc", Array, "Run the checks with the supplied labels" do |labels|
89
+ options[:labels] ||= Set.new
90
+ options[:labels].merge labels
91
+ end
92
+
93
+ opts.on "--add-checks-path path1,path2,etc", Array, "A directory containing additional out-of-tree checks to run" do |paths|
94
+ options[:additional_checks_path] ||= Set.new
95
+ options[:additional_checks_path].merge paths.map {|p| File.expand_path p}
96
+ end
97
+
98
+ opts.on "--npm-registry URL", "Use a custom npm registry when installing dependencies for javascript scanners" do |url|
99
+ options[:npm_registry] = url
100
+ end
101
+
102
+ opts.on "--exclude path1,path2,path3,etc", Array, "A list of paths to ignore when running recursive tasks (npm, retirejs, snyk, etc)" do |paths|
103
+ paths.each do |path|
104
+ options[:exclude_dirs] ||= Set.new
105
+ options[:exclude_dirs] << path
106
+ end
107
+ end
108
+
109
+ opts.separator ""
110
+ opts.separator "Output options:"
111
+
112
+ opts.on "-d", "--debug", "Lots of output" do
113
+ options[:debug] = true
114
+ end
115
+
116
+ opts.on "-f",
117
+ "--format TYPE",
118
+ [:text, :html, :csv, :tabs, :json, :jira, :markdown],
119
+ "Specify output formats. Default is text" do |type|
120
+ options[:output_format] = type
121
+ end
122
+
123
+ opts.on "--css-file CSSFile", "Specify CSS to use for HTML output" do |file|
124
+ options[:html_style] = File.expand_path file
125
+ end
126
+
127
+ opts.on "-i IGNOREFILE", "--ignore-config IGNOREFILE", "Use configuration to ignore warnings" do |file|
128
+ options[:ignore_file] = file
129
+ end
130
+
131
+ opts.on "-I", "--interactive-ignore", "Interactively ignore warnings" do
132
+ options[:interactive_ignore] = true
133
+ end
134
+
135
+ opts.on "-o", "--output FILE", "Specify file for output. Defaults to stdout." do |file|
136
+ options[:output_file] = file
137
+ end
138
+
139
+ opts.on "--summary", "Only output summary of warnings" do
140
+ options[:summary_only] = true
141
+ end
142
+
143
+ opts.on "-L LOGFILE", "--logfile LOGFILE", "Write full Glue log to LOGFILE" do |file|
144
+ options[:logfile] = file
145
+ end
146
+
147
+ opts.separator ""
148
+ opts.separator "JIRA options:"
149
+
150
+ opts.on "--jira-project PROJECT", "Specify the jira project to create issues in. If issue looks like APPS-13, this should be APPS." do |project|
151
+ options[:jira_project] = project
152
+ end
153
+
154
+ opts.on "--jira-api-url URL", "Specify the jira rest api endpoint. Eg. domain.com/jira/jira/rest/api/2/." do |url|
155
+ options[:jira_api_url] = url
156
+ end
157
+
158
+ opts.on "--jira-cookie COOKIE", "Specify the session cookie to get to Jira." do |cookie|
159
+ options[:jira_cookie] = cookie
160
+ end
161
+
162
+ opts.on "--jira-component COMPONENT", "Specify the JIRA component to use." do |component|
163
+ options[:jira_component] = component
164
+ end
165
+
166
+ opts.separator ""
167
+ opts.separator "ZAP options:"
168
+
169
+ opts.on "--zap-api-token token", "Specify the ZAP API token to use when connecting to the API" do |token|
170
+ options[:zap_api_token] = token
171
+ end
172
+
173
+ opts.on "--zap-host HOST", "Specify the host ZAP is running on." do |host|
174
+ options[:zap_host] = host
175
+ end
176
+
177
+ opts.on "--zap-port PORT", "Specify the port ZAP is running on." do |port|
178
+ options[:zap_port] = port
179
+ end
180
+
181
+ opts.separator ""
182
+ opts.separator "Checkmarx options:"
183
+
184
+ opts.on "--checkmarx-user USER", "Specify the Checkmarx user to use when connecting to the API" do |user|
185
+ options[:checkmarx_user] = user
186
+ end
187
+
188
+ opts.on "--checkmarx-password PASSWORD", "Specify password for the Checkmarx API user" do |password|
189
+ options[:checkmarx_password] = password
190
+ end
191
+
192
+ opts.on "--checkmarx-server server", "Specify the API server to use for Checkmarx scans" do |server|
193
+ options[:checkmarx_server] = server
194
+ end
195
+
196
+ opts.on "--checkmarx-log logfile", "Specify the log file to use for Checkmarx scans" do |logfile|
197
+ options[:checkmarx_log] = logfile
198
+ end
199
+
200
+ opts.on "--checkmarx-project project", "Specify the full path of the Checkmarx project for this scan" do |project|
201
+ options[:checkmarx_project] = project
202
+ end
203
+
204
+ opts.separator ""
205
+ opts.separator "PMD options:"
206
+
207
+ opts.on "--pmd-path PATH", "The full path to the base PMD directory" do |dir|
208
+ options[:pmd_path] = dir
209
+ end
210
+
211
+ opts.on "--pmd-checks CHECK1,CHECK2", "The list of checks passed to PMD run.sh -R, default: 'java-basic,java-sunsecure'" do |checks|
212
+ options[:pmd_checks] = checks
213
+ end
214
+
215
+ opts.separator ""
216
+ opts.separator "FindSecurityBugs options:"
217
+
218
+ opts.on "--findsecbugs-path PATH", "The full path to the base FindSecurityBugs directory" do |dir|
219
+ options[:findsecbugs_path] = dir
220
+ end
221
+
222
+ opts.separator ""
223
+ opts.separator "Configuration files:"
224
+
225
+ opts.on "-c", "--config-file FILE", "Use specified configuration file" do |file|
226
+ options[:config_file] = File.expand_path(file)
227
+ end
228
+
229
+ opts.on "-C", "--create-config [FILE]", "Output configuration file based on options" do |file|
230
+ if file
231
+ options[:create_config] = file
232
+ else
233
+ options[:create_config] = true
234
+ end
235
+ end
236
+
237
+ opts.separator ""
238
+
239
+ opts.on "-k", "--checks", "List all available vulnerability checks" do
240
+ options[:list_checks] = true
241
+ end
242
+
243
+ opts.on "--optional-checks", "List optional checks" do
244
+ options[:list_optional_checks] = true
245
+ end
246
+
247
+ opts.on "-v", "--version", "Show Glue version" do
248
+ options[:show_version] = true
249
+ end
250
+
251
+ opts.on_tail "-h", "--help", "Display this message" do
252
+ options[:show_help] = true
253
+ end
254
+ end
255
+
256
+ if destructive
257
+ parser.parse! args
258
+ else
259
+ parser.parse args
260
+ end
261
+
262
+ if options[:previous_results_json] and options[:output_files]
263
+ options[:comparison_output_file] = options[:output_files].shift
264
+ end
265
+
266
+ return options, parser
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,50 @@
1
+ class Glue::Reporters
2
+ @reporters = []
3
+
4
+ #Add a task. This will call +_klass_.new+ when running tests
5
+ def self.add klass
6
+ @reporters << klass unless @reporters.include? klass
7
+ end
8
+
9
+ def self.reporters
10
+ @reporters
11
+ end
12
+
13
+ def self.initialize_reporters reporters_directory = ""
14
+ #Load all files in task_directory
15
+ Dir.glob(File.join(reporters_directory, "*.rb")).sort.each do |f|
16
+ require f
17
+ end
18
+ end
19
+
20
+ #No need to use this directly.
21
+ def initialize options = { }
22
+ end
23
+
24
+ #Run all the tasks on the given Tracker.
25
+ #Returns a new instance of tasks with the results.
26
+ def self.run_report(tracker)
27
+ @reporters.each do |c|
28
+ reporter = c.new()
29
+ if tracker.options[:output_format].first == reporter.format
30
+ begin
31
+ output = reporter.run_report(tracker)
32
+ if tracker.options[:output_file]
33
+ file = File.open(tracker.options[:output_file], 'w'){ |f| f.write(output)}
34
+ else
35
+ Glue.notify output unless tracker.options[:quiet]
36
+ end
37
+ rescue => e
38
+ Glue.error e.message
39
+ tracker.error e
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ #Load all files in reporters/ directory
48
+ Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/reporters/*.rb").sort.each do |f|
49
+ require f.match(/(glue\/reporters\/.*)\.rb$/)[0]
50
+ end
@@ -0,0 +1,21 @@
1
+ require 'glue/finding'
2
+
3
+ class Glue::BaseReporter
4
+ attr_accessor :name, :format
5
+
6
+ def initialize()
7
+ end
8
+
9
+ def run_report(tracker)
10
+ Glue.notify "Running base reoprt..."
11
+ output = ""
12
+ tracker.findings.each do |finding|
13
+ output += out(finding)
14
+ end
15
+ output
16
+ end
17
+
18
+ def out(finding)
19
+ end
20
+
21
+ end
@@ -0,0 +1,19 @@
1
+ require 'glue/finding'
2
+ require 'glue/reporters/base_reporter'
3
+
4
+ class Glue::CSVReporter < Glue::BaseReporter
5
+
6
+ Glue::Reporters.add self
7
+
8
+ attr_accessor :name, :format
9
+
10
+ def initialize()
11
+ @name = "CSVReporter"
12
+ @format = :to_csv
13
+ end
14
+
15
+ def out(finding)
16
+ finding.to_csv
17
+ end
18
+
19
+ end
@@ -0,0 +1,59 @@
1
+ require 'glue/finding'
2
+ require 'glue/reporters/base_reporter'
3
+ require 'json'
4
+ require 'curb'
5
+
6
+ class Glue::JiraReporter < Glue::BaseReporter
7
+
8
+ Glue::Reporters.add self
9
+
10
+ attr_accessor :name, :format
11
+
12
+ def initialize()
13
+ @name = "JiraReporter"
14
+ @format = :to_jira
15
+ end
16
+
17
+ def run_report(tracker)
18
+ @project = tracker.options[:jira_project.to_s]
19
+ @api = tracker.options[:jira_api_url.to_s]
20
+ @cookie = tracker.options[:jira_cookie.to_s]
21
+ @component = tracker.options[:jira_component.to_s]
22
+
23
+ tracker.findings.each do |finding|
24
+ report finding
25
+ end
26
+ "Results are in JIRA"
27
+ end
28
+
29
+ def report(finding)
30
+ json = get_jira_json(finding)
31
+ http = Curl.post("#{@api}/issue/", json.to_s) do |http|
32
+ http.headers['Content-Type'] = "application/json"
33
+ http.headers['Cookie'] = @cookie
34
+ end
35
+ if http.response_code != 201 # Created ...
36
+ Glue.error "Problem with HTTP #{http.response_code} - #{http.body_str}"
37
+ end
38
+ end
39
+
40
+ private
41
+ def get_jira_json(finding)
42
+ json = {
43
+ "fields": {
44
+ "project":
45
+ {
46
+ "key": "#{@project}"
47
+ },
48
+ "summary": "#{finding.appname} - #{finding.description}",
49
+ "description": "#{finding.to_string}\n\nFINGERPRINT: #{finding.fingerprint}",
50
+ "issuetype": {
51
+ "name": "Task"
52
+ },
53
+ "labels":["Glue","#{finding.appname}"],
54
+ "components": [ { "name": "#{@component}" } ]
55
+ }
56
+ }.to_json
57
+ json
58
+ end
59
+ end