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
@@ -8,8 +8,6 @@ module PWN
8
8
  # SAST Module used to identify hard-code/plain-text
9
9
  # passwords within source code.
10
10
  module Password
11
- @@logger = PWN::Plugins::PWNLogger.create
12
-
13
11
  # Supported Method Parameters::
14
12
  # PWN::SAST::Password.scan(
15
13
  # :dir_path => 'optional path to dir defaults to .'
@@ -19,102 +17,22 @@ 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 -Ein \
39
- -e "password(\\s=|=)" \
40
- -e "passwd(\\s=|=)" \
41
- -e "pass(\\s=|=)" \
42
- -e "password:\\s" \
43
- -e "pwd(\\s=|=)" #{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
- )
103
20
 
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
21
+ test_case_filter = %(
22
+ grep -Ein \
23
+ -e "password(\\s=|=)" \
24
+ -e "passwd(\\s=|=)" \
25
+ -e "pass(\\s=|=)" \
26
+ -e "password:\\s" \
27
+ -e "pwd(\\s=|=)" {PWN_SAST_SRC_TARGET} 2> /dev/null
28
+ )
29
+
30
+ PWN::SAST::TestCaseEngine.execute(
31
+ test_case_filter: test_case_filter,
32
+ security_references: security_references,
33
+ dir_path: dir_path,
34
+ git_repo_root_uri: git_repo_root_uri
35
+ )
118
36
  end
119
37
 
120
38
  # Used primarily to map NIST 800-53 Revision 4 Security Controls
@@ -8,8 +8,6 @@ module PWN
8
8
  # SAST Module used to identify HTTP input
9
9
  # mechanisms that exist in PHP code (e.g. $_REQUEST, $_GET, etc.)
10
10
  module PHPInputMechanisms
11
- @@logger = PWN::Plugins::PWNLogger.create
12
-
13
11
  # Supported Method Parameters::
14
12
  # PWN::SAST::PHPInputMechanisms.scan(
15
13
  # dir_path: 'optional path to dir defaults to .'
@@ -19,104 +17,27 @@ 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$/) && File.extname(entry).include?('.php') && 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 '$_COOKIE' \
40
- -e '$_FILES' \
41
- -e '$_GET' \
42
- -e '$_POST' \
43
- -e '$_REQUEST' \
44
- -e '$_SERVER' \
45
- -e '$_SESSION' #{entry} 2> /dev/null
46
- "
47
-
48
- str = `#{test_case_filter}`.to_s.scrub
49
20
 
50
- if str.to_s.empty?
51
- # If str length is >= 64 KB do not include results. (Due to Mongo Document Size Restrictions)
52
- logger_results = "#{logger_results}~" # Catching bugs is good :)
53
- else
54
- 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
55
-
56
- hash_line = {
57
- timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S.%9N %z').to_s,
58
- security_references: security_references,
59
- filename: { git_repo_root_uri: git_repo_root_uri, entry: entry },
60
- line_no_and_contents: '',
61
- raw_content: str,
62
- test_case_filter: test_case_filter
63
- }
64
-
65
- # COMMMENT: Must be a better way to implement this (regex is kinda funky)
66
- line_contents_split = str.split(/^(\d{1,}):|\n(\d{1,}):/)[1..-1]
67
- line_no_count = line_contents_split.length # This should always be an even number
68
- current_count = 0
69
- while line_no_count > current_count
70
- line_no = line_contents_split[current_count]
71
- contents = line_contents_split[current_count + 1]
72
- if Dir.exist?('.git')
73
- repo_root = '.'
74
-
75
- author = PWN::Plugins::Git.get_author(
76
- repo_root: repo_root,
77
- from_line: line_no,
78
- to_line: line_no,
79
- target_file: entry,
80
- entry_beautified: entry_beautified
81
- )
82
- end
83
- author ||= 'N/A'
84
-
85
- ai_analysis = nil
86
- if ai_introspection
87
- request = {
88
- scm_uri: "#{hash_line[:filename][:git_repo_root_uri]}/#{hash_line[:filename][:entry]}",
89
- line_no: line_no,
90
- source_code_snippet: contents
91
- }.to_json
92
- response = PWN::AI::Introspection.reflect(request: request)
93
- if response.is_a?(Hash)
94
- ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
95
- ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
96
- end
97
- end
21
+ test_case_filter = "
22
+ grep -Fn \
23
+ -e '$_COOKIE' \
24
+ -e '$_FILES' \
25
+ -e '$_GET' \
26
+ -e '$_POST' \
27
+ -e '$_REQUEST' \
28
+ -e '$_SERVER' \
29
+ -e '$_SESSION' {PWN_SAST_SRC_TARGET} 2> /dev/null
30
+ "
98
31
 
99
- hash_line[:line_no_and_contents] = line_no_and_contents_arr.push(
100
- line_no: line_no,
101
- contents: contents,
102
- author: author,
103
- ai_analysis: ai_analysis
104
- )
32
+ include_extensions = %w[.phar .pht .phtm .phtml .php .php2 .php3 .php4 .php5 .php7 .php8 .phps .phpt .pgif .inc]
105
33
 
106
- current_count += 2
107
- end
108
- result_arr.push(hash_line)
109
- logger_results = "#{logger_results}x" # Seeing progress is good :)
110
- end
111
- end
112
- end
113
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
114
- if logger_results.empty?
115
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
116
- else
117
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
118
- end
119
- result_arr
34
+ PWN::SAST::TestCaseEngine.execute(
35
+ test_case_filter: test_case_filter,
36
+ security_references: security_references,
37
+ dir_path: dir_path,
38
+ include_extensions: include_extensions,
39
+ git_repo_root_uri: git_repo_root_uri
40
+ )
120
41
  rescue StandardError => e
