pwn 0.5.442 → 0.5.443

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +3 -3
  4. data/lib/pwn/sast/amqp_connect_as_guest.rb +12 -89
  5. data/lib/pwn/sast/apache_file_system_util_api.rb +11 -91
  6. data/lib/pwn/sast/aws.rb +13 -93
  7. data/lib/pwn/sast/banned_function_calls_c.rb +138 -218
  8. data/lib/pwn/sast/base64.rb +12 -90
  9. data/lib/pwn/sast/beef_hook.rb +10 -90
  10. data/lib/pwn/sast/cmd_execution_java.rb +12 -92
  11. data/lib/pwn/sast/cmd_execution_python.rb +14 -94
  12. data/lib/pwn/sast/cmd_execution_ruby.rb +22 -102
  13. data/lib/pwn/sast/cmd_execution_scala.rb +12 -92
  14. data/lib/pwn/sast/csrf.rb +10 -90
  15. data/lib/pwn/sast/deserial_java.rb +17 -97
  16. data/lib/pwn/sast/emoticon.rb +17 -98
  17. data/lib/pwn/sast/eval.rb +10 -90
  18. data/lib/pwn/sast/factory.rb +12 -92
  19. data/lib/pwn/sast/http_authorization_header.rb +20 -100
  20. data/lib/pwn/sast/inner_html.rb +10 -90
  21. data/lib/pwn/sast/keystore.rb +10 -90
  22. data/lib/pwn/sast/local_storage.rb +11 -91
  23. data/lib/pwn/sast/location_hash.rb +10 -90
  24. data/lib/pwn/sast/log4j.rb +10 -90
  25. data/lib/pwn/sast/logger.rb +24 -104
  26. data/lib/pwn/sast/md5.rb +10 -90
  27. data/lib/pwn/sast/outer_html.rb +10 -90
  28. data/lib/pwn/sast/padding_oracle.rb +11 -91
  29. data/lib/pwn/sast/password.rb +15 -95
  30. data/lib/pwn/sast/php_input_mechanisms.rb +16 -96
  31. data/lib/pwn/sast/php_type_juggling.rb +14 -94
  32. data/lib/pwn/sast/pom_version.rb +1 -1
  33. data/lib/pwn/sast/port.rb +16 -96
  34. data/lib/pwn/sast/post_message.rb +10 -90
  35. data/lib/pwn/sast/private_key.rb +10 -90
  36. data/lib/pwn/sast/redirect.rb +13 -93
  37. data/lib/pwn/sast/redos.rb +16 -96
  38. data/lib/pwn/sast/shell.rb +18 -98
  39. data/lib/pwn/sast/signature.rb +10 -90
  40. data/lib/pwn/sast/sql.rb +19 -93
  41. data/lib/pwn/sast/ssl.rb +14 -94
  42. data/lib/pwn/sast/sudo.rb +10 -90
  43. data/lib/pwn/sast/task_tag.rb +23 -103
  44. data/lib/pwn/sast/test_case_engine.rb +147 -0
  45. data/lib/pwn/sast/throw_errors.rb +14 -94
  46. data/lib/pwn/sast/token.rb +12 -92
  47. data/lib/pwn/sast/type_script_type_juggling.rb +14 -94
  48. data/lib/pwn/sast/version.rb +12 -92
  49. data/lib/pwn/sast/window_location_hash.rb +10 -90
  50. data/lib/pwn/sast.rb +4 -0
  51. data/lib/pwn/version.rb +1 -1
  52. data/lib/pwn.rb +0 -2
  53. data/spec/lib/pwn/sast/test_case_engine_spec.rb +20 -0
  54. data/third_party/pwn_rdoc.jsonl +1 -1
  55. metadata +5 -3
data/lib/pwn/sast/ssl.rb CHANGED
@@ -19,102 +19,22 @@ module PWN
19
19
  public_class_method def self.scan(opts = {})
20
20
  dir_path = opts[:dir_path]
21
21
  git_repo_root_uri = opts[:git_repo_root_uri].to_s.scrub
22
- result_arr = []
23
- ai_introspection = PWN::Env[:ai][:introspection]
24
- logger_results = "AI Introspection => #{ai_introspection} => "
25
22
 
