owasp-glue 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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