121
42
  raise e
122
43
  end
@@ -8,8 +8,6 @@ module PWN
8
8
  # SAST Module used to identify loose comparisons
9
9
  # (i.e. == instead of ===) within PHP source code.
10
10
  module PHPTypeJuggling
11
- @@logger = PWN::Plugins::PWNLogger.create
12
-
13
11
  # Supported Method Parameters::
14
12
  # PWN::SAST::PHPTypeJuggling.scan(
15
13
  # dir_path: 'optional path to dir defaults to .'
@@ -19,102 +17,25 @@ 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$/) && File.extname(entry).include?('.php') && 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 '!=' #{entry} 2> /dev/null | \
41
- grep -v \
42
- -e '===' \
43
- -e '!=='
44
- "
45
-
46
- str = `#{test_case_filter}`.to_s.scrub
47
20
 
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
21
+ test_case_filter = "
22
+ grep -Fn \
23
+ -e '==' \
24
+ -e '!=' {PWN_SAST_SRC_TARGET} 2> /dev/null | \
25
+ grep -v \
26
+ -e '===' \
27
+ -e '!=='
28
+ "
96
29
 
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
- )
30
+ include_extensions = %w[.phar .pht .phtm .phtml .php .php2 .php3 .php4 .php5 .php7 .php8 .phps .phpt .pgif .inc]
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
+ include_extensions: include_extensions,
37
+ git_repo_root_uri: git_repo_root_uri
38
+ )
118
39
  rescue StandardError => e
119
40
  raise e
120
41
  end
@@ -9,8 +9,6 @@ module PWN
9
9
  # of dependent software within source repos to ensure patching
10
10
  # requirements for those dependencies can be met.
11
11
  module PomVersion
12
- @@logger = PWN::Plugins::PWNLogger.create
13
-
14
12
  # Supported Method Parameters::
15
13
  # PWN::SAST::PomVersion.scan(
16
14
  # dir_path: 'optional path to dir defaults to .'
@@ -37,7 +35,7 @@ module PWN
37
35
 
38
36
  test_case_filter = "
39
37
  grep -in -B2 \
40
- -e 'version' #{entry} 2> /dev/null
38
+ -e 'version' {PWN_SAST_SRC_TARGET} 2> /dev/null
41
39
  "
42
40
 
43
41
  str = `#{test_case_filter}`.to_s.scrub
data/lib/pwn/sast/port.rb CHANGED
@@ -10,8 +10,6 @@ module PWN
10
10
  # code to get a sense around appropriate secure network
11
11
  # communications in place.
12
12
  module Port
13
- @@logger = PWN::Plugins::PWNLogger.create
14
-
15
13
  # Supported Method Parameters::
16
14
  # PWN::SAST::Port.scan(
17
15
  # dir_path: 'optional path to dir defaults to .'
@@ -21,103 +19,23 @@ module PWN
21
19
  public_class_method def self.scan(opts = {})
22
20
  dir_path = opts[:dir_path]
23
21
  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
-
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$/ && 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 -niE \
41
- -e "localhost:\\d" \
42
- -e ":\/\/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
43
- -e "port\\s=\\s([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
44
- -e "port=([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
45
- -e "port:([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
46
- -e "port:\\s([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" #{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
22
 
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
114
- logger_banner = "http://#{Socket.gethostname}:8808/doc_root/pwn-#{PWN::VERSION.to_s.scrub}/#{to_s.scrub.gsub('::', '/')}.html"
115
- if logger_results.empty?
116
- @@logger.info("#{logger_banner}: No files applicable to this test case.\n")
117
- else
118
- @@logger.info("#{logger_banner} => #{logger_results}complete.\n")
119
- end
120
- result_arr
23
+ test_case_filter = %(
24
+ grep -niE \
25
+ -e "localhost:\\d" \
26
+ -e ":\/\/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
27
+ -e "port\\s=\\s([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
28
+ -e "port=([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
29
+ -e "port:([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" \
30
+ -e "port:\\s([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])" {PWN_SAST_SRC_TARGET} 2> /dev/null
31
+ )
32
+
33
+ PWN::SAST::TestCaseEngine.execute(
34
+ test_case_filter: test_case_filter,
35
+ security_references: security_references,
36
+ dir_path: dir_path,
37
+ git_repo_root_uri: git_repo_root_uri
38
+ )
121
39
  rescue StandardError => e
122
40
  raise e
123
41
  end
@@ -9,8 +9,6 @@ module PWN
9
9
  # declarations within source code in an effort to
10
10
  # determine if XSS is possible
11
11
  module PostMessage
12
- @@logger = PWN::Plugins::PWNLogger.create
13
-
14
12
  # Supported Method Parameters::
15
13
  # PWN::SAST::PostMessage.scan(
16
14
  # dir_path: 'optional path to dir defaults to .'
@@ -20,98 +18,18 @@ 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$/ && 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 'postMessage(' #{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
21
 
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
- )
22
+ test_case_filter = "
23
+ grep -n \
24
+ -e 'postMessage(' {PWN_SAST_SRC_TARGET} 2> /dev/null
25
+ "
100
26
 
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
27
+ PWN::SAST::TestCaseEngine.execute(
28
+ test_case_filter: test_case_filter,
29
+ security_references: security_references,
30
+ dir_path: dir_path,
31
+ git_repo_root_uri: git_repo_root_uri
32
+ )
115
33
  rescue StandardError => e
116
34
  raise e
117
35
  end