pwn 0.5.442 → 0.5.444

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +3 -3
  4. data/bin/pwn_sast +1 -0
  5. data/lib/pwn/plugins/file_fu.rb +20 -22
  6. data/lib/pwn/sast/amqp_connect_as_guest.rb +12 -91
  7. data/lib/pwn/sast/apache_file_system_util_api.rb +11 -93
  8. data/lib/pwn/sast/aws.rb +13 -95
  9. data/lib/pwn/sast/banned_function_calls_c.rb +140 -219
  10. data/lib/pwn/sast/base64.rb +12 -92
  11. data/lib/pwn/sast/beef_hook.rb +10 -92
  12. data/lib/pwn/sast/cmd_execution_go_lang.rb +83 -0
  13. data/lib/pwn/sast/cmd_execution_java.rb +14 -93
  14. data/lib/pwn/sast/cmd_execution_python.rb +16 -95
  15. data/lib/pwn/sast/cmd_execution_ruby.rb +24 -103
  16. data/lib/pwn/sast/cmd_execution_scala.rb +14 -93
  17. data/lib/pwn/sast/csrf.rb +10 -92
  18. data/lib/pwn/sast/deserial_java.rb +19 -98
  19. data/lib/pwn/sast/emoticon.rb +17 -100
  20. data/lib/pwn/sast/eval.rb +10 -92
  21. data/lib/pwn/sast/factory.rb +15 -95
  22. data/lib/pwn/sast/http_authorization_header.rb +20 -102
  23. data/lib/pwn/sast/inner_html.rb +10 -92
  24. data/lib/pwn/sast/keystore.rb +10 -92
  25. data/lib/pwn/sast/local_storage.rb +11 -93
  26. data/lib/pwn/sast/location_hash.rb +10 -92
  27. data/lib/pwn/sast/log4j.rb +12 -91
  28. data/lib/pwn/sast/logger.rb +24 -106
  29. data/lib/pwn/sast/md5.rb +10 -92
  30. data/lib/pwn/sast/outer_html.rb +10 -92
  31. data/lib/pwn/sast/padding_oracle.rb +11 -93
  32. data/lib/pwn/sast/password.rb +15 -97
  33. data/lib/pwn/sast/php_input_mechanisms.rb +18 -97
  34. data/lib/pwn/sast/php_type_juggling.rb +16 -95
  35. data/lib/pwn/sast/pom_version.rb +1 -3
  36. data/lib/pwn/sast/port.rb +16 -98
  37. data/lib/pwn/sast/post_message.rb +10 -92
  38. data/lib/pwn/sast/private_key.rb +10 -92
  39. data/lib/pwn/sast/redirect.rb +13 -95
  40. data/lib/pwn/sast/redos.rb +16 -98
  41. data/lib/pwn/sast/shell.rb +18 -100
  42. data/lib/pwn/sast/signature.rb +10 -92
  43. data/lib/pwn/sast/sql.rb +19 -95
  44. data/lib/pwn/sast/ssl.rb +14 -96
  45. data/lib/pwn/sast/sudo.rb +10 -92
  46. data/lib/pwn/sast/task_tag.rb +23 -105
  47. data/lib/pwn/sast/test_case_engine.rb +188 -0
  48. data/lib/pwn/sast/throw_errors.rb +14 -96
  49. data/lib/pwn/sast/token.rb +12 -94
  50. data/lib/pwn/sast/type_script_type_juggling.rb +16 -95
  51. data/lib/pwn/sast/version.rb +12 -94
  52. data/lib/pwn/sast/window_location_hash.rb +10 -92
  53. data/lib/pwn/sast.rb +5 -0
  54. data/lib/pwn/version.rb +1 -1
  55. data/lib/pwn.rb +0 -2
  56. data/spec/lib/pwn/sast/cmd_execution_go_lang_spec.rb +25 -0
  57. data/spec/lib/pwn/sast/test_case_engine_spec.rb +20 -0
  58. data/third_party/pwn_rdoc.jsonl +1 -1
  59. metadata +7 -3
@@ -9,8 +9,6 @@ module PWN
9
9
  # calls in C & C++ code per:
10
10
  # https://msdn.microsoft.com/en-us/library/bb288454.aspx
11
11
  module BannedFunctionCallsC