26
- PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
27
- if File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/ && entry !~ /test/i
28
- line_no_and_contents_arr = []
29
- entry_beautified = false
30
-
31
- if File.extname(entry) == '.js' && (`wc -l #{entry}`.split.first.to_i < 20 || entry.include?('.min.js') || entry.include?('-all.js'))
32
- js_beautify = `js-beautify #{entry} > #{entry}.JS-BEAUTIFIED 2> /dev/null`.to_s.scrub
33
- entry = "#{entry}.JS-BEAUTIFIED"
34
- entry_beautified = true
35
- end
36
-
37
- test_case_filter = "
38
- grep -Fin \
39
- -e 'ssl' \
40
- -e 'tls' \
41
- -e 'trustAll' \
42
- -e 'trustmanager' \
43
- -e 'ssl_version' #{entry} 2> /dev/null
44
- "
45
-
46
- str = `#{test_case_filter}`.to_s.scrub
47
-
48
- if str.to_s.empty?
49
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
50
- logger_results = "#{logger_results}~" # Catching bugs is good :)
51
- else
52
- str = "1:Result larger than 64KB -> Size: #{str.to_s.length}. Please click the \"Path\" link for more details." if str.to_s.length >= 64_000
53
-
54
- hash_line = {
55
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
56
- security_references: security_references,
57
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
58
- line_no_and_contents: '',
59
- raw_content: str,
60
- test_case_filter: test_case_filter
61
- }
62
-
63
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
64
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
65
- line_no_count = line_contents_split.length # This should always be an even number
66
- current_count = 0
67
- while line_no_count > current_count
68
- line_no = line_contents_split[current_count]
69
- contents = line_contents_split[current_count + 1]
70
- if Dir.exist?('.git')
71
- repo_root = '.'
72
-
73
- author = PWN::Plugins::Git.get_author(
74
- repo_root: repo_root,
75
- from_line: line_no,
76
- to_line: line_no,
77
- target_file: entry,
78
- entry_beautified: entry_beautified
79
- )
80
- end
81
- author ||= 'N/A'
82
-
83
- ai_analysis = nil
84
- if ai_introspection
85
- request = {
86
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
87
- line_no: line_no,
88
- source_code_snippet: contents
89
- }.to_json
90
- response = PWN::AI::Introspection.reflect(request: request)
91
- if response.is_a?(Hash)
92
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
93
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
94
- end
95
- end
96
-
97
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
98
- line_no: line_no,
99
- contents: contents,
100
- author: author,
101
- ai_analysis: ai_analysis
102
- )
23
+ test_case_filter = "
24
+ grep -Fin \
25
+ -e 'ssl' \
26
+ -e 'tls' \
27
+ -e 'trustAll' \
28
+ -e 'trustmanager' \
29
+ -e 'ssl_version' {PWN_SAST_SRC_TARGET} 2> /dev/null
30
+ "
103
31
 
104
- current_count += 2
105
- end
106
- result_arr.push(hash_line)
107
- logger_results = "#{logger_results}x" # Seeing progress is good :)
108
- end
109
- end
110
- end
111
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
112
- if logger_results.empty?
113
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
114
- else
115
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
116
- end
117
- result_arr
32
+ PWN::SAST::TestCaseEngine.execute(
33
+ test_case_filter: test_case_filter,
34
+ security_references: security_references,
35
+ dir_path: dir_path,
36
+ git_repo_root_uri: git_repo_root_uri
37
+ )
118
38
  rescue StandardError => e
119
39
  raise e
120
40
  end
data/lib/pwn/sast/sudo.rb CHANGED
@@ -19,98 +19,18 @@ module PWN
19
19
  public_class_method def self.scan(opts = {})
20
20
  dir_path = opts[:dir_path]
21
21
  git_repo_root_uri = opts[:git_repo_root_uri].to_s.scrub
22
- result_arr = []
23
- ai_introspection = PWN::Env[:ai][:introspection]
24
- logger_results = "AI Introspection => #{ai_introspection} => "
25
22
 
26
- PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
27
- if File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/ && entry !~ /test/i
28
- line_no_and_contents_arr = []
29
- entry_beautified = false
30
-
31
- if File.extname(entry) == '.js' && (`wc -l #{entry}`.split.first.to_i < 20 || entry.include?('.min.js') || entry.include?('-all.js'))
32
- js_beautify = `js-beautify #{entry} > #{entry}.JS-BEAUTIFIED 2> /dev/null`.to_s.scrub
33
- entry = "#{entry}.JS-BEAUTIFIED"
34
- entry_beautified = true
35
- end
36
-
37
- test_case_filter = "
38
- grep -niE \
39
- -e 'sudo' #{entry} 2> /dev/null
40
- "
41
-
42
- str = `#{test_case_filter}`.to_s.scrub
43
-
44
- if str.to_s.empty?
45
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
46
- logger_results = "#{logger_results}~" # Catching bugs is good :)
47
- else
48
- str = "1:Result larger than 64KB -> Size: #{str.to_s.length}. Please click the \"Path\" link for more details." if str.to_s.length >= 64_000
49
-
50
- hash_line = {
51
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
52
- security_references: security_references,
53
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
54
- line_no_and_contents: '',
55
- raw_content: str,
56
- test_case_filter: test_case_filter
57
- }
58
-
59
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
60
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
61
- line_no_count = line_contents_split.length # This should always be an even number
62
- current_count = 0
63
- while line_no_count > current_count
64
- line_no = line_contents_split[current_count]
65
- contents = line_contents_split[current_count + 1]
66
- if Dir.exist?('.git')
67
- repo_root = '.'
68
-
69
- author = PWN::Plugins::Git.get_author(
70
- repo_root: repo_root,
71
- from_line: line_no,
72
- to_line: line_no,
73
- target_file: entry,
74
- entry_beautified: entry_beautified
75
- )
76
- end
77
- author ||= 'N/A'
78
-
79
- ai_analysis = nil
80
- if ai_introspection
81
- request = {
82
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
83
- line_no: line_no,
84
- source_code_snippet: contents
85
- }.to_json
86
- response = PWN::AI::Introspection.reflect(request: request)
87
- if response.is_a?(Hash)
88
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
89
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
90
- end
91
- end
92
-
93
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
94
- line_no: line_no,
95
- contents: contents,
96
- author: author,
97
- ai_analysis: ai_analysis
98
- )
23
+ test_case_filter = "
24
+ grep -niE \
25
+ -e 'sudo' {PWN_SAST_SRC_TARGET} 2> /dev/null
26
+ "
99
27
 
100
- current_count += 2
101
- end
102
- result_arr.push(hash_line)
103
- logger_results = "#{logger_results}x" # Seeing progress is good :)
104
- end
105
- end
106
- end
107
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
108
- if logger_results.empty?
109
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
110
- else
111
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
112
- end
113
- result_arr
28
+ PWN::SAST::TestCaseEngine.execute(
29
+ test_case_filter: test_case_filter,
30
+ security_references: security_references,
31
+ dir_path: dir_path,
32
+ git_repo_root_uri: git_repo_root_uri
33
+ )
114
34
  rescue StandardError => e
115
35
  raise e
116
36
  end
@@ -20,111 +20,31 @@ module PWN
20
20
  public_class_method def self.scan(opts = {})
21
21
  dir_path = opts[:dir_path]
22
22
  git_repo_root_uri = opts[:git_repo_root_uri].to_s.scrub
23
- result_arr = []
24
- ai_introspection = PWN::Env[:ai][:introspection]
25
- logger_results = "AI Introspection => #{ai_introspection} => "
26
23
 
27
- PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
28
- if File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/ && entry !~ /test/i
29
- line_no_and_contents_arr = []
30
- entry_beautified = false
31
-
32
- if File.extname(entry) == '.js' && (`wc -l #{entry}`.split.first.to_i < 20 || entry.include?('.min.js') || entry.include?('-all.js'))
33
- js_beautify = `js-beautify #{entry} > #{entry}.JS-BEAUTIFIED 2> /dev/null`.to_s.scrub
34
- entry = "#{entry}.JS-BEAUTIFIED"
35
- entry_beautified = true
36
- end
37
-
38
- test_case_filter = "
39
- grep -Fin \
40
- -e '//' \
41
- -e '<!--' \
42
- -e '/**' \
43
- -e '#' #{entry} 2> /dev/null | \
44
- grep -i \
45
- -e SECURITY \
46
- -e TODO \
47
- -e FIXME \
48
- -e XXX \
49
- -e CHECKME \
50
- -e DOCME \
51
- -e TESTME \
52
- -e PENDING \
53
- -e DISCUSS | grep -v '://'
54
- "
55
-
56
- str = `#{test_case_filter}`.to_s.scrub
57
-
58
- if str.to_s.empty?
59
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
60
- logger_results = "#{logger_results}~" # Catching bugs is good :)
61
- else
62
- str = "1:Result larger than 64KB -> Size: #{str.to_s.length}. Please click the \"Path\" link for more details." if str.to_s.length >= 64_000
63
-
64
- hash_line = {
65
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
66
- security_references: security_references,
67
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
68
- line_no_and_contents: '',
69
- raw_content: str,
70
- test_case_filter: test_case_filter
71
- }
72
-
73
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
74
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
75
- line_no_count = line_contents_split.length # This should always be an even number
76
- current_count = 0
77
- while line_no_count > current_count
78
- line_no = line_contents_split[current_count]
79
- contents = line_contents_split[current_count + 1]
80
- if Dir.exist?('.git')
81
- repo_root = '.'
82
-
83
- author = PWN::Plugins::Git.get_author(
84
- repo_root: repo_root,
85
- from_line: line_no,
86
- to_line: line_no,
87
- target_file: entry,
88
- entry_beautified: entry_beautified
89
- )
90
- end
91
- author ||= 'N/A'
92
-
93
- ai_analysis = nil
94
- if ai_introspection
95
- request = {
96
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
97
- line_no: line_no,
98
- source_code_snippet: contents
99
- }.to_json
100
- response = PWN::AI::Introspection.reflect(request: request)
101
- if response.is_a?(Hash)
102
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
103
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
104
- end
105
- end
106
-
107
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
108
- line_no: line_no,
109
- contents: contents,
110
- author: author,
111
- ai_analysis: ai_analysis
112
- )
24
+ test_case_filter = "
25
+ grep -Fin \
26
+ -e '//' \
27
+ -e '<!--' \
28
+ -e '/**' \
29
+ -e '#' {PWN_SAST_SRC_TARGET} 2> /dev/null | \
30
+ grep -i \
31
+ -e SECURITY \
32
+ -e TODO \
33
+ -e FIXME \
34
+ -e XXX \
35
+ -e CHECKME \
36
+ -e DOCME \
37
+ -e TESTME \
38
+ -e PENDING \
39
+ -e DISCUSS | grep -v '://'
40
+ "
113
41
 
114
- current_count += 2
115
- end
116
- result_arr.push(hash_line)
117
- logger_results = "#{logger_results}x" # Seeing progress is good :)
118
- end
119
- end
120
- end
121
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
122
- if logger_results.empty?
123
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
124
- else
125
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
126
- end
127
- result_arr
42
+ PWN::SAST::TestCaseEngine.execute(
43
+ test_case_filter: test_case_filter,
44
+ security_references: security_references,
45
+ dir_path: dir_path,
46
+ git_repo_root_uri: git_repo_root_uri
47
+ )
128
48
  rescue StandardError => e
129
49
  raise e
130
50
  end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'json'
4
+ require 'socket'
5
+
6
+ module PWN
7
+ module SAST
8
+ # SAST Module used to execute PWN::SAST::* modules
9
+ module TestCaseEngine
10
+ @@logger = PWN::Plugins::PWNLogger.create
11
+
12
+ # Supported Method Parameters::
13
+ # PWN::SAST::TestCaseEngine.execute(
14
+ # test_case_filter: 'required - grep command to filter results',
15
+ # security_references: 'required - Hash with keys :sast_module, :section, :nist_800_53_uri, :cwe_id, :cwe_uri',
16
+ # dir_path: 'optional - path to dir defaults to .'
17
+ # git_repo_root_uri: 'optional - http uri of git repo scanned'
18
+ # )
19
+
20
+ public_class_method def self.execute(opts = {})
21
+ test_case_filter = opts[:test_case_filter]
22
+ raise 'ERROR: test_case_filter must be nil' if test_case_filter.nil?
23
+
24
+ security_references = opts[:security_references]
25
+ raise 'ERROR: security_references must be a Hash' unless security_references.is_a?(Hash)
26
+
27
+ dir_path = opts[:dir_path] ||= '.'
28
+ git_repo_root_uri = opts[:git_repo_root_uri].to_s.scrub
29
+
30
+ result_arr = []
31
+ ai_introspection = PWN::Env[:ai][:introspection]
32
+ logger_results = "AI Introspection => #{ai_introspection} => "
33
+
34
+ PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
35
+ if File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/ && entry !~ /test/i
36
+ line_no_and_contents_arr = []
37
+ entry_beautified = false
38
+
39
+ if File.extname(entry) == '.js' && (`wc -l #{entry}`.split.first.to_i < 20 || entry.include?('.min.js') || entry.include?('-all.js'))
40
+ js_beautify = `js-beautify #{entry} > #{entry}.JS-BEAUTIFIED 2> /dev/null`.to_s.scrub
41
+ entry = "#{entry}.JS-BEAUTIFIED"
42
+ entry_beautified = true
43
+ end
44
+
45
+ # Replace tokenized test_case_filter, PWN_ENTRY with actual entry
46
+ this_test_case_filter = test_case_filter.to_s.gsub('{PWN_SAST_SRC_TARGET}', entry.to_s.scrub).to_s.scrub
47
+ str = `#{this_test_case_filter}`.to_s.scrub
48
+
49
+ if str.to_s.empty?
50
+ # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
51
+ logger_results = "#{logger_results}~" # Catching bugs is good :)
52
+ else
53
+ str = "1:Result larger than 64KB -> Size: #{str.to_s.length}. Please click the \"Path\" link for more details." if str.to_s.length >= 64_000
54
+
55
+ hash_line = {
56
+ timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
57
+ security_references: security_references,
58
+ filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
59
+ line_no_and_contents: '',
60
+ raw_content: str,
61
+ test_case_filter: test_case_filter
62
+ }
63
+
64
+ # COMMMENT: Must be a better way to implement this (regex is kinda funky)
65
+ line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
66
+ line_no_count = line_contents_split.length # This should always be an even number
67
+ current_count = 0
68
+ while line_no_count > current_count
69
+ line_no = line_contents_split[current_count]
70
+ contents = line_contents_split[current_count + 1]
71
+ if Dir.exist?('.git')
72
+ repo_root = '.'
73
+
74
+ author = PWN::Plugins::Git.get_author(
75
+ repo_root: repo_root,
76
+ from_line: line_no,
77
+ to_line: line_no,
78
+ target_file: entry,
79
+ entry_beautified: entry_beautified
80
+ )
81
+ end
82
+ author ||= 'N/A'
83
+
84
+ ai_analysis = nil
85
+ if ai_introspection
86
+ request = {
87
+ scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
88
+ line_no: line_no,
89
+ source_code_snippet: contents
90
+ }.to_json
91
+ response = PWN::AI::Introspection.reflect(request: request)
92
+ if response.is_a?(Hash)
93
+ ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
94
+ ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
95
+ end
96
+ end
97
+
98
+ hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
99
+ line_no: line_no,
100
+ contents: contents,
101
+ author: author,
102
+ ai_analysis: ai_analysis
103
+ )
104
+
105
+ current_count += 2
106
+ end
107
+ result_arr.push(hash_line)
108
+ logger_results = "#{logger_results}x" # Seeing progress is good :)
109
+ end
110
+ end
111
+ end
112
+ logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
113
+ if logger_results.empty?
114
+ @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
115
+ else
116
+ @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
117
+ end
118
+ result_arr
119
+ rescue StandardError => e
120
+ raise e
121
+ end
122
+
123
+ # Author(s):: 0day Inc. <support@0dayinc.com>
124
+
125
+ public_class_method def self.authors
126
+ "AUTHOR(S):
127
+ 0day Inc. <support@0dayinc.com>
128
+ "
129
+ end
130
+
131
+ # Display Usage for this Module
132
+
133
+ public_class_method def self.help
134
+ puts "USAGE:
135
+ sast_arr = #{self}.execute(
136
+ test_case_filter: 'required grep command to filter results',
137
+ security_references: 'required Hash with keys :sast_module, :section, :nist_800_53_uri, :cwe_id, :cwe_uri',
138
+ dir_path: 'optional path to dir defaults to .',
139
+ git_repo_root_uri: 'optional http uri of git repo scanned'
140
+ )
141
+
142
+ #{self}.authors
143
+ "
144
+ end
145
+ end
146
+ end
147
+ end
@@ -19,101 +19,21 @@ module PWN
19
19
  public_class_method def self.scan(opts = {})
20
20
  dir_path = opts[:dir_path]
21
21
  git_repo_root_uri = opts[:git_repo_root_uri].to_s.scrub
22
- result_arr = []
23
- ai_introspection = PWN::Env[:ai][:introspection]
24
- logger_results = "AI Introspection => #{ai_introspection} => "
25
22
 
26
- PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
27
- if (File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/) && entry !~ /test/i
28
- line_no_and_contents_arr = []
29
- entry_beautified = false
30
-
31
- if File.extname(entry) == '.js' && (`wc -l #{entry}`.split.first.to_i < 20 || entry.include?('.min.js') || entry.include?('-all.js'))
32
- js_beautify = `js-beautify #{entry} > #{entry}.JS-BEAUTIFIED 2> /dev/null`.to_s.scrub
33
- entry = "#{entry}.JS-BEAUTIFIED"
34
- entry_beautified = true
35
- end
36
-
37
- test_case_filter = %(
38
- grep -in \
39
- -e panic \
40
- -e raise \
41
- -e throw #{entry} 2> /dev/null | \
42
- grep '"'
43
- )
44
-
45
- str = `#{test_case_filter}`.to_s.scrub
46
-
47
- if str.to_s.empty?
48
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
49
- logger_results = "#{logger_results}~" # Catching bugs is good :)
50
- else
51
- str = "1:Result larger than 64KB -> Size: #{str.to_s.length}. Please click the \"Path\" link for more details." if str.to_s.length >= 64_000
52
-
53
- hash_line = {
54
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
55
- security_references: security_references,
56
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
57
- line_no_and_contents: '',
58
- raw_content: str,
59
- test_case_filter: test_case_filter
60
- }
61
-
62
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
63
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
64
- line_no_count = line_contents_split.length # This should always be an even number
65
- current_count = 0
66
- while line_no_count > current_count
67
- line_no = line_contents_split[current_count]
68
- contents = line_contents_split[current_count + 1]
69
- if Dir.exist?('.git')
70
- repo_root = '.'
71
-
72
- author = PWN::Plugins::Git.get_author(
73
- repo_root: repo_root,
74
- from_line: line_no,
75
- to_line: line_no,
76
- target_file: entry,
77
- entry_beautified: entry_beautified
78
- )
79
- end
80
- author ||= 'N/A'
81
-
82
- ai_analysis = nil
83
- if ai_introspection
84
- request = {
85
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
86
- line_no: line_no,
87
- source_code_snippet: contents
88
- }.to_json
89
- response = PWN::AI::Introspection.reflect(request: request)
90
- if response.is_a?(Hash)
91
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
92
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
93
- end
94
- end
95
-
96
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
97
- line_no: line_no,
98
- contents: contents,
99
- author: author,
100
- ai_analysis: ai_analysis
101
- )
102
-
103
- current_count += 2
104
- end
105
- result_arr.push(hash_line)
106
- logger_results = "#{logger_results}x" # Seeing progress is good :)
107
- end
108
- end
109
- end
110
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
111
- if logger_results.empty?
112
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
113
- else
114
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
115
- end
116
- result_arr
23
+ test_case_filter = %(
24
+ grep -in \
25
+ -e panic \
26
+ -e raise \
27
+ -e throw {PWN_SAST_SRC_TARGET} 2> /dev/null | \
28
+ grep '"'
29
+ )
30
+
31
+ PWN::SAST::TestCaseEngine.execute(
32
+ test_case_filter: test_case_filter,
33
+ security_references: security_references,
34
+ dir_path: dir_path,
35
+ git_repo_root_uri: git_repo_root_uri
36
+ )
117
37
  rescue StandardError => e
118
38
  raise e
119
39
  end