pwn 0.5.441 → 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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +3 -3
  4. data/lib/pwn/plugins/repl.rb +3 -5
  5. data/lib/pwn/sast/amqp_connect_as_guest.rb +12 -89
  6. data/lib/pwn/sast/apache_file_system_util_api.rb +11 -91
  7. data/lib/pwn/sast/aws.rb +13 -93
  8. data/lib/pwn/sast/banned_function_calls_c.rb +138 -218
  9. data/lib/pwn/sast/base64.rb +12 -90
  10. data/lib/pwn/sast/beef_hook.rb +10 -90
  11. data/lib/pwn/sast/cmd_execution_java.rb +12 -92
  12. data/lib/pwn/sast/cmd_execution_python.rb +14 -94
  13. data/lib/pwn/sast/cmd_execution_ruby.rb +22 -102
  14. data/lib/pwn/sast/cmd_execution_scala.rb +12 -92
  15. data/lib/pwn/sast/csrf.rb +10 -90
  16. data/lib/pwn/sast/deserial_java.rb +17 -97
  17. data/lib/pwn/sast/emoticon.rb +17 -98
  18. data/lib/pwn/sast/eval.rb +10 -90
  19. data/lib/pwn/sast/factory.rb +12 -92
  20. data/lib/pwn/sast/http_authorization_header.rb +20 -100
  21. data/lib/pwn/sast/inner_html.rb +10 -90
  22. data/lib/pwn/sast/keystore.rb +10 -90
  23. data/lib/pwn/sast/local_storage.rb +11 -91
  24. data/lib/pwn/sast/location_hash.rb +10 -90
  25. data/lib/pwn/sast/log4j.rb +10 -90
  26. data/lib/pwn/sast/logger.rb +24 -104
  27. data/lib/pwn/sast/md5.rb +10 -90
  28. data/lib/pwn/sast/outer_html.rb +10 -90
  29. data/lib/pwn/sast/padding_oracle.rb +11 -91
  30. data/lib/pwn/sast/password.rb +15 -95
  31. data/lib/pwn/sast/php_input_mechanisms.rb +16 -96
  32. data/lib/pwn/sast/php_type_juggling.rb +14 -94
  33. data/lib/pwn/sast/pom_version.rb +1 -1
  34. data/lib/pwn/sast/port.rb +16 -96
  35. data/lib/pwn/sast/post_message.rb +10 -90
  36. data/lib/pwn/sast/private_key.rb +10 -90
  37. data/lib/pwn/sast/redirect.rb +13 -93
  38. data/lib/pwn/sast/redos.rb +16 -96
  39. data/lib/pwn/sast/shell.rb +18 -98
  40. data/lib/pwn/sast/signature.rb +10 -90
  41. data/lib/pwn/sast/sql.rb +19 -93
  42. data/lib/pwn/sast/ssl.rb +14 -94
  43. data/lib/pwn/sast/sudo.rb +10 -90
  44. data/lib/pwn/sast/task_tag.rb +23 -103
  45. data/lib/pwn/sast/test_case_engine.rb +147 -0
  46. data/lib/pwn/sast/throw_errors.rb +14 -94
  47. data/lib/pwn/sast/token.rb +12 -92
  48. data/lib/pwn/sast/type_script_type_juggling.rb +14 -94
  49. data/lib/pwn/sast/version.rb +12 -92
  50. data/lib/pwn/sast/window_location_hash.rb +10 -90
  51. data/lib/pwn/sast.rb +4 -0
  52. data/lib/pwn/version.rb +1 -1
  53. data/lib/pwn.rb +0 -2
  54. data/spec/lib/pwn/sast/test_case_engine_spec.rb +20 -0
  55. data/third_party/pwn_rdoc.jsonl +1 -1
  56. metadata +5 -3
@@ -21,105 +21,25 @@ module PWN
21
21
  public_class_method def self.scan(opts = {})
22
22
  dir_path = opts[:dir_path]
23
23
  git_repo_root_uri = opts[:git_repo_root_uri].to_s.scrub
24
- result_arr = []
25
- ai_introspection = PWN::Env[:ai][:introspection]
26
- logger_results = "AI Introspection => #{ai_introspection} => "
27
24
 
28
- PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
29
- if (File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/) && (File.extname(entry) == '.scala' || File.extname(entry) == '.java') && entry !~ /test/i
30
- line_no_and_contents_arr = []
31
- entry_beautified = false
32
-
33
- if File.extname(entry) == '.js' && (`wc -l #{entry}`.split.first.to_i < 20 || entry.include?('.min.js') || entry.include?('-all.js'))
34
- js_beautify = `js-beautify #{entry} > #{entry}.JS-BEAUTIFIED 2> /dev/null`.to_s.scrub
35
- entry = "#{entry}.JS-BEAUTIFIED"
36
- entry_beautified = true
37
- end
38
-
39
- test_case_filter = "
40
- grep -in \
41
- -e readObject \
42
- -e XMLdecoder \
43
- -e fromXML \
44
- -e readObjectNodData \
45
- -e readResolve \
46
- -e readExternal \
47
- -e readUnshared \
48
- -e Serializable #{entry} 2> /dev/null
49
- "
50
-
51
- str = `#{test_case_filter}`.to_s.scrub
52
-
53
- if str.to_s.empty?
54
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
55
- logger_results = "#{logger_results}~" # Catching bugs is good :)
56
- else
57
- 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
58
-
59
- hash_line = {
60
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
61
- security_references: security_references,
62
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
63
- line_no_and_contents: '',
64
- raw_content: str,
65
- test_case_filter: test_case_filter
66
- }
67
-
68
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
69
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
70
- line_no_count = line_contents_split.length # This should always be an even number
71
- current_count = 0
72
- while line_no_count > current_count
73
- line_no = line_contents_split[current_count]
74
- contents = line_contents_split[current_count + 1]
75
- if Dir.exist?('.git')
76
- repo_root = '.'
77
-
78
- author = PWN::Plugins::Git.get_author(
79
- repo_root: repo_root,
80
- from_line: line_no,
81
- to_line: line_no,
82
- target_file: entry,
83
- entry_beautified: entry_beautified
84
- )
85
- end
86
- author ||= 'N/A'
87
-
88
- ai_analysis = nil
89
- if ai_introspection
90
- request = {
91
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
92
- line_no: line_no,
93
- source_code_snippet: contents
94
- }.to_json
95
- response = PWN::AI::Introspection.reflect(request: request)
96
- if response.is_a?(Hash)
97
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
98
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
99
- end
100
- end
101
-
102
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
103
- line_no: line_no,
104
- contents: contents,
105
- author: author,
106
- ai_analysis: ai_analysis
107
- )
25
+ test_case_filter = "
26
+ grep -in \
27
+ -e readObject \
28
+ -e XMLdecoder \
29
+ -e fromXML \
30
+ -e readObjectNodData \
31
+ -e readResolve \
32
+ -e readExternal \
33
+ -e readUnshared \
34
+ -e Serializable {PWN_SAST_SRC_TARGET} 2> /dev/null
35
+ "
108
36
 
109
- current_count += 2
110
- end
111
- result_arr.push(hash_line)
112
- logger_results = "#{logger_results}x" # Seeing progress is good :)
113
- end
114
- end
115
- end
116
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
117
- if logger_results.empty?
118
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
119
- else
120
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
121
- end
122
- result_arr
37
+ PWN::SAST::TestCaseEngine.execute(
38
+ test_case_filter: test_case_filter,
39
+ security_references: security_references,
40
+ dir_path: dir_path,
41
+ git_repo_root_uri: git_repo_root_uri
42
+ )
123
43
  end
124
44
 
125
45
  # Used primarily to map NIST 800-53 Revision 4 Security Controls
@@ -19,106 +19,25 @@ 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 -Fn \
39
- -e ':-)' \
40
- -e ';-)' \
41
- -e ':-P' \
42
- -e ':-D' \
43
- -e '\_o_/' \
44
- -e '\_O_/' \
45
- -e '\_0_/' \
46
- -e ':-O' #{entry} 2> /dev/null
47
- "
48
-
49
- str = `#{test_case_filter}`.to_s.scrub
50
-
51
- if str.to_s.empty?
52
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
53
- logger_results = "#{logger_results}~" # Catching bugs is good :)
54
- else
55
- 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
56
-
57
- hash_line = {
58
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
59
- security_references: security_references,
60
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
61
- line_no_and_contents: '',
62
- raw_content: str,
63
- test_case_filter: test_case_filter
64
- }
65
-
66
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
67
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
68
- line_no_count = line_contents_split.length # This should always be an even number
69
- current_count = 0
70
- while line_no_count > current_count
71
- line_no = line_contents_split[current_count]
72
- contents = line_contents_split[current_count + 1]
73
- if Dir.exist?('.git')
74
- repo_root = '.'
75
-
76
- author = PWN::Plugins::Git.get_author(
77
- repo_root: repo_root,
78
- from_line: line_no,
79
- to_line: line_no,
80
- target_file: entry,
81
- entry_beautified: entry_beautified
82
- )
83
- end
84
- author ||= 'N/A'
85
-
86
- ai_analysis = nil
87
- if ai_introspection
88
- request = {
89
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
90
- line_no: line_no,
91
- source_code_snippet: contents
92
- }.to_json
93
- response = PWN::AI::Introspection.reflect(request: request)
94
- if response.is_a?(Hash)
95
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
96
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
97
- end
98
- end
99
-
100
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
101
- line_no: line_no,
102
- contents: contents,
103
- author: author,
104
- ai_analysis: ai_analysis
105
- )
106
-
107
- current_count += 2
108
- end
109
- result_arr.push(hash_line)
110
- logger_results = "#{logger_results}x" # Seeing progress is good :)
111
- end
112
- end
113
- end
23
+ test_case_filter = "
24
+ grep -Fn \
25
+ -e ':-)' \
26
+ -e ';-)' \
27
+ -e ':-P' \
28
+ -e ':-D' \
29
+ -e '\_o_/' \
30
+ -e '\_O_/' \
31
+ -e '\_0_/' \
32
+ -e ':-O' {PWN_SAST_SRC_TARGET} 2> /dev/null
33
+ "
114
34
 
115
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
116
- if logger_results.empty?
117
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
118
- else
119
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
120
- end
121
- result_arr
35
+ PWN::SAST::TestCaseEngine.execute(
36
+ test_case_filter: test_case_filter,
37
+ security_references: security_references,
38
+ dir_path: dir_path,
39
+ git_repo_root_uri: git_repo_root_uri
40
+ )
122
41
  rescue StandardError => e
123
42
  raise e
124
43
  end
data/lib/pwn/sast/eval.rb CHANGED
@@ -20,98 +20,18 @@ 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 -n \
40
- -e 'eval(' #{entry} 2> /dev/null
41
- "
42
-
43
- str = `#{test_case_filter}`.to_s.scrub
44
-
45
- if str.to_s.empty?
46
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
47
- logger_results = "#{logger_results}~" # Catching bugs is good :)
48
- else
49
- 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
50
-
51
- hash_line = {
52
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
53
- security_references: security_references,
54
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
55
- line_no_and_contents: '',
56
- raw_content: str,
57
- test_case_filter: test_case_filter
58
- }
59
-
60
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
61
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
62
- line_no_count = line_contents_split.length # This should always be an even number
63
- current_count = 0
64
- while line_no_count > current_count
65
- line_no = line_contents_split[current_count]
66
- contents = line_contents_split[current_count + 1]
67
- if Dir.exist?('.git')
68
- repo_root = '.'
69
-
70
- author = PWN::Plugins::Git.get_author(
71
- repo_root: repo_root,
72
- from_line: line_no,
73
- to_line: line_no,
74
- target_file: entry,
75
- entry_beautified: entry_beautified
76
- )
77
- end
78
- author ||= 'N/A'
79
-
80
- ai_analysis = nil
81
- if ai_introspection
82
- request = {
83
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
84
- line_no: line_no,
85
- source_code_snippet: contents
86
- }.to_json
87
- response = PWN::AI::Introspection.reflect(request: request)
88
- if response.is_a?(Hash)
89
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
90
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
91
- end
92
- end
93
-
94
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
95
- line_no: line_no,
96
- contents: contents,
97
- author: author,
98
- ai_analysis: ai_analysis
99
- )
24
+ test_case_filter = "
25
+ grep -n \
26
+ -e 'eval(' {PWN_SAST_SRC_TARGET} 2> /dev/null
27
+ "
100
28
 
101
- current_count += 2
102
- end
103
- result_arr.push(hash_line)
104
- logger_results = "#{logger_results}x" # Seeing progress is good :)
105
- end
106
- end
107
- end
108
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
109
- if logger_results.empty?
110
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
111
- else
112
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
113
- end
114
- result_arr
29
+ PWN::SAST::TestCaseEngine.execute(
30
+ test_case_filter: test_case_filter,
31
+ security_references: security_references,
32
+ dir_path: dir_path,
33
+ git_repo_root_uri: git_repo_root_uri
34
+ )
115
35
  rescue StandardError => e
116
36
  raise e
117
37
  end
@@ -21,100 +21,20 @@ module PWN
21
21
  public_class_method def self.scan(opts = {})
22
22
  dir_path = opts[:dir_path]
23
23
  git_repo_root_uri = opts[:git_repo_root_uri].to_s.scrub
24
- result_arr = []
25
- ai_introspection = PWN::Env[:ai][:introspection]
26
- logger_results = "AI Introspection => #{ai_introspection} => "
27
24
 
28
- PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
29
- if (File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/) && (File.extname(entry) == '.scala' || File.extname(entry) == '.java') && entry !~ /test/i
30
- line_no_and_contents_arr = []
31
- entry_beautified = false
32
-
33
- if File.extname(entry) == '.js' && (`wc -l #{entry}`.split.first.to_i < 20 || entry.include?('.min.js') || entry.include?('-all.js'))
34
- js_beautify = `js-beautify #{entry} > #{entry}.JS-BEAUTIFIED 2> /dev/null`.to_s.scrub
35
- entry = "#{entry}.JS-BEAUTIFIED"
36
- entry_beautified = true
37
- end
38
-
39
- test_case_filter = "
40
- grep -in \
41
- -e DocumentBuilderFactory \
42
- -e XMLInputFactory \
43
- -e SAXParserFactory #{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
- )
25
+ test_case_filter = "
26
+ grep -in \
27
+ -e DocumentBuilderFactory \
28
+ -e XMLInputFactory \
29
+ -e SAXParserFactory {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
  end
119
39
 
120
40
  # Used primarily to map NIST 800-53 Revision 4 Security Controls
@@ -19,107 +19,27 @@ 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 -Ein \
39
- -e "Authorization:(\\sBasic|Basic)" \
40
- -e "Authorization:(\\sBearer|Bearer)" \
41
- -e "Authorization:(\\sDigest|Digest)" \
42
- -e "Authorization:(\\sHOBA|HOBA)" \
43
- -e "Authorization:(\\sMutual|Mutual)" \
44
- -e "Authorization:(\\sNegotiate|Negotiate)" \
45
- -e "Authorization:(\\sVapid|Vapid)" \
46
- -e "Authorization:(\\sSCRAM|SCRAM)" \
47
- -e "Authorization:(\\sAWS|AWS)" \
48
- -e "authorization(\\s=|=)" #{entry} 2> /dev/null
49
- )
50
-
51
- str = `#{test_case_filter}`.to_s.scrub
52
-
53
- if str.to_s.empty?
54
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
55
- logger_results = "#{logger_results}~" # Catching bugs is good :)
56
- else
57
- 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
58
-
59
- hash_line = {
60
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
61
- security_references: security_references,
62
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
63
- line_no_and_contents: '',
64
- raw_content: str,
65
- test_case_filter: test_case_filter
66
- }
67
-
68
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
69
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
70
- line_no_count = line_contents_split.length # This should always be an even number
71
- current_count = 0
72
- while line_no_count > current_count
73
- line_no = line_contents_split[current_count]
74
- contents = line_contents_split[current_count + 1]
75
- if Dir.exist?('.git')
76
- repo_root = '.'
77
-
78
- author = PWN::Plugins::Git.get_author(
79
- repo_root: repo_root,
80
- from_line: line_no,
81
- to_line: line_no,
82
- target_file: entry,
83
- entry_beautified: entry_beautified
84
- )
85
- end
86
- author ||= 'N/A'
87
-
88
- ai_analysis = nil
89
- if ai_introspection
90
- request = {
91
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
92
- line_no: line_no,
93
- source_code_snippet: contents
94
- }.to_json
95
- response = PWN::AI::Introspection.reflect(request: request)
96
- if response.is_a?(Hash)
97
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
98
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
99
- end
100
- end
101
-
102
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
103
- line_no: line_no,
104
- contents: contents,
105
- author: author,
106
- ai_analysis: ai_analysis
107
- )
108
-
109
- current_count += 2
110
- end
111
- result_arr.push(hash_line)
112
- logger_results = "#{logger_results}x" # Seeing progress is good :)
113
- end
114
- end
115
- end
116
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
117
- if logger_results.empty?
118
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
119
- else
120
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
121
- end
122
- result_arr
23
+ test_case_filter = %(
24
+ grep -Ein \
25
+ -e "Authorization:(\\sBasic|Basic)" \
26
+ -e "Authorization:(\\sBearer|Bearer)" \
27
+ -e "Authorization:(\\sDigest|Digest)" \
28
+ -e "Authorization:(\\sHOBA|HOBA)" \
29
+ -e "Authorization:(\\sMutual|Mutual)" \
30
+ -e "Authorization:(\\sNegotiate|Negotiate)" \
31
+ -e "Authorization:(\\sVapid|Vapid)" \
32
+ -e "Authorization:(\\sSCRAM|SCRAM)" \
33
+ -e "Authorization:(\\sAWS|AWS)" \
34
+ -e "authorization(\\s=|=)" {PWN_SAST_SRC_TARGET} 2> /dev/null
35
+ )
36
+
37
+ PWN::SAST::TestCaseEngine.execute(
38
+ test_case_filter: test_case_filter,
39
+ security_references: security_references,
40
+ dir_path: dir_path,
41
+ git_repo_root_uri: git_repo_root_uri
42
+ )
123
43
  end
124
44
 
125
45
  # Used primarily to map NIST 800-53 Revision 4 Security Controls