12
- @@logger = PWN::Plugins::PWNLogger.create
13
-
14
12
  # Supported Method Parameters::
15
13
  # PWN::SAST::BannedFunctionCallsC.scan(
16
14
  # :dir_path => 'optional path to dir defaults to .'
@@ -20,226 +18,149 @@ module PWN
20
18
  public_class_method def self.scan(opts = {})
21
19
  dir_path = opts[:dir_path]
22
20
  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
-
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$/) && (File.extname(entry) == '.c' || File.extname(entry) == '.cpp' || File.extname(entry) == '.c++' || File.extname(entry) == '.cxx' || File.extname(entry) == '.h' || File.extname(entry) == '.hpp' || File.extname(entry) == '.h++' || File.extname(entry) == '.hh' || File.extname(entry) == '.hxx' || File.extname(entry) == '.ii' || File.extname(entry) == '.ixx' || File.extname(entry) == '.ipp' || File.extname(entry) == '.inl' || File.extname(entry) == '.txx' || File.extname(entry) == '.tpp' || File.extname(entry) == '.tpl') && 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 -Fn \
40
- -e 'strcpy' \
41
- -e 'strcpyA' \
42
- -e 'strcpyW' \
43
- -e 'wcscpy' \
44
- -e '_tcscpy' \
45
- -e '_mbscpy' \
46
- -e 'StrCpy' \
47
- -e 'StrCpyA' \
48
- -e 'StrCpyW' \
49
- -e 'lstrcpy' \
50
- -e 'lstrcpyA' \
51
- -e 'lstrcpyW' \
52
- -e '_tccpy' \
53
- -e '_mbccpy' \
54
- -e '_ftcscpy' \
55
- -e 'strncpy' \
56
- -e 'wcsncpy' \
57
- -e '_tcsncpy' \
58
- -e '_mbsncpy' \
59
- -e '_mbsnbcpy' \
60
- -e 'StrCpyN' \
61
- -e 'StrCpyNA' \
62
- -e 'StrCpyNW' \
63
- -e 'StrNCpy' \
64
- -e 'strcpynA' \
65
- -e 'StrNCpyA' \
66
- -e 'StrNCpyW' \
67
- -e 'lstrcpyn' \
68
- -e 'lstrcpynA' \
69
- -e 'lstrcpynW' \
70
- -e 'strcat' \
71
- -e 'strcatA' \
72
- -e 'strcatW' \
73
- -e 'wcscat' \
74
- -e '_tcscat' \
75
- -e '_mbscat' \
76
- -e 'StrCat' \
77
- -e 'StrCatA' \
78
- -e 'StrCatW' \
79
- -e 'lstrcat' \
80
- -e 'lstrcatA' \
81
- -e 'lstrcatW' \
82
- -e 'StrCatBuff' \
83
- -e 'StrCatBuffA' \
84
- -e 'StrCatBuffW' \
85
- -e 'StrCatChainW' \
86
- -e '_tccat' \
87
- -e '_mbccat' \
88
- -e '_ftcscat' \
89
- -e 'strncat' \
90
- -e 'wcsncat' \
91
- -e '_tcsncat' \
92
- -e '_mbsncat' \
93
- -e '_mbsnbcat' \
94
- -e 'StrCatN' \
95
- -e 'StrCatNA' \
96
- -e 'StrCatNW' \
97
- -e 'StrNCat' \
98
- -e 'StrNCatA' \
99
- -e 'StrNCatW' \
100
- -e 'lstrncat' \
101
- -e 'lstrcatnA' \
102
- -e 'lstrcatnW' \
103
- -e 'lstrcatn' \
104
- -e 'sprintfW' \
105
- -e 'sprintfA' \
106
- -e 'wsprintf' \
107
- -e 'wsprintfW' \
108
- -e 'wsprintfA' \
109
- -e 'sprintf' \
110
- -e 'swprintf' \
111
- -e '_stprintf' \
112
- -e 'wvsprintf' \
113
- -e 'wvsprintfA' \
114
- -e 'wvsprintfW' \
115
- -e 'vsprintf' \
116
- -e '_vstprintf' \
117
- -e 'vswprintf' \
118
- -e 'wvsprintf' \
119
- -e 'wvsprintfA' \
120
- -e 'wvsprintfW' \
121
- -e 'vsprintf' \
122
- -e '_vstprintf' \
123
- -e 'vswprintf' \
124
- -e 'strncpy' \
125
- -e 'wcsncpy' \
126
- -e '_tcsncpy' \
127
- -e '_mbsncpy' \
128
- -e '_mbsnbcpy' \
129
- -e 'StrCpyN' \
130
- -e 'StrCpyNA' \
131
- -e 'StrCpyNW' \
132
- -e 'StrNCpy' \
133
- -e 'strcpynA' \
134
- -e 'StrNCpyA' \
135
- -e 'StrNCpyW' \
136
- -e 'lstrcpyn' \
137
- -e 'lstrcpynA' \
138
- -e 'lstrcpynW' \
139
- -e '_fstrncpy' \
140
- -e 'strncat' \
141
- -e 'wcsncat' \
142
- -e '_tcsncat' \
143
- -e '_mbsncat' \
144
- -e '_mbsnbcat' \
145
- -e 'StrCatN' \
146
- -e 'StrCatNA' \
147
- -e 'StrCatNW' \
148
- -e 'StrNCat' \
149
- -e 'StrNCatA' \
150
- -e 'StrNCatW' \
151
- -e 'lstrncat' \
152
- -e 'lstrcatnA' \
153
- -e 'lstrcatnW' \
154
- -e 'lstrcatn' \
155
- -e '_fstrncat' \
156
- -e 'gets' \
157
- -e '_getts' \
158
- -e '_gettws' \
159
- -e 'IsBadWritePtr' \
160
- -e 'IsBadHugeWritePtr' \
161
- -e 'IsBadReadPtr' \
162
- -e 'IsBadHugeReadPtr' \
163
- -e 'IsBadCodePtr' \
164
- -e 'IsBadStringPtr' \
165
- -e 'memcpy' \
166
- -e 'RtlCopyMemory' \
167
- -e 'CopyMemory' \
168
- -e 'wmemcpy' #{entry} 2> /dev/null
169
- "
170
-
171
- str = `#{test_case_filter}`.to_s.scrub
172
21
 
173
- if str.to_s.empty?
174
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
175
- logger_results = "#{logger_results}~" # Catching bugs is good :)
176
- else
177
- 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
178
-
179
- hash_line = {
180
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
181
- security_references: security_references,
182
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
183
- line_no_and_contents: '',
184
- raw_content: str,
185
- test_case_filter: test_case_filter
186
- }
187
-
188
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
189
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
190
- line_no_count = line_contents_split.length # This should always be an even number
191
- current_count = 0
192
- while line_no_count > current_count
193
- line_no = line_contents_split[current_count]
194
- contents = line_contents_split[current_count + 1]
195
- if Dir.exist?('.git')
196
- repo_root = '.'
197
-
198
- author = PWN::Plugins::Git.get_author(
199
- repo_root: repo_root,
200
- from_line: line_no,
201
- to_line: line_no,
202
- target_file: entry,
203
- entry_beautified: entry_beautified
204
- )
205
- end
206
- author ||= 'N/A'
207
-
208
- ai_analysis = nil
209
- if ai_introspection
210
- request = {
211
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
212
- line_no: line_no,
213
- source_code_snippet: contents
214
- }.to_json
215
- response = PWN::AI::Introspection.reflect(request: request)
216
- if response.is_a?(Hash)
217
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
218
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
219
- end
220
- end
22
+ test_case_filter = "
23
+ grep -Fn \
24
+ -e 'strcpy' \
25
+ -e 'strcpyA' \
26
+ -e 'strcpyW' \
27
+ -e 'wcscpy' \
28
+ -e '_tcscpy' \
29
+ -e '_mbscpy' \
30
+ -e 'StrCpy' \
31
+ -e 'StrCpyA' \
32
+ -e 'StrCpyW' \
33
+ -e 'lstrcpy' \
34
+ -e 'lstrcpyA' \
35
+ -e 'lstrcpyW' \
36
+ -e '_tccpy' \
37
+ -e '_mbccpy' \
38
+ -e '_ftcscpy' \
39
+ -e 'strncpy' \
40
+ -e 'wcsncpy' \
41
+ -e '_tcsncpy' \
42
+ -e '_mbsncpy' \
43
+ -e '_mbsnbcpy' \
44
+ -e 'StrCpyN' \
45
+ -e 'StrCpyNA' \
46
+ -e 'StrCpyNW' \
47
+ -e 'StrNCpy' \
48
+ -e 'strcpynA' \
49
+ -e 'StrNCpyA' \
50
+ -e 'StrNCpyW' \
51
+ -e 'lstrcpyn' \
52
+ -e 'lstrcpynA' \
53
+ -e 'lstrcpynW' \
54
+ -e 'strcat' \
55
+ -e 'strcatA' \
56
+ -e 'strcatW' \
57
+ -e 'wcscat' \
58
+ -e '_tcscat' \
59
+ -e '_mbscat' \
60
+ -e 'StrCat' \
61
+ -e 'StrCatA' \
62
+ -e 'StrCatW' \
63
+ -e 'lstrcat' \
64
+ -e 'lstrcatA' \
65
+ -e 'lstrcatW' \
66
+ -e 'StrCatBuff' \
67
+ -e 'StrCatBuffA' \
68
+ -e 'StrCatBuffW' \
69
+ -e 'StrCatChainW' \
70
+ -e '_tccat' \
71
+ -e '_mbccat' \
72
+ -e '_ftcscat' \
73
+ -e 'strncat' \
74
+ -e 'wcsncat' \
75
+ -e '_tcsncat' \
76
+ -e '_mbsncat' \
77
+ -e '_mbsnbcat' \
78
+ -e 'StrCatN' \
79
+ -e 'StrCatNA' \
80
+ -e 'StrCatNW' \
81
+ -e 'StrNCat' \
82
+ -e 'StrNCatA' \
83
+ -e 'StrNCatW' \
84
+ -e 'lstrncat' \
85
+ -e 'lstrcatnA' \
86
+ -e 'lstrcatnW' \
87
+ -e 'lstrcatn' \
88
+ -e 'sprintfW' \
89
+ -e 'sprintfA' \
90
+ -e 'wsprintf' \
91
+ -e 'wsprintfW' \
92
+ -e 'wsprintfA' \
93
+ -e 'sprintf' \
94
+ -e 'swprintf' \
95
+ -e '_stprintf' \
96
+ -e 'wvsprintf' \
97
+ -e 'wvsprintfA' \
98
+ -e 'wvsprintfW' \
99
+ -e 'vsprintf' \
100
+ -e '_vstprintf' \
101
+ -e 'vswprintf' \
102
+ -e 'wvsprintf' \
103
+ -e 'wvsprintfA' \
104
+ -e 'wvsprintfW' \
105
+ -e 'vsprintf' \
106
+ -e '_vstprintf' \
107
+ -e 'vswprintf' \
108
+ -e 'strncpy' \
109
+ -e 'wcsncpy' \
110
+ -e '_tcsncpy' \
111
+ -e '_mbsncpy' \
112
+ -e '_mbsnbcpy' \
113
+ -e 'StrCpyN' \
114
+ -e 'StrCpyNA' \
115
+ -e 'StrCpyNW' \
116
+ -e 'StrNCpy' \
117
+ -e 'strcpynA' \
118
+ -e 'StrNCpyA' \
119
+ -e 'StrNCpyW' \
120
+ -e 'lstrcpyn' \
121
+ -e 'lstrcpynA' \
122
+ -e 'lstrcpynW' \
123
+ -e '_fstrncpy' \
124
+ -e 'strncat' \
125
+ -e 'wcsncat' \
126
+ -e '_tcsncat' \
127
+ -e '_mbsncat' \
128
+ -e '_mbsnbcat' \
129
+ -e 'StrCatN' \
130
+ -e 'StrCatNA' \
131
+ -e 'StrCatNW' \
132
+ -e 'StrNCat' \
133
+ -e 'StrNCatA' \
134
+ -e 'StrNCatW' \
135
+ -e 'lstrncat' \
136
+ -e 'lstrcatnA' \
137
+ -e 'lstrcatnW' \
138
+ -e 'lstrcatn' \
139
+ -e '_fstrncat' \
140
+ -e 'gets' \
141
+ -e '_getts' \
142
+ -e '_gettws' \
143
+ -e 'IsBadWritePtr' \
144
+ -e 'IsBadHugeWritePtr' \
145
+ -e 'IsBadReadPtr' \
146
+ -e 'IsBadHugeReadPtr' \
147
+ -e 'IsBadCodePtr' \
148
+ -e 'IsBadStringPtr' \
149
+ -e 'memcpy' \
150
+ -e 'RtlCopyMemory' \
151
+ -e 'CopyMemory' \
152
+ -e 'wmemcpy' {PWN_SAST_SRC_TARGET} 2> /dev/null
153
+ "
221
154
 
222
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
223
- line_no: line_no,
224
- contents: contents,
225
- author: author,
226
- ai_analysis: ai_analysis
227
- )
155
+ include_extensions = %w[.c .cats .idc .cpp .cc .cxx .c++ .cp .CPP .C .cppm .ixx .h .hpp .hxx .hh .h++ .inc .inl .ipp .tcc .tpp .txx .i .s .asm .o .obj .a .so .lib .dll .exe .pdb .vcxproj .sln .dsp .dsw .cbp .cmake .make .mk]
228
156
 
229
- current_count += 2
230
- end
231
- result_arr.push(hash_line)
232
- logger_results = "#{logger_results}x" # Seeing progress is good :)
233
- end
234
- end
235
- end
236
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
237
- if logger_results.empty?
238
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
239
- else
240
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
241
- end
242
- result_arr
157
+ PWN::SAST::TestCaseEngine.execute(
158
+ test_case_filter: test_case_filter,
159
+ security_references: security_references,
160
+ dir_path: dir_path,
161
+ include_extensions: include_extensions,
162
+ git_repo_root_uri: git_repo_root_uri
163
+ )
243
164
  rescue StandardError => e
244
165
  raise e
245
166
  end
@@ -8,8 +8,6 @@ module PWN
8
8
  # SAST Module used to identify Base64 encoded strings
9
9
  # that may have sensitive artifacts when decoded.
10
10
  module Base64
11
- @@logger = PWN::Plugins::PWNLogger.create
12
-
13
11
  # Supported Method Parameters::
14
12
  # PWN::SAST::Base64.scan(
15
13
  # dir_path: 'optional path to dir defaults to .'
@@ -19,98 +17,20 @@ module PWN
19
17
  public_class_method def self.scan(opts = {})
20
18
  dir_path = opts[:dir_path]
21
19
  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
-
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
- # TODO: Include regex to search for Base64 strings
38
- test_case_filter = "
39
- grep -Ein \
40
- -e 'BASE64' #{entry} 2> /dev/null
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
20
 
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
- )
21
+ test_case_filter = "
22
+ grep -Ein \
23
+ -e 'BASE64' \
24
+ -e '^[A-Za-z0-9+/]{12}([A-Za-z0-9+/]{4})*$|^[A-Za-z0-9+/]{8}([A-Za-z0-9+/]{4})*[A-Za-z0-9+/]{2}==$|^[A-Za-z0-9+/]{8}([A-Za-z0-9+/]{4})*[A-Za-z0-9+/]{3}=$' \
25
+ {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
@@ -8,8 +8,6 @@ module PWN
8
8
  # SAST Module used to detect if the default BeEF
9
9
  # exploitation hooks reside within source code.
10
10
  module BeefHook
11
- @@logger = PWN::Plugins::PWNLogger.create
12
-
13
11
  # Supported Method Parameters::
14
12
  # PWN::SAST::BeefHook.scan(
15
13
  # dir_path: 'optional path to dir defaults to .'
@@ -19,98 +17,18 @@ module PWN
19
17
  public_class_method def self.scan(opts = {})
20
18
  dir_path = opts[:dir_path]
21
19
  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
-
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 'hook.js' #{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
20
 
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
- )
21
+ test_case_filter = "
22
+ grep -Fin \
23
+ -e 'hook.js' {PWN_SAST_SRC_TARGET} 2> /dev/null
24
+ "
99
25
 
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
26
+ PWN::SAST::TestCaseEngine.execute(
27
+ test_case_filter: test_case_filter,
28
+ security_references: security_references,
29
+ dir_path: dir_path,
30
+ git_repo_root_uri: git_repo_root_uri
31
+ )
114
32
  rescue StandardError => e
115
33
  raise e
116
34
  end