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,60 @@
1
+ require 'glue/tasks/base_task'
2
+ require 'glue/util'
3
+ require 'nokogiri'
4
+
5
+ class Glue::Checkmarx < Glue::BaseTask
6
+
7
+ # Glue::Tasks.add self
8
+ include Glue::Util
9
+
10
+ def initialize(trigger, tracker)
11
+ super(trigger, tracker)
12
+ @name = "Checkmarx"
13
+ @description = "CxSAST"
14
+ @stage = :code
15
+ @labels << "code"
16
+ end
17
+
18
+ def run
19
+ rootpath = @trigger.path
20
+ runsystem(true, "runCxConsole.sh", "scan", "-v",
21
+ "-CxUser", "#{@tracker.options[:checkmarx_user]}",
22
+ "-CxPassword", "#{@tracker.options[:checkmarx_password]}",
23
+ "-CxServer", "#{@tracker.options[:checkmarx_server]}",
24
+ "-LocationType", "folder",
25
+ "-LocationPath", "#{rootpath}",
26
+ "-ProjectName", "#{@tracker.options[:checkmarx_project]}",
27
+ "-ReportXML", "#{rootpath}checkmarx_results.xml",
28
+ "-Log", "#{@tracker.options[:checkmarx_log]}"
29
+ )
30
+ @results = Nokogiri::XML(File.read("#{rootpath}checkmarx_results.xml")).xpath '//Result'
31
+ end
32
+
33
+ def analyze
34
+ begin
35
+ @results.each do |result|
36
+ description = result.parent.attributes['name'].value.gsub('_', ' ')
37
+ detail = result.attributes['DeepLink'].value
38
+ source = { :scanner => @name, :file => result.attributes['FileName'].value, :line => result.attributes['Line'].value.to_i, :code => result.at_xpath('Path/PathNode/Snippet/Line/Code').text }
39
+ sev = severity(result.parent.attributes['Severity'].value)
40
+ fprint = fingerprint("#{description}#{source}#{sev}")
41
+
42
+ report description, detail, source, sev, fprint
43
+ end
44
+ rescue Exception => e
45
+ Glue.warn e.message
46
+ Glue.warn e.backtrace
47
+ end
48
+ end
49
+
50
+ def supported?
51
+ supported=runsystem(true, "runCxConsole.sh", "--help")
52
+ if supported =~ /command not found/
53
+ Glue.notify "Install CxConsolePlugin"
54
+ return false
55
+ else
56
+ return true
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,55 @@
1
+ require 'glue/tasks/base_task'
2
+ require 'glue/util'
3
+ require 'tempfile'
4
+
5
+ class Glue::DawnScanner < Glue::BaseTask
6
+
7
+ Glue::Tasks.add self
8
+ include Glue::Util
9
+
10
+ def initialize(trigger, tracker)
11
+ super(trigger, tracker)
12
+ @name = "DawnScanner"
13
+ @description = "DawnScanner ruby analyzer"
14
+ @stage = :code
15
+ @labels << "code"
16
+ end
17
+
18
+ def run
19
+ Dir.chdir("#{@trigger.path}") do
20
+ @results_file = Tempfile.new(['dawnresults', 'xml'])
21
+ runsystem(true, "dawn", "-F", "#{@results_file.path}", "-j", ".")
22
+ @results = JSON.parse(File.read("#{@results_file.path}"))['vulnerabilities']
23
+ end
24
+ end
25
+
26
+ def analyze
27
+ begin
28
+ @results.each do |result|
29
+ description = result['name'].gsub('\n',' ')
30
+ detail = "#{result['message']}\n#{result['remediation']}\n#{result['cve_link']}"
31
+ source = {:scanner => @name, :file => nil, :line => nil, :code => nil}
32
+ sev = severity(result['severity'])
33
+ fprint = fingerprint("#{description}#{detail}#{source}#{sev}")
34
+
35
+ report description, detail, source, sev, fprint
36
+ end
37
+ rescue Exception => e
38
+ Glue.warn e.message
39
+ Glue.warn e.backtrace
40
+ ensure
41
+ File.unlink @results_file
42
+ end
43
+ end
44
+
45
+ def supported?
46
+ supported=runsystem(true, "dawn", "--version")
47
+ if supported =~ /command not found/
48
+ Glue.notify "Install dawnscanner: 'gem install dawnscanner'"
49
+ return false
50
+ else
51
+ return true
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,69 @@
1
+ require 'glue/tasks/base_task'
2
+ require 'json'
3
+ require 'glue/util'
4
+
5
+ class Glue::ESLint < Glue::BaseTask
6
+
7
+ Glue::Tasks.add self
8
+ include Glue::Util
9
+
10
+ def initialize(trigger, tracker)
11
+ super(trigger,tracker)
12
+ @name = "ESLint/ScanJS"
13
+ @description = "Source analysis for JavaScript"
14
+ @stage = :code
15
+ @labels << "code" << "javascript"
16
+ end
17
+
18
+ def run
19
+ rootpath = @trigger.path
20
+ currentpath = File.expand_path File.dirname(__FILE__)
21
+ Glue.debug "ESLint Config Path: #{currentpath}"
22
+ @result = `eslint -c #{currentpath}/scanjs-eslintrc --no-color --quiet --format json #{rootpath}`
23
+ end
24
+
25
+ def analyze
26
+ # puts @result
27
+ begin
28
+ parsed = JSON.parse(@result)
29
+ parsed.each do |result|
30
+ findings = {}
31
+ prints = []
32
+ messages = []
33
+ result['messages'].each do |msg|
34
+ message = msg['message']
35
+ findings[message] = {} if findings[message].nil?
36
+ findings[message][:detail] = msg['ruleId']
37
+ if messages.include?(message)
38
+ findings[message][:source] = "#{findings[message][:source]},#{msg['line']}" unless findings[message][:source].include?(",#{msg['line']}")
39
+ else
40
+ findings[message][:source] = "#{result['filePath']} Line: #{msg['line']}"
41
+ messages << message
42
+ end
43
+ findings[message][:severity] = severity(msg['severity'].to_s)
44
+ end
45
+ findings.each do |key, value|
46
+ print = fingerprint("#{key}#{value[:detail]}#{value[:source]}#{value[:sev]}")
47
+ unless prints.include?(print)
48
+ prints << print
49
+ report key, value[:detail], value[:source], value[:severity], print
50
+ end
51
+ end
52
+ end
53
+ rescue Exception => e
54
+ Glue.warn e.message
55
+ Glue.warn e.backtrace
56
+ end
57
+ end
58
+
59
+ def supported?
60
+ supported=runsystem(true, "eslint", "-c", "~/.scanjs-eslintrc")
61
+ if supported =~ /command not found/
62
+ Glue.notify "Install eslint and the scanjs .eslintrc"
63
+ return false
64
+ else
65
+ return true
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,60 @@
1
+ # https://github.com/jessek/hashdeep/releases/tag/release-4.4
2
+
3
+ require 'glue/tasks/base_task'
4
+ require 'open3'
5
+
6
+ class Glue::FIM < Glue::BaseTask
7
+
8
+ Glue::Tasks.add self
9
+
10
+ def initialize(trigger, tracker)
11
+ super(trigger,tracker)
12
+ @name = "FIM"
13
+ @description = "File integrity monitor"
14
+ @stage = :file
15
+ @result = ''
16
+ @labels << "filesystem"
17
+ end
18
+
19
+ def run
20
+ rootpath = @trigger.path
21
+ if File.exists?("/area81/tmp/#{rootpath}/filehash")
22
+ Glue.notify "File Hashes found, comparing to file system"
23
+ cmd="hashdeep -j99 -r -a -vv -k /area81/tmp/#{rootpath}/filehash #{rootpath}"
24
+
25
+ # Ugly stdout parsing
26
+ r=/(.*): No match/
27
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
28
+ while line = stdout.gets
29
+ if line.match r
30
+ @result << line
31
+ end
32
+ end
33
+ end
34
+ else
35
+ Glue.notify "No existing baseline - generating initial hashes"
36
+ cmd="mkdir -p /area81/tmp/#{rootpath}; hashdeep -j99 -r #{rootpath} > /area81/tmp/#{rootpath}/filehash"
37
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
38
+ while line = stdout.gets
39
+ puts "."
40
+ end
41
+ end
42
+ @result = ''
43
+ end
44
+ end
45
+
46
+ def analyze
47
+ list = @result.split(/\n/)
48
+ list.each do |v|
49
+ # v.slice! installdir
50
+ Glue.notify v
51
+ report "File changed.", v, @name, :low
52
+ end
53
+ end
54
+
55
+ def supported?
56
+ # In future, verify tool is available.
57
+ return true
58
+ end
59
+
60
+ end
@@ -0,0 +1,90 @@
1
+ require 'glue/tasks/base_task'
2
+ require 'glue/util'
3
+ require 'nokogiri'
4
+ require 'tempfile'
5
+ require 'mkmf'
6
+
7
+ MakeMakefile::Logging.instance_variable_set(:@logfile, File::NULL)
8
+
9
+ class Glue::FindSecurityBugs < Glue::BaseTask
10
+
11
+ Glue::Tasks.add self
12
+ include Glue::Util
13
+
14
+ def initialize(trigger, tracker)
15
+ super(trigger, tracker)
16
+ @name = "FindSecurityBugs"
17
+ @description = "FindSecurityBugs plugin for FindBugs"
18
+ @stage = :code
19
+ @labels << "code"
20
+ end
21
+
22
+ def run
23
+ @results_file = Tempfile.new(['findsecbugs','xml'])
24
+
25
+ unless File.exist?("#{@trigger.path}/.git/config")
26
+ Dir.chdir(@trigger.path) do
27
+ runsystem(true, "git", "init")
28
+ runsystem(true, "git", "add", "*")
29
+ runsystem(true, "git", "commit", "-am", "fake commit for mvn compile")
30
+ end
31
+ end
32
+
33
+ directories_with?('pom.xml').each do |dir|
34
+ Dir.chdir(dir) do
35
+ runsystem(true, "mvn", "compile", "-fn")
36
+ end
37
+ end
38
+
39
+ Dir.chdir(@tracker.options[:findsecbugs_path]) do
40
+ runsystem(true, "/bin/sh", "#{@tracker.options[:findsecbugs_path]}/findsecbugs.sh", "-effort:max", "-quiet", "-xml:withMessages", "-output", "#{@results_file.path}", "#{@trigger.path}")
41
+ @results = Nokogiri::XML(File.read(@results_file)).xpath '//BugInstance'
42
+ end
43
+ end
44
+
45
+ def analyze
46
+ begin
47
+ @results.each do |result|
48
+ description = result.xpath('ShortMessage').text
49
+ bug_type = result.attributes['type'].value
50
+ detail = "Class: #{result.at_xpath('Method').attributes['classname'].value}, Method: #{result.at_xpath('Method').attributes['name'].value}\n#{result.xpath('LongMessage').text}\nhttps://find-sec-bugs.github.io/bugs.htm##{bug_type}"
51
+
52
+ file = result.at_xpath('SourceLine').attributes['sourcepath'].value
53
+ trigger_path = Pathname.new(@trigger.path)
54
+ real_path = nil
55
+ trigger_path.find {|path| real_path = path if path.fnmatch "*/#{file}"}
56
+ file = real_path.relative_path_from(trigger_path).to_s unless real_path.nil?
57
+
58
+ line = result.at_xpath('SourceLine[@primary="true"]').attributes['start'].value
59
+ code = "#{result.at_xpath('String').attributes['value'].value}"
60
+ source = {:scanner => @name, :file => file, :line => line, :code => code}
61
+ sev = result.attributes['priority'].value
62
+ fprint = fingerprint("#{description}#{detail}#{source}")
63
+
64
+ report description, detail, source, sev, fprint
65
+ end
66
+ rescue Exception => e
67
+ Glue.warn e.message
68
+ Glue.warn e.backtrace
69
+ ensure
70
+ File.unlink @results_file
71
+ end
72
+ end
73
+
74
+ def supported?
75
+ unless find_executable0('mvn') and File.exist?("#{@trigger.path}/pom.xml")
76
+ Glue.notify "FindSecurityBugs support requires maven and pom.xml"
77
+ Glue.notify "Please install maven somewhere in your PATH and include a valid pom.xml in the project root"
78
+ return false
79
+ end
80
+
81
+ unless @tracker.options.has_key?(:findsecbugs_path) and File.exist?("#{@tracker.options[:findsecbugs_path]}/findsecbugs.sh")
82
+ Glue.notify "#{@tracker.options[:findsecbugs_path]}"
83
+ Glue.notify "Download and unpack the latest findsecbugs-cli release: https://github.com/find-sec-bugs/find-sec-bugs/releases"
84
+ return false
85
+ else
86
+ return true
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,58 @@
1
+ require 'glue/tasks/base_task'
2
+ require 'glue/util'
3
+ require 'find'
4
+ require 'pry'
5
+
6
+ class Glue::Npm < Glue::BaseTask
7
+
8
+ Glue::Tasks.add self
9
+ include Glue::Util
10
+
11
+ def initialize(trigger, tracker)
12
+ super(trigger, tracker)
13
+ @name = "NPM"
14
+ @description = "Node Package Manager"
15
+ @stage = :file
16
+ @labels << "file" << "javascript"
17
+ @results = []
18
+ end
19
+
20
+ def run
21
+ exclude_dirs = ['node_modules','bower_components']
22
+ exclude_dirs = exclude_dirs.concat(@tracker.options[:exclude_dirs]).uniq if @tracker.options[:exclude_dirs]
23
+ directories_with?('package.json', exclude_dirs).each do |dir|
24
+ Glue.notify "#{@name} scanning: #{dir}"
25
+ Dir.chdir(dir) do
26
+ if @tracker.options.has_key?(:npm_registry)
27
+ registry = "--registry #{@tracker.options[:npm_registry]}"
28
+ else
29
+ registry = nil
30
+ end
31
+ @command = "npm install -q --ignore-scripts #{registry}"
32
+ @results << runsystem(true, @command)
33
+ end
34
+ end
35
+ end
36
+
37
+ def analyze
38
+ begin
39
+ if @results.include? false
40
+ Glue.warn 'Error installing javascript dependencies with #{@command}'
41
+ end
42
+ rescue Exception => e
43
+ Glue.warn e.message
44
+ Glue.warn e.backtrace
45
+ end
46
+ end
47
+
48
+ def supported?
49
+ supported = find_executable0('npm')
50
+ unless supported
51
+ Glue.notify "Install npm: https://nodejs.org/en/download/"
52
+ return false
53
+ else
54
+ return true
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,65 @@
1
+ require 'glue/tasks/base_task'
2
+ require 'glue/util'
3
+
4
+ class Glue::NodeSecurityProject < Glue::BaseTask
5
+
6
+ Glue::Tasks.add self
7
+ include Glue::Util
8
+
9
+ def initialize(trigger, tracker)
10
+ super(trigger, tracker)
11
+ @name = "NodeSecurityProject"
12
+ @description = "Node Security Project"
13
+ @stage = :code
14
+ @labels << "code"
15
+ @results = []
16
+ end
17
+
18
+ def run
19
+ exclude_dirs = ['node_modules','bower_components']
20
+ exclude_dirs = exclude_dirs.concat(@tracker.options[:exclude_dirs]).uniq if @tracker.options[:exclude_dirs]
21
+ directories_with?('package.json', exclude_dirs).each do |dir|
22
+ Glue.notify "#{@name} scanning: #{dir}"
23
+ Dir.chdir(dir) do
24
+ res = runsystem(true, "nsp", "check", "--output", "json")
25
+ @results << JSON.parse(res)
26
+ end
27
+ end
28
+ end
29
+
30
+ def analyze
31
+ begin
32
+ @results.each do |dir_result|
33
+ # This block iterates through each package name found and selects the unique nsp advisories
34
+ # regardless of version, and builds a Glue finding hash for each unique package/advisory combo.
35
+ dir_result.uniq {|finding| finding['module']}.each do |package|
36
+ dir_result.select {|f| f['module'] == package['module']}.uniq {|m| m['advisory']}.each do |unique_finding|
37
+ description = "#{unique_finding['module']} - #{unique_finding['title']}"
38
+ detail = "Upgrade to versions: #{unique_finding['patched_versions']}\n#{unique_finding['advisory']}"
39
+ source = {
40
+ :scanner => 'NodeSecurityProject',
41
+ :file => "#{unique_finding['module']} - #{unique_finding['vulnerable_versions']}",
42
+ :line => nil,
43
+ :code => nil
44
+ }
45
+ report description, detail, source, 'medium', fingerprint("#{description}#{detail}#{source}")
46
+ end
47
+ end
48
+ end
49
+ rescue Exception => e
50
+ Glue.warn e.message
51
+ Glue.warn e.backtrace
52
+ end
53
+ end
54
+
55
+ def supported?
56
+ supported=runsystem(true, "nsp", "--version")
57
+ if supported =~ /command not found/
58
+ Glue.notify "Install nodesecurity: 'npm install -g nsp'"
59
+ return false
60
+ else
61
+ return true
62
+ end
63
+ end
64
+
65
+ end