pwn 0.5.398 → 0.5.399
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.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/bin/pwn_burp_suite_pro_active_rest_api_scan +16 -24
- data/bin/pwn_burp_suite_pro_active_scan +16 -25
- data/bin/pwn_zaproxy_active_rest_api_scan +166 -0
- data/bin/{pwn_owasp_zap_active_scan → pwn_zaproxy_active_scan} +57 -49
- data/lib/pwn/plugins/burp_suite.rb +21 -17
- data/lib/pwn/plugins/{owasp_zap.rb → zaproxy.rb} +128 -100
- data/lib/pwn/plugins.rb +1 -1
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/plugins/{owasp_zap_spec.rb → zaproxy_spec.rb} +3 -3
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e10ec68e7ef2ebf6cce111bacbb8c9fbe95a5f5db4f775f845f1d1829d30f89a
|
4
|
+
data.tar.gz: 0fec666835b27fae7f193a6468d78c5351eec13cffd6293d3e175fec7dcc3891
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69b64372dbe837e9320ad98a1064956b12581f154c1d14e1e77d1f4ba4e2de0530fa5b8ba13c31320fd4f8cbbcaf7db81c62b44f5612ef576355e7c997d685ae
|
7
|
+
data.tar.gz: 0b2fbf6d6c83e491ec54a30e114adddae1a211b063ca66d4aca07388df80da8b8fd2d455cb884523d3bedb31740de4f0a79986ccb5bfd496430087c81a427dd6
|
data/README.md
CHANGED
@@ -37,7 +37,7 @@ $ cd /opt/pwn
|
|
37
37
|
$ ./install.sh
|
38
38
|
$ ./install.sh ruby-gem
|
39
39
|
$ pwn
|
40
|
-
pwn[v0.5.
|
40
|
+
pwn[v0.5.399]:001 >>> PWN.help
|
41
41
|
```
|
42
42
|
|
43
43
|
[](https://youtu.be/G7iLUY4FzsI)
|
@@ -52,7 +52,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
52
52
|
$ gem uninstall --all --executables pwn
|
53
53
|
$ gem install --verbose pwn
|
54
54
|
$ pwn
|
55
|
-
pwn[v0.5.
|
55
|
+
pwn[v0.5.399]:001 >>> PWN.help
|
56
56
|
```
|
57
57
|
|
58
58
|
If you're using a multi-user install of RVM do:
|
@@ -62,7 +62,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
62
62
|
$ rvmsudo gem uninstall --all --executables pwn
|
63
63
|
$ rvmsudo gem install --verbose pwn
|
64
64
|
$ pwn
|
65
|
-
pwn[v0.5.
|
65
|
+
pwn[v0.5.399]:001 >>> PWN.help
|
66
66
|
```
|
67
67
|
|
68
68
|
PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
|
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require 'fileutils'
|
5
4
|
require 'pwn'
|
6
5
|
require 'optparse'
|
7
6
|
require 'uri'
|
@@ -16,14 +15,22 @@ OptionParser.new do |options|
|
|
16
15
|
opts[:target_url] = t
|
17
16
|
end
|
18
17
|
|
19
|
-
options.on('-
|
20
|
-
opts[:
|
18
|
+
options.on('-oDIR', '--report_output_dir=DIR', '<Required - Output Directory for Active Scan Report>') do |o|
|
19
|
+
opts[:output_dir] = o
|
21
20
|
end
|
22
21
|
|
23
22
|
options.on('-dSWAGGER', '--swagger_definitions=SWAGGER', '<Required - Comma-delimited list of Swagger JSON/YAML files to import>') do |s|
|
24
23
|
opts[:swagger_definitions] = s
|
25
24
|
end
|
26
25
|
|
26
|
+
options.on('-bBPATH', '--burp_path=BPATH', '<Optional - Path to Burp Suite Pro Jar File (Defaults to /opt/burpsuite/burpsuite-pro.jar)>') do |b|
|
27
|
+
opts[:burp_jar_path] = b
|
28
|
+
end
|
29
|
+
|
30
|
+
options.on('-h', '--[no-]headless', '<Optional - Run Burp and Browser Headless>') do |h|
|
31
|
+
opts[:headless] = h
|
32
|
+
end
|
33
|
+
|
27
34
|
options.on('-D', '--[no-]debug', '<Optional - Enable Debug Output and Do Not Delete Temporary OpenAPI Spec>') do |d|
|
28
35
|
opts[:debug] = d
|
29
36
|
end
|
@@ -48,14 +55,6 @@ OptionParser.new do |options|
|
|
48
55
|
opts[:exclude_paths] = e
|
49
56
|
end
|
50
57
|
|
51
|
-
options.on('-bBPATH', '--burp_path=BPATH', '<Optional - Path to Burp Suite Pro Jar File (Defaults to /opt/burpsuite/burpsuite-pro.jar)>') do |b|
|
52
|
-
opts[:burp_jar_path] = b
|
53
|
-
end
|
54
|
-
|
55
|
-
options.on('-h', '--[no-]headless', '<Optional - Run Burp and Browser Headless>') do |h|
|
56
|
-
opts[:headless] = h
|
57
|
-
end
|
58
|
-
|
59
58
|
options.on('-iURL', '--in_scope=URL', '<Optional - URL to add include in scope (Defaults to value of --target_url)>') do |s|
|
60
59
|
opts[:in_scope] = s
|
61
60
|
end
|
@@ -70,17 +69,17 @@ begin
|
|
70
69
|
timestamp = Time.now.strftime('%Y-%m-%d_%H-%M-%S%Z')
|
71
70
|
logger = PWN::Plugins::PWNLogger.create
|
72
71
|
|
73
|
-
burp_jar_path = opts[:burp_jar_path]
|
74
|
-
headless = opts[:headless] || false
|
75
72
|
target_url = opts[:target_url]
|
76
73
|
raise 'ERROR: --target_url is required.' if target_url.nil?
|
77
74
|
|
78
|
-
|
79
|
-
raise 'ERROR: --
|
75
|
+
output_dir = opts[:output_dir]
|
76
|
+
raise 'ERROR: --report_output_dir is required.' if output_dir.nil?
|
80
77
|
|
81
78
|
swagger_definitions = opts[:swagger_definitions]
|
82
79
|
raise 'ERROR: --swagger_definitions is required.' if swagger_definitions.nil?
|
83
80
|
|
81
|
+
burp_jar_path = opts[:burp_jar_path]
|
82
|
+
headless = opts[:headless] || false
|
84
83
|
debug = opts[:debug] || false
|
85
84
|
|
86
85
|
swagger_defs_arr = swagger_definitions.split(',').map(&:strip)
|
@@ -146,7 +145,7 @@ begin
|
|
146
145
|
|
147
146
|
raise "ERROR: Failed to import OpenAPI/Swagger spec #{openapi_spec} into Burp Suite Pro's Sitemap." if json_sitemap.nil? || json_sitemap.empty?
|
148
147
|
|
149
|
-
PWN::Plugins::BurpSuite.
|
148
|
+
PWN::Plugins::BurpSuite.active_scan(
|
150
149
|
burp_obj: burp_obj,
|
151
150
|
target_url: in_scope,
|
152
151
|
exclude_paths: exlude_paths
|
@@ -159,17 +158,11 @@ begin
|
|
159
158
|
# Once DefectDojo begins to support XML report results
|
160
159
|
report_types = %i[html xml]
|
161
160
|
report_types.each do |report_type|
|
162
|
-
this_output_path = "#{output_path}.html"
|
163
|
-
# this_output_path = "#{File.dirname(output_path)}/#{File.basename(output_path, File.extname(output_path))}.html"
|
164
|
-
|
165
|
-
this_output_path = "#{output_path}.xml" if report_type == :xml
|
166
|
-
# this_output_path = "#{File.dirname(output_path)}/#{File.basename(output_path, File.extname(output_path))}.xml" if report_type == :xml
|
167
|
-
|
168
161
|
PWN::Plugins::BurpSuite.generate_scan_report(
|
169
162
|
burp_obj: burp_obj,
|
170
163
|
target_url: in_scope,
|
171
164
|
report_type: report_type,
|
172
|
-
|
165
|
+
output_dir: output_dir
|
173
166
|
)
|
174
167
|
end
|
175
168
|
|
@@ -177,6 +170,5 @@ begin
|
|
177
170
|
rescue StandardError => e
|
178
171
|
raise e
|
179
172
|
ensure
|
180
|
-
FileUtils.rm_f(openapi_spec) unless debug
|
181
173
|
burp_obj = PWN::Plugins::BurpSuite.stop(burp_obj: burp_obj) unless burp_obj.nil?
|
182
174
|
end
|
@@ -14,8 +14,8 @@ OptionParser.new do |options|
|
|
14
14
|
opts[:target_url] = t
|
15
15
|
end
|
16
16
|
|
17
|
-
options.on('-
|
18
|
-
opts[:
|
17
|
+
options.on('-oDIR', '--report_output_dir=DIR', '<Required - Output Directory for Active Scan Report>') do |o|
|
18
|
+
opts[:output_dir] = o
|
19
19
|
end
|
20
20
|
|
21
21
|
options.on('-eLIST', '--exclude_paths=LIST', '<Optional - Comma-delimited list of paths to exlude from scanning (e.g. "/api/login, /api/logout, /api/etc")>') do |e|
|
@@ -30,6 +30,10 @@ OptionParser.new do |options|
|
|
30
30
|
opts[:headless] = h
|
31
31
|
end
|
32
32
|
|
33
|
+
options.on('-bTYPE', '--browser_type=TYPE', '<Optional - Browser Type <firefox|chrome|headless|rest> (Defaults to chrome)>') do |b|
|
34
|
+
opts[:browser_type] = b
|
35
|
+
end
|
36
|
+
|
33
37
|
options.on('-s', '--[no-]spider', '<Optional - Crawl / Spider Target Prior to Scanning (Defaults to false)>') do |s|
|
34
38
|
opts[:spider] = s
|
35
39
|
end
|
@@ -51,20 +55,19 @@ end
|
|
51
55
|
begin
|
52
56
|
logger = PWN::Plugins::PWNLogger.create
|
53
57
|
|
54
|
-
burp_jar_path = opts[:burp_jar_path]
|
55
|
-
headless = opts[:headless] || false
|
56
|
-
spider = opts[:spider] || false
|
57
58
|
target_url = opts[:target_url]
|
58
59
|
raise 'ERROR: --target_url is required.' if target_url.nil?
|
59
60
|
|
60
|
-
|
61
|
-
raise 'ERROR: --
|
61
|
+
output_dir = opts[:output_dir]
|
62
|
+
raise 'ERROR: --report_output_dir is required.' if output_dir.nil?
|
62
63
|
|
63
64
|
exlude_paths = opts[:exclude_paths]
|
64
65
|
exlude_paths = exlude_paths.split(',').map(&:strip) if exlude_paths.is_a?(String)
|
65
|
-
|
66
|
+
burp_jar_path = opts[:burp_jar_path]
|
67
|
+
headless = opts[:headless] || false
|
68
|
+
browser_type = opts[:browser_type] ||= :chrome
|
69
|
+
spider = opts[:spider] || false
|
66
70
|
navigation_instruct = opts[:navigation_instruct]
|
67
|
-
|
68
71
|
in_scope = opts[:in_scope] ||= target_url
|
69
72
|
|
70
73
|
# ------
|
@@ -77,7 +80,7 @@ begin
|
|
77
80
|
else
|
78
81
|
burp_obj = PWN::Plugins::BurpSuite.start(
|
79
82
|
burp_jar_path: burp_jar_path,
|
80
|
-
browser_type:
|
83
|
+
browser_type: browser_type
|
81
84
|
)
|
82
85
|
end
|
83
86
|
|
@@ -101,7 +104,7 @@ begin
|
|
101
104
|
browser = browser_obj[:browser]
|
102
105
|
browser.goto(target_url)
|
103
106
|
|
104
|
-
|
107
|
+
if navigation_instruct
|
105
108
|
File.read(navigation_instruct).each_line do |instruction|
|
106
109
|
# Look for any set method in this instruction and replace its value w/ asterisks
|
107
110
|
redact_regex = /\.set\(['"]([^'"]*)['"]\)/
|
@@ -112,13 +115,7 @@ begin
|
|
112
115
|
end
|
113
116
|
|
114
117
|
PWN::Plugins::BurpSuite.spider(burp_obj: burp_obj, target_url: in_scope) if spider
|
115
|
-
|
116
|
-
duration = 9
|
117
|
-
print "Waiting #{duration} seconds prior to kicking off active scan..."
|
118
|
-
sleep duration # Sleep for now so everything loads the way we expect - blech.
|
119
|
-
print "\n"
|
120
|
-
|
121
|
-
PWN::Plugins::BurpSuite.invoke_active_scan(
|
118
|
+
PWN::Plugins::BurpSuite.active_scan(
|
122
119
|
burp_obj: burp_obj,
|
123
120
|
target_url: in_scope,
|
124
121
|
exclude_paths: exlude_paths
|
@@ -131,17 +128,11 @@ begin
|
|
131
128
|
# Once DefectDojo begins to support XML report results
|
132
129
|
report_types = %i[html xml]
|
133
130
|
report_types.each do |report_type|
|
134
|
-
this_output_path = "#{output_path}.html"
|
135
|
-
# this_output_path = "#{File.dirname(output_path)}/#{File.basename(output_path, File.extname(output_path))}.html"
|
136
|
-
|
137
|
-
this_output_path = "#{output_path}.xml" if report_type == :xml
|
138
|
-
# this_output_path = "#{File.dirname(output_path)}/#{File.basename(output_path, File.extname(output_path))}.xml" if report_type == :xml
|
139
|
-
|
140
131
|
PWN::Plugins::BurpSuite.generate_scan_report(
|
141
132
|
burp_obj: burp_obj,
|
142
133
|
target_url: in_scope,
|
143
134
|
report_type: report_type,
|
144
|
-
|
135
|
+
output_dir: output_dir
|
145
136
|
)
|
146
137
|
end
|
147
138
|
|
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pwn'
|
6
|
+
require 'optparse'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
opts = {}
|
10
|
+
OptionParser.new do |options|
|
11
|
+
options.banner = "USAGE:
|
12
|
+
#{File.basename($PROGRAM_NAME)} [opts]
|
13
|
+
"
|
14
|
+
|
15
|
+
options.on('-aAPIKEY', '--api_key=APIKEY', '<Required - OWASP Zap API Key (Tools>Options>API)>') do |a|
|
16
|
+
opts[:api_key] = a
|
17
|
+
end
|
18
|
+
|
19
|
+
options.on('-tTARGET', '--target_url=TARGET', '<Required - Target URI to Scan>') do |t|
|
20
|
+
opts[:target_url] = t
|
21
|
+
end
|
22
|
+
|
23
|
+
options.on('-oPATH', '--report_output_path=PATH', '<Required - Output Path for Active Scan Issues>') do |o|
|
24
|
+
opts[:output_path] = o
|
25
|
+
end
|
26
|
+
|
27
|
+
options.on('-dSWAGGER', '--swagger_definitions=SWAGGER', '<Required - Comma-delimited list of Swagger JSON/YAML files to import>') do |s|
|
28
|
+
opts[:swagger_definitions] = s
|
29
|
+
end
|
30
|
+
|
31
|
+
options.on('-zZPATH', '--zap_bin_path=ZPATH', '<Optional - Path to zap.sh>') do |z|
|
32
|
+
opts[:zap_bin_path] = z
|
33
|
+
end
|
34
|
+
|
35
|
+
options.on('-h', '--[no-]headless', '<Optional - Run ZAP and Browser Headless>') do |h|
|
36
|
+
opts[:headless] = h
|
37
|
+
end
|
38
|
+
|
39
|
+
options.on('-D', '--[no-]debug', '<Optional - Enable Debug Output and Do Not Delete Temporary OpenAPI Spec>') do |d|
|
40
|
+
opts[:debug] = d
|
41
|
+
end
|
42
|
+
|
43
|
+
options.on('-vVERSION', '--openapi_spec_version=VERSION', '<Optional - OpenAPI/Swagger Specification Version (Defaults to 3.0.3)>') do |o|
|
44
|
+
opts[:openapi_spec_version] = o
|
45
|
+
end
|
46
|
+
|
47
|
+
options.on('-HJSON', '--additional_http_headers=JSON', '<Optional - JSON string of additional HTTP headers to include in requests (e.g. \'{"Header1":"Value1","Header2":"Value2"}\')>') do |h|
|
48
|
+
opts[:additional_http_headers] = h
|
49
|
+
end
|
50
|
+
|
51
|
+
options.on('-eLIST', '--exclude_paths=LIST', '<Optional - Comma-delimited list of paths to exlude from scanning (e.g. "/api/login, /api/logout, /api/etc")>') do |e|
|
52
|
+
opts[:exclude_paths] = e
|
53
|
+
end
|
54
|
+
|
55
|
+
options.on('-iURL', '--in_scope=URL', '<Optional - URL to add include in scope (Defaults to value of --target_url)>') do |s|
|
56
|
+
opts[:in_scope] = s
|
57
|
+
end
|
58
|
+
end.parse!
|
59
|
+
|
60
|
+
if opts.empty?
|
61
|
+
puts `#{File.basename($PROGRAM_NAME)} --help`
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
begin
|
66
|
+
timestamp = Time.now.strftime('%Y-%m-%d_%H-%M-%S%Z')
|
67
|
+
logger = PWN::Plugins::PWNLogger.create
|
68
|
+
|
69
|
+
api_key = opts[:api_key]
|
70
|
+
raise 'ERROR: --api_key is required.' if api_key.nil?
|
71
|
+
|
72
|
+
target_url = opts[:target_url]
|
73
|
+
raise 'ERROR: --target_url is required.' if target_url.nil?
|
74
|
+
|
75
|
+
output_path = opts[:output_path]
|
76
|
+
raise 'ERROR: --report_output_path is required.' if output_path.nil?
|
77
|
+
|
78
|
+
swagger_definitions = opts[:swagger_definitions]
|
79
|
+
raise 'ERROR: --swagger_definitions is required.' if swagger_definitions.nil?
|
80
|
+
|
81
|
+
zap_bin_path = opts[:zap_bin_path]
|
82
|
+
headless = opts[:headless] || false
|
83
|
+
debug = opts[:debug] || false
|
84
|
+
|
85
|
+
swagger_defs_arr = swagger_definitions.split(',').map(&:strip)
|
86
|
+
scheme = URI.parse(target_url).scheme
|
87
|
+
target_host = URI.parse(target_url).host
|
88
|
+
base_url = "#{scheme}://#{target_host}"
|
89
|
+
|
90
|
+
openapi_spec_version = opts[:openapi_spec_version]
|
91
|
+
openapi_spec_root = File.dirname(swagger_defs_arr.first)
|
92
|
+
openapi_spec = "#{openapi_spec_root}/openapi_spec-#{target_host}-#{timestamp}.json"
|
93
|
+
|
94
|
+
PWN::Plugins::OpenAPI.generate_spec(
|
95
|
+
spec_paths: swagger_defs_arr,
|
96
|
+
base_url: base_url,
|
97
|
+
output_json_path: openapi_spec,
|
98
|
+
target_version: openapi_spec_version,
|
99
|
+
debug: debug
|
100
|
+
)
|
101
|
+
|
102
|
+
additional_http_headers = opts[:additional_http_headers]
|
103
|
+
additional_http_headers = JSON.parse(additional_http_headers, symbolize_names: true) if additional_http_headers.is_a?(String)
|
104
|
+
|
105
|
+
exlude_paths = opts[:exclude_paths]
|
106
|
+
exlude_paths = exlude_paths.split(',').map(&:strip) if exlude_paths.is_a?(String)
|
107
|
+
|
108
|
+
in_scope = opts[:in_scope] ||= target_url
|
109
|
+
|
110
|
+
# ------
|
111
|
+
# Open ZAP
|
112
|
+
if headless
|
113
|
+
zap_obj = PWN::Plugins::Zaproxy.start(
|
114
|
+
zap_bin_path: zap_bin_path,
|
115
|
+
headless: headless
|
116
|
+
)
|
117
|
+
else
|
118
|
+
zap_obj = PWN::Plugins::Zaproxy.start(
|
119
|
+
zap_bin_path: zap_bin_path,
|
120
|
+
browser_type: :chrome
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
logger.info(zap_obj)
|
125
|
+
|
126
|
+
json_sitemap = PWN::Plugins::Zaproxy.import_openapi_to_sitemap(
|
127
|
+
zap_obj: zap_obj,
|
128
|
+
openapi_spec: openapi_spec
|
129
|
+
)
|
130
|
+
|
131
|
+
raise "ERROR: Failed to import OpenAPI/Swagger spec #{openapi_spec} into ZAP's Sitemap." if json_sitemap.nil? || json_sitemap.empty?
|
132
|
+
|
133
|
+
PWN::Plugins::Zaproxy.active_scan(
|
134
|
+
zap_obj: zap_obj,
|
135
|
+
target_url: target_url,
|
136
|
+
exclude_paths: exlude_paths
|
137
|
+
)
|
138
|
+
|
139
|
+
# Dump a list of scan issues from Active Scan result
|
140
|
+
# scan_issues = PWN::Plugins::Zaproxy.get_scan_issues(zap_obj: zap_obj)
|
141
|
+
# puts scan_issues
|
142
|
+
|
143
|
+
# Once DefectDojo begins to support XML report results
|
144
|
+
report_types = %i[html xml]
|
145
|
+
report_types.each do |report_type|
|
146
|
+
this_output_path = "#{output_path}.html"
|
147
|
+
# this_output_path = "#{File.dirname(output_path)}/#{File.basename(output_path, File.extname(output_path))}.html"
|
148
|
+
|
149
|
+
this_output_path = "#{output_path}.xml" if report_type == :xml
|
150
|
+
# this_output_path = "#{File.dirname(output_path)}/#{File.basename(output_path, File.extname(output_path))}.xml" if report_type == :xml
|
151
|
+
|
152
|
+
PWN::Plugins::Zaproxy.generate_scan_report(
|
153
|
+
zap_obj: zap_obj,
|
154
|
+
target_url: in_scope,
|
155
|
+
report_type: report_type,
|
156
|
+
output_path: this_output_path
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
zap_obj = PWN::Plugins::Zaproxy.stop(zap_obj: zap_obj)
|
161
|
+
rescue StandardError => e
|
162
|
+
raise e
|
163
|
+
ensure
|
164
|
+
FileUtils.rm_f(openapi_spec) unless debug
|
165
|
+
zap_obj = PWN::Plugins::Zaproxy.stop(zap_obj: zap_obj) unless zap_obj.nil?
|
166
|
+
end
|
@@ -22,12 +22,8 @@ OptionParser.new do |options|
|
|
22
22
|
opts[:output_dir] = o
|
23
23
|
end
|
24
24
|
|
25
|
-
options.on('-
|
26
|
-
opts[:
|
27
|
-
end
|
28
|
-
|
29
|
-
options.on('-IINST', '--navigation_instruct=INST', '<Optional - Path to Navigation Instructions (e.g. Auth w/ Target - see /pwn/etc/owasp_zap/navigation.instruct.EXAMPLE)>') do |i|
|
30
|
-
opts[:navigation_instruct] = i
|
25
|
+
options.on('-eLIST', '--exclude_paths=LIST', '<Optional - Comma-delimited list of paths to exlude from scanning (e.g. "/api/login, /api/logout, /api/etc")>') do |e|
|
26
|
+
opts[:exclude_paths] = e
|
31
27
|
end
|
32
28
|
|
33
29
|
options.on('-zZPATH', '--zap_bin_path=ZPATH', '<Optional - Path to zap.sh>') do |z|
|
@@ -38,8 +34,20 @@ OptionParser.new do |options|
|
|
38
34
|
opts[:headless] = h
|
39
35
|
end
|
40
36
|
|
41
|
-
options.on('-
|
42
|
-
opts[:
|
37
|
+
options.on('-bTYPE', '--browser_type=TYPE', '<Optional - Browser Type <firefox|chrome|headless|rest> (Defaults to chrome)>') do |b|
|
38
|
+
opts[:browser_type] = b
|
39
|
+
end
|
40
|
+
|
41
|
+
options.on('-s', '--[no-]spider', '<Optional - Crawl / Spider Target Prior to Scanning (Defaults to false)>') do |s|
|
42
|
+
opts[:spider] = s
|
43
|
+
end
|
44
|
+
|
45
|
+
options.on('-IINST', '--navigation_instruct=INST', '<Optional - Path to Navigation Instructions (e.g. Auth w/ Target - see /pwn/etc/owasp_zap/navigation.instruct.EXAMPLE)>') do |i|
|
46
|
+
opts[:navigation_instruct] = i
|
47
|
+
end
|
48
|
+
|
49
|
+
options.on('-iURL', '--in_scope=URL', '<Optional - URL to add include in scope (Defaults to value of --target_url)>') do |s|
|
50
|
+
opts[:in_scope] = s
|
43
51
|
end
|
44
52
|
end.parse!
|
45
53
|
|
@@ -59,64 +67,64 @@ begin
|
|
59
67
|
browser_type = opts[:browser_type].to_s.strip.chomp.scrub.to_sym
|
60
68
|
end
|
61
69
|
|
62
|
-
target_url = opts[:target_url]
|
63
|
-
|
64
|
-
|
70
|
+
target_url = opts[:target_url]
|
71
|
+
raise 'ERROR: --target_url is required.' if target_url.nil?
|
72
|
+
|
73
|
+
output_dir = opts[:output_dir]
|
74
|
+
raise 'ERROR: --report_output_dir is required.' if output_dir.nil?
|
75
|
+
|
76
|
+
exlude_paths = opts[:exclude_paths]
|
77
|
+
exlude_paths = exlude_paths.split(',').map(&:strip) if exlude_paths.is_a?(String)
|
65
78
|
zap_bin_path = opts[:zap_bin_path].to_s.strip.chomp.scrub if File.exist?(opts[:zap_bin_path].to_s.strip.chomp.scrub)
|
66
|
-
headless = opts[:headless]
|
67
|
-
|
79
|
+
headless = opts[:headless] || false
|
80
|
+
browser_type = opts[:browser_type] ||= :chrome
|
81
|
+
spider = opts[:spider] || false
|
82
|
+
navigation_instruct = opts[:navigation_instruct]
|
83
|
+
in_scope = opts[:in_scope] ||= target_url
|
68
84
|
|
69
85
|
# ------
|
70
86
|
# Dynamically build arguments hash based on flags passed and Open Zap
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
87
|
+
if headless
|
88
|
+
zap_obj = PWN::Plugins::Zaproxy.start(
|
89
|
+
zap_bin_path: zap_bin_path,
|
90
|
+
api_key: api_key,
|
91
|
+
headless: headless,
|
92
|
+
browser_type: :headless
|
93
|
+
)
|
94
|
+
else
|
95
|
+
zap_obj = PWN::Plugins::Zaproxy.start(
|
96
|
+
zap_bin_path: zap_bin_path,
|
97
|
+
api_key: api_key,
|
98
|
+
browser_type: browser_type
|
99
|
+
)
|
100
|
+
end
|
77
101
|
|
78
102
|
logger.info(zap_obj)
|
79
103
|
|
80
|
-
browser_obj =
|
81
|
-
browser_type: browser_type,
|
82
|
-
proxy: proxy
|
83
|
-
)
|
104
|
+
browser_obj = zap_obj[:zap_browser]
|
84
105
|
browser = browser_obj[:browser]
|
85
|
-
|
86
|
-
if browser_type == :rest
|
87
|
-
browser.get(target_url)
|
88
|
-
else
|
89
|
-
browser.goto(target_url)
|
90
|
-
end
|
106
|
+
browser.goto(target_url)
|
91
107
|
|
92
108
|
if navigation_instruct
|
93
109
|
File.read(navigation_instruct).each_line do |instruction|
|
110
|
+
# Look for any set method in this instruction and replace its value w/ asterisks
|
111
|
+
redact_regex = /\.set\(['"]([^'"]*)['"]\)/
|
112
|
+
redacted_instruction = instruction.gsub(redact_regex, ".set('********')")
|
113
|
+
print "\nExecuting Instruction: #{redacted_instruction}"
|
94
114
|
browser.instance_eval(instruction.to_s.scrub.strip.chomp)
|
95
115
|
end
|
96
116
|
end
|
97
117
|
|
98
|
-
PWN::Plugins::
|
118
|
+
PWN::Plugins::Zaproxy.spider(zap_obj: zap_obj, target_url: target_url) if spider
|
119
|
+
PWN::Plugins::Zaproxy.active_scan(
|
99
120
|
zap_obj: zap_obj,
|
100
|
-
|
101
|
-
)
|
102
|
-
|
103
|
-
PWN::Plugins::OwaspZap.active_scan(
|
104
|
-
zap_obj: zap_obj,
|
105
|
-
target: target_url
|
121
|
+
target_url: target_url
|
106
122
|
)
|
107
123
|
|
108
124
|
# Generate all Report Types
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
report_type = 'html'
|
113
|
-
when 2
|
114
|
-
report_type = 'markdown'
|
115
|
-
when 3
|
116
|
-
report_type = 'xml'
|
117
|
-
end
|
118
|
-
|
119
|
-
report_path = PWN::Plugins::OwaspZap.generate_report(
|
125
|
+
report_types = %i[html markdown xml]
|
126
|
+
report_types.each do |report_type|
|
127
|
+
report_path = PWN::Plugins::Zaproxy.generate_scan_report(
|
120
128
|
zap_obj: zap_obj,
|
121
129
|
output_dir: output_dir,
|
122
130
|
report_type: report_type
|
@@ -125,10 +133,10 @@ begin
|
|
125
133
|
logger.info("Report can be found here: #{report_path}")
|
126
134
|
end
|
127
135
|
|
128
|
-
PWN::Plugins::
|
136
|
+
PWN::Plugins::Zaproxy.stop(zap_obj: zap_obj)
|
129
137
|
rescue StandardError => e
|
130
138
|
raise e
|
131
139
|
ensure
|
132
|
-
PWN::Plugins::
|
140
|
+
PWN::Plugins::Zaproxy.stop(zap_obj: zap_obj) unless zap_obj.nil?
|
133
141
|
browser_obj = PWN::Plugins::TransparentBrowser.close(browser_obj: browser_obj) unless browser_obj.nil?
|
134
142
|
end
|
@@ -879,13 +879,13 @@ module PWN
|
|
879
879
|
end
|
880
880
|
|
881
881
|
# Supported Method Parameters::
|
882
|
-
# active_scan_url_arr = PWN::Plugins::BurpSuite.
|
882
|
+
# active_scan_url_arr = PWN::Plugins::BurpSuite.active_scan(
|
883
883
|
# burp_obj: 'required - burp_obj returned by #start method',
|
884
884
|
# target_url: 'required - target url to scan in sitemap (should be loaded & authenticated w/ burp_obj[:burp_browser])',
|
885
885
|
# exclude_paths: 'optional - array of paths to exclude from active scan (default: [])'
|
886
886
|
# )
|
887
887
|
|
888
|
-
public_class_method def self.
|
888
|
+
public_class_method def self.active_scan(opts = {})
|
889
889
|
burp_obj = opts[:burp_obj]
|
890
890
|
rest_browser = burp_obj[:rest_browser]
|
891
891
|
pwn_burp_api = burp_obj[:pwn_burp_api]
|
@@ -1016,9 +1016,9 @@ module PWN
|
|
1016
1016
|
# Supported Method Parameters::
|
1017
1017
|
# PWN::Plugins::BurpSuite.generate_scan_report(
|
1018
1018
|
# burp_obj: 'required - burp_obj returned by #start method',
|
1019
|
-
# target_url: 'required - target_url passed to #
|
1020
|
-
#
|
1021
|
-
#
|
1019
|
+
# target_url: 'required - target_url passed to #active_scan method',
|
1020
|
+
# output_dir: 'required - directory to save the report',
|
1021
|
+
# report_type: required - <:html|:xml>'
|
1022
1022
|
# )
|
1023
1023
|
|
1024
1024
|
public_class_method def self.generate_scan_report(opts = {})
|
@@ -1026,16 +1026,20 @@ module PWN
|
|
1026
1026
|
target_url = opts[:target_url]
|
1027
1027
|
rest_browser = burp_obj[:rest_browser]
|
1028
1028
|
pwn_burp_api = burp_obj[:pwn_burp_api]
|
1029
|
+
output_dir = opts[:output_dir]
|
1030
|
+
raise "ERROR: #{output_dir} does not exist." unless Dir.exist?(output_dir)
|
1031
|
+
|
1029
1032
|
report_type = opts[:report_type]
|
1030
|
-
# When pwn_burp begins to support XML report generation
|
1031
|
-
valid_report_types_arr = %i[
|
1032
|
-
html
|
1033
|
-
xml
|
1034
|
-
]
|
1035
1033
|
|
1036
|
-
|
1034
|
+
valid_report_types_arr = %i[html xml]
|
1035
|
+
raise "ERROR: INVALID Report Type => #{report_type}" unless valid_report_types_arr.include?(report_type)
|
1037
1036
|
|
1038
|
-
|
1037
|
+
case report_type
|
1038
|
+
when :html
|
1039
|
+
report_path = "#{output_dir}/burp_active_scan_results.html"
|
1040
|
+
when :xml
|
1041
|
+
report_path = "#{output_dir}/burp_active_scan_results.xml"
|
1042
|
+
end
|
1039
1043
|
|
1040
1044
|
scheme = URI.parse(target_url).scheme
|
1041
1045
|
host = URI.parse(target_url).host
|
@@ -1058,7 +1062,7 @@ module PWN
|
|
1058
1062
|
"http://#{pwn_burp_api}/scanreport/#{report_type.to_s.upcase}/#{report_url}"
|
1059
1063
|
)
|
1060
1064
|
|
1061
|
-
File.open(
|
1065
|
+
File.open(report_path, 'w') do |f|
|
1062
1066
|
f.puts(report_resp.body.gsub("\r\n", "\n"))
|
1063
1067
|
end
|
1064
1068
|
rescue RestClient::BadRequest => e
|
@@ -1198,7 +1202,7 @@ module PWN
|
|
1198
1202
|
comment: 'optional - comment for the sitemap entry (default: \"\")',
|
1199
1203
|
)
|
1200
1204
|
|
1201
|
-
active_scan_url_arr = #{self}.
|
1205
|
+
active_scan_url_arr = #{self}.active_scan(
|
1202
1206
|
burp_obj: 'required - burp_obj returned by #start method',
|
1203
1207
|
target_url: 'required - target url to scan in sitemap (should be loaded & authenticated w/ burp_obj[:burp_browser])',
|
1204
1208
|
exclude_paths: 'optional - array of paths to exclude from active scan (default: [])'
|
@@ -1210,9 +1214,9 @@ module PWN
|
|
1210
1214
|
|
1211
1215
|
#{self}.generate_scan_report(
|
1212
1216
|
burp_obj: 'required - burp_obj returned by #start method',
|
1213
|
-
target_url: 'required - target_url passed to #
|
1214
|
-
|
1215
|
-
|
1217
|
+
target_url: 'required - target_url passed to #active_scan method',
|
1218
|
+
output_dir: 'required - directory to save the report',
|
1219
|
+
report_type: 'required - <:html|:xml>'
|
1216
1220
|
)
|
1217
1221
|
|
1218
1222
|
#{self}.stop(
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'cgi'
|
3
4
|
require 'pty'
|
4
5
|
require 'securerandom'
|
5
6
|
require 'json'
|
@@ -9,7 +10,7 @@ module PWN
|
|
9
10
|
module Plugins
|
10
11
|
# This plugin converts images to readable text
|
11
12
|
# TODO: Convert all rest requests to POST instead of GET
|
12
|
-
module
|
13
|
+
module Zaproxy
|
13
14
|
@@logger = PWN::Plugins::PWNLogger.create
|
14
15
|
|
15
16
|
# Supported Method Parameters::
|
@@ -30,12 +31,10 @@ module PWN
|
|
30
31
|
end
|
31
32
|
params = opts[:params]
|
32
33
|
http_body = opts[:http_body].to_s.scrub
|
33
|
-
|
34
|
-
|
35
|
-
base_zap_api_uri = "http://#{host}:#{port}"
|
34
|
+
zap_rest_api = zap_obj[:zap_rest_api]
|
35
|
+
base_zap_api_uri = "http://#{zap_rest_api}"
|
36
36
|
|
37
|
-
|
38
|
-
rest_client = browser_obj[:browser]::Request
|
37
|
+
rest_client = zap_obj[:rest_browser]::Request
|
39
38
|
|
40
39
|
case http_method
|
41
40
|
when :get
|
@@ -72,10 +71,11 @@ module PWN
|
|
72
71
|
end
|
73
72
|
|
74
73
|
# Supported Method Parameters::
|
75
|
-
# zap_obj = PWN::Plugins::
|
74
|
+
# zap_obj = PWN::Plugins::Zaproxy.start(
|
76
75
|
# api_key: 'required - api key for API authorization',
|
77
76
|
# zap_bin_path: 'optional - path to zap.sh file'
|
78
77
|
# headless: 'optional - run zap headless if set to true',
|
78
|
+
# browser_type: 'optional - defaults to :firefox. See PWN::Plugins::TransparentBrowser.help for a list of types',
|
79
79
|
# proxy: 'optional - change local zap proxy listener (defaults to http://127.0.0.1:<Random 1024-65535>)',
|
80
80
|
# )
|
81
81
|
|
@@ -84,14 +84,9 @@ module PWN
|
|
84
84
|
api_key = opts[:api_key].to_s.scrub.strip.chomp
|
85
85
|
zap_obj[:api_key] = api_key
|
86
86
|
|
87
|
-
headless = if opts[:headless]
|
88
|
-
true
|
89
|
-
else
|
90
|
-
false
|
91
|
-
end
|
92
|
-
|
93
87
|
if opts[:zap_bin_path]
|
94
|
-
zap_bin_path = opts[:zap_bin_path]
|
88
|
+
zap_bin_path = opts[:zap_bin_path]
|
89
|
+
raise "ERROR: zap.sh not found at #{zap_bin_path}" unless File.exist?(zap_bin_path)
|
95
90
|
else
|
96
91
|
underlying_os = PWN::Plugins::DetectOS.type
|
97
92
|
|
@@ -108,21 +103,36 @@ module PWN
|
|
108
103
|
zap_bin = File.basename(zap_bin_path)
|
109
104
|
zap_dir = File.dirname(zap_bin_path)
|
110
105
|
|
106
|
+
headless = opts[:headless] || false
|
107
|
+
browser_type = opts[:browser_type] ||= :firefox
|
108
|
+
zap_ip = opts[:zap_ip] ||= '127.0.0.1'
|
109
|
+
zap_port = opts[:zap_port] ||= PWN::Plugins::Sock.get_random_unused_port
|
110
|
+
|
111
|
+
zap_rest_ip = opts[:pwn_zap_ip] ||= '127.0.0.1'
|
112
|
+
zap_rest_port = opts[:pwn_zap_port] ||= PWN::Plugins::Sock.get_random_unused_port
|
113
|
+
|
111
114
|
if headless
|
112
|
-
|
115
|
+
zaproxy_cmd = "cd #{zap_dir} && ./#{zap_bin} -daemon"
|
113
116
|
else
|
114
|
-
|
117
|
+
zaproxy_cmd = "cd #{zap_dir} && ./#{zap_bin}"
|
115
118
|
end
|
116
119
|
|
117
|
-
|
120
|
+
browser_obj1 = PWN::Plugins::TransparentBrowser.open(browser_type: :rest)
|
121
|
+
rest_browser = browser_obj1[:browser]
|
118
122
|
|
119
|
-
|
120
|
-
|
123
|
+
zap_obj[:mitm_proxy] = "#{zap_ip}:#{zap_port}"
|
124
|
+
zap_obj[:zap_rest_api] = zap_obj[:mitm_proxy]
|
125
|
+
zap_obj[:rest_browser] = rest_browser
|
121
126
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
127
|
+
zaproxy_cmd = "#{zaproxy_cmd} -host #{zap_ip} -port #{zap_port}"
|
128
|
+
|
129
|
+
browser_obj2 = PWN::Plugins::TransparentBrowser.open(
|
130
|
+
browser_type: browser_type,
|
131
|
+
proxy: "http://#{zap_obj[:mitm_proxy]}",
|
132
|
+
devtools: true
|
133
|
+
)
|
134
|
+
|
135
|
+
zap_obj[:zap_browser] = browser_obj2
|
126
136
|
|
127
137
|
pwn_stdout_log_path = "/tmp/pwn_plugins_owasp-#{SecureRandom.hex}.log"
|
128
138
|
pwn_stdout_log = File.new(pwn_stdout_log_path, 'w')
|
@@ -131,7 +141,7 @@ module PWN
|
|
131
141
|
pwn_stdout_log.fsync
|
132
142
|
|
133
143
|
fork_pid = Process.fork do
|
134
|
-
PTY.spawn(
|
144
|
+
PTY.spawn(zaproxy_cmd) do |stdout, _stdin, _pid|
|
135
145
|
stdout.each do |line|
|
136
146
|
puts line
|
137
147
|
pwn_stdout_log.puts line
|
@@ -176,25 +186,57 @@ module PWN
|
|
176
186
|
end
|
177
187
|
|
178
188
|
# Supported Method Parameters::
|
179
|
-
# PWN::Plugins::
|
189
|
+
# PWN::Plugins::Zaproxy.import_openapi_to_sitemap(
|
190
|
+
# zap_obj: 'required - zap_obj returned from #open method',
|
191
|
+
# openapi_spec: 'required - path to OpenAPI JSON or YAML spec file'
|
192
|
+
# )
|
193
|
+
|
194
|
+
public_class_method def self.import_openapi_to_sitemap(opts = {})
|
195
|
+
zap_obj = opts[:zap_obj]
|
196
|
+
api_key = zap_obj[:api_key].to_s.scrub
|
197
|
+
openapi_spec = opts[:openapi_spec]
|
198
|
+
raise "ERROR: openapi_spec file #{openapi_spec} does not exist" unless File.exist?(openapi_spec)
|
199
|
+
|
200
|
+
openapi_spec_root = File.dirname(openapi_spec)
|
201
|
+
Dir.chdir(openapi_spec_root)
|
202
|
+
|
203
|
+
params = {
|
204
|
+
apikey: api_key,
|
205
|
+
file: openapi_spec
|
206
|
+
}
|
207
|
+
|
208
|
+
response = zap_rest_call(
|
209
|
+
zap_obj: zap_obj,
|
210
|
+
rest_call: 'JSON/openapi/action/importFile/',
|
211
|
+
params: params
|
212
|
+
)
|
213
|
+
|
214
|
+
JSON.parse(response.body, symbolize_names: true)
|
215
|
+
rescue StandardError, SystemExit, Interrupt => e
|
216
|
+
stop(zap_obj) unless zap_obj.nil?
|
217
|
+
raise e
|
218
|
+
end
|
219
|
+
|
220
|
+
# Supported Method Parameters::
|
221
|
+
# PWN::Plugins::Zaproxy.spider(
|
180
222
|
# zap_obj: 'required - zap_obj returned from #open method',
|
181
|
-
#
|
223
|
+
# target_url: 'required - url to spider'
|
182
224
|
# )
|
183
225
|
|
184
226
|
public_class_method def self.spider(opts = {})
|
185
227
|
zap_obj = opts[:zap_obj]
|
186
|
-
|
228
|
+
target_url = opts[:target_url].to_s.scrub
|
187
229
|
api_key = zap_obj[:api_key].to_s.scrub
|
188
230
|
|
189
|
-
# target_domain_name = URI.parse(
|
231
|
+
# target_domain_name = URI.parse(target_url).host
|
190
232
|
|
191
233
|
params = {
|
192
234
|
apikey: api_key,
|
193
|
-
url:
|
235
|
+
url: target_url,
|
194
236
|
maxChildren: 9,
|
195
237
|
recurse: 3,
|
196
238
|
contextName: '',
|
197
|
-
subtreeOnly:
|
239
|
+
subtreeOnly: target_url
|
198
240
|
}
|
199
241
|
|
200
242
|
response = zap_rest_call(
|
@@ -229,26 +271,26 @@ module PWN
|
|
229
271
|
end
|
230
272
|
|
231
273
|
# Supported Method Parameters::
|
232
|
-
# PWN::Plugins::
|
274
|
+
# PWN::Plugins::Zaproxy.active_scan(
|
233
275
|
# zap_obj: 'required - zap_obj returned from #open method',
|
234
|
-
#
|
276
|
+
# target_url: 'required - url to scan',
|
235
277
|
# scan_policy: 'optional - scan policy to use (defaults to Default Policy)'
|
236
278
|
# )
|
237
279
|
|
238
280
|
public_class_method def self.active_scan(opts = {})
|
239
281
|
zap_obj = opts[:zap_obj]
|
240
282
|
api_key = zap_obj[:api_key].to_s.scrub
|
241
|
-
|
283
|
+
target_url = opts[:target_url]
|
242
284
|
if opts[:scan_policy].nil?
|
243
285
|
scan_policy = 'Default Policy'
|
244
286
|
else
|
245
287
|
scan_policy = opts[:scan_policy].to_s.scrub.strip.chomp
|
246
288
|
end
|
247
289
|
|
248
|
-
# TODO: Implement adding
|
290
|
+
# TODO: Implement adding target_url to scope so that inScopeOnly can be changed to true
|
249
291
|
params = {
|
250
292
|
apikey: api_key,
|
251
|
-
url:
|
293
|
+
url: target_url,
|
252
294
|
recurse: true,
|
253
295
|
inScopeOnly: true,
|
254
296
|
scanPolicyName: scan_policy
|
@@ -286,19 +328,19 @@ module PWN
|
|
286
328
|
end
|
287
329
|
|
288
330
|
# Supported Method Parameters::
|
289
|
-
# PWN::Plugins::
|
331
|
+
# PWN::Plugins::Zaproxy.alerts(
|
290
332
|
# zap_obj: 'required - zap_obj returned from #open method',
|
291
|
-
#
|
333
|
+
# target_url: 'required - base url to return alerts'
|
292
334
|
# )
|
293
335
|
|
294
336
|
public_class_method def self.alerts(opts = {})
|
295
337
|
zap_obj = opts[:zap_obj]
|
296
338
|
api_key = zap_obj[:api_key].to_s.scrub
|
297
|
-
|
339
|
+
target_url = opts[:target_url]
|
298
340
|
|
299
341
|
params = {
|
300
342
|
apikey: api_key,
|
301
|
-
url:
|
343
|
+
url: target_url
|
302
344
|
}
|
303
345
|
|
304
346
|
response = zap_rest_call(
|
@@ -314,36 +356,39 @@ module PWN
|
|
314
356
|
end
|
315
357
|
|
316
358
|
# Supported Method Parameters::
|
317
|
-
# report_path = PWN::Plugins::
|
359
|
+
# report_path = PWN::Plugins::Zaproxy.generate_scan_report(
|
318
360
|
# zap_obj: 'required - zap_obj returned from #open method',
|
319
361
|
# output_dir: 'required - directory to save report',
|
320
|
-
# report_type: 'required -
|
362
|
+
# report_type: 'required - <:html|:markdown|:xml>'
|
321
363
|
# )
|
322
364
|
|
323
|
-
public_class_method def self.
|
365
|
+
public_class_method def self.generate_scan_report(opts = {})
|
324
366
|
zap_obj = opts[:zap_obj]
|
325
367
|
api_key = zap_obj[:api_key].to_s.scrub
|
326
|
-
output_dir = opts[:output_dir]
|
327
|
-
|
368
|
+
output_dir = opts[:output_dir]
|
369
|
+
raise "ERROR: output_dir #{output_dir} does not exist." unless Dir.exist?(output_dir)
|
328
370
|
|
329
|
-
|
330
|
-
|
331
|
-
|
371
|
+
report_type = opts[:report_type]
|
372
|
+
|
373
|
+
valid_report_types_arr = %i[html markdown xml]
|
374
|
+
raise "ERROR: Invalid report_type => #{report_type}" unless valid_report_types_arr.include?(report_type)
|
332
375
|
|
333
376
|
case report_type
|
334
377
|
when :html
|
335
|
-
report_path = "#{output_dir}/
|
378
|
+
report_path = "#{output_dir}/zaproxy_active_scan_results.html"
|
336
379
|
rest_call = 'OTHER/core/other/htmlreport/'
|
337
380
|
when :markdown
|
338
|
-
report_path = "#{output_dir}/
|
381
|
+
report_path = "#{output_dir}/zaproxy_active_scan_results.md"
|
339
382
|
rest_call = 'OTHER/core/other/mdreport/'
|
340
383
|
when :xml
|
341
|
-
report_path = "#{output_dir}/
|
384
|
+
report_path = "#{output_dir}/zaproxy_active_scan_results.xml"
|
342
385
|
rest_call = 'OTHER/core/other/xmlreport/'
|
343
|
-
else
|
344
|
-
raise @@logger.error("ERROR: Unsupported report type: #{report_type}\nValid report types are <html|markdown|xml>")
|
345
386
|
end
|
346
387
|
|
388
|
+
params = {
|
389
|
+
apikey: api_key
|
390
|
+
}
|
391
|
+
|
347
392
|
response = zap_rest_call(
|
348
393
|
zap_obj: zap_obj,
|
349
394
|
rest_call: rest_call,
|
@@ -361,7 +406,7 @@ module PWN
|
|
361
406
|
end
|
362
407
|
|
363
408
|
# Supported Method Parameters::
|
364
|
-
# PWN::Plugins::
|
409
|
+
# PWN::Plugins::Zaproxy.breakpoint(
|
365
410
|
# zap_obj: 'required - zap_obj returned from #open method',
|
366
411
|
# regex_type: 'required - :url, :request_header, :request_body, :response_header or :response_body',
|
367
412
|
# regex_pattern: 'required - regex pattern to search for respective regex_type',
|
@@ -395,7 +440,7 @@ module PWN
|
|
395
440
|
end
|
396
441
|
|
397
442
|
# Supported Method Parameters::
|
398
|
-
# PWN::Plugins::
|
443
|
+
# PWN::Plugins::Zaproxy.tamper(
|
399
444
|
# zap_obj: 'required - zap_obj returned from #open method',
|
400
445
|
# domain: 'required - FQDN to tamper (e.g. test.domain.local)',
|
401
446
|
# enabled: 'optional - boolean (defaults to true)'
|
@@ -427,42 +472,7 @@ module PWN
|
|
427
472
|
end
|
428
473
|
|
429
474
|
# Supported Method Parameters::
|
430
|
-
# PWN::Plugins::
|
431
|
-
# zap_obj: 'required - zap_obj returned from #open method',
|
432
|
-
# spec: 'required - path to OpenAPI spec file (e.g. /path/to/openapi.yaml)',
|
433
|
-
# target: 'required - target URL to ovverride the service URL in the OpenAPI spec (e.g. https://fq.dn)',
|
434
|
-
# context_id: 'optional - ID of the ZAP context (Defaults to first context, if any)',
|
435
|
-
# user_id: 'optional - ID of the ZAP user (Defaults to first user, if any)'
|
436
|
-
# )
|
437
|
-
|
438
|
-
public_class_method def self.import_openapi_spec_file(opts = {})
|
439
|
-
zap_obj = opts[:zap_obj]
|
440
|
-
api_key = zap_obj[:api_key].to_s.scrub
|
441
|
-
spec = opts[:spec]
|
442
|
-
target = opts[:target]
|
443
|
-
context_id = opts[:context_id]
|
444
|
-
user_id = opts[:user_id]
|
445
|
-
|
446
|
-
params = {
|
447
|
-
apikey: api_key,
|
448
|
-
file: spec,
|
449
|
-
target: target,
|
450
|
-
contextId: context_id,
|
451
|
-
user_id: user_id
|
452
|
-
}
|
453
|
-
|
454
|
-
zap_rest_call(
|
455
|
-
zap_obj: zap_obj,
|
456
|
-
rest_call: "JSON/break/action/openapi/?zapapiformat=JSON&apikey=#{api_key}",
|
457
|
-
params: params
|
458
|
-
)
|
459
|
-
rescue StandardError, SystemExit, Interrupt => e
|
460
|
-
stop(zap_obj) unless zap_obj.nil?
|
461
|
-
raise e
|
462
|
-
end
|
463
|
-
|
464
|
-
# Supported Method Parameters::
|
465
|
-
# watir_resp = PWN::Plugins::OwaspZap.request(
|
475
|
+
# watir_resp = PWN::Plugins::Zaproxy.request(
|
466
476
|
# zap_obj: 'required - zap_obj returned from #open method',
|
467
477
|
# browser_obj: 'required - browser_obj w/ browser_type: :firefox||:headless returned from #open method',
|
468
478
|
# instruction: 'required - watir instruction to make (e.g. button(text: "Google Search").click)'
|
@@ -502,14 +512,28 @@ module PWN
|
|
502
512
|
end
|
503
513
|
|
504
514
|
# Supported Method Parameters::
|
505
|
-
# PWN::Plugins::
|
506
|
-
# :
|
515
|
+
# PWN::Plugins::Zaproxy.stop(
|
516
|
+
# zap_obj: 'required - zap_obj returned from #open method'
|
507
517
|
# )
|
508
518
|
|
509
519
|
public_class_method def self.stop(opts = {})
|
510
520
|
zap_obj = opts[:zap_obj]
|
511
|
-
|
512
|
-
|
521
|
+
api_key = zap_obj[:api_key]
|
522
|
+
browser_obj = zap_obj[:zap_browser]
|
523
|
+
rest_browser = zap_obj[:rest_browser]
|
524
|
+
|
525
|
+
browser_obj = PWN::Plugins::TransparentBrowser.close(browser_obj: browser_obj)
|
526
|
+
|
527
|
+
params = { apikey: api_key }
|
528
|
+
zap_rest_call(
|
529
|
+
zap_obj: zap_obj,
|
530
|
+
rest_call: 'JSON/core/action/shutdown/',
|
531
|
+
params: params
|
532
|
+
)
|
533
|
+
|
534
|
+
zap_obj = nil
|
535
|
+
rescue StandardError, SystemExit, Interrupt => e
|
536
|
+
stop(zap_obj) unless zap_obj.nil?
|
513
537
|
raise e
|
514
538
|
end
|
515
539
|
|
@@ -531,28 +555,32 @@ module PWN
|
|
531
555
|
headless: 'optional - run zap headless if set to true',
|
532
556
|
proxy: 'optional - change local zap proxy listener (defaults to http://127.0.0.1:<Random 1024-65535>)'
|
533
557
|
)
|
534
|
-
puts zap_obj.public_methods
|
535
558
|
|
536
559
|
#{self}.spider(
|
537
560
|
zap_obj: 'required - zap_obj returned from #open method',
|
538
|
-
|
561
|
+
target_url: 'required - url to spider'
|
562
|
+
)
|
563
|
+
|
564
|
+
#{self}.import_openapi_to_sitemap(
|
565
|
+
zap_obj: 'required - zap_obj returned from #open method',
|
566
|
+
openapi_spec: 'required - path to OpenAPI JSON or YAML spec file'
|
539
567
|
)
|
540
568
|
|
541
569
|
#{self}.active_scan(
|
542
570
|
zap_obj: 'required - zap_obj returned from #open method'
|
543
|
-
|
571
|
+
target_url: 'required - url to scan',
|
544
572
|
scan_policy: 'optional - scan policy to use (defaults to Default Policy)'
|
545
573
|
)
|
546
574
|
|
547
575
|
json_alerts = #{self}.alerts(
|
548
576
|
zap_obj: 'required - zap_obj returned from #open method'
|
549
|
-
|
577
|
+
target_url: 'required - base url to return alerts'
|
550
578
|
)
|
551
579
|
|
552
|
-
report_path = #{self}.
|
580
|
+
report_path = #{self}.generate_scan_report(
|
553
581
|
zap_obj: 'required - zap_obj returned from #open method',
|
554
582
|
output_dir: 'required - directory to save report',
|
555
|
-
report_type: 'required -
|
583
|
+
report_type: 'required - <:html|:markdown|:xml>'
|
556
584
|
)
|
557
585
|
|
558
586
|
#{self}.breakpoint(
|
data/lib/pwn/plugins.rb
CHANGED
@@ -51,7 +51,6 @@ module PWN
|
|
51
51
|
autoload :OpenAI, 'pwn/plugins/open_ai'
|
52
52
|
autoload :OpenAPI, 'pwn/plugins/open_api'
|
53
53
|
autoload :OpenVAS, 'pwn/plugins/openvas'
|
54
|
-
autoload :OwaspZap, 'pwn/plugins/owasp_zap'
|
55
54
|
autoload :Packet, 'pwn/plugins/packet'
|
56
55
|
autoload :PDFParse, 'pwn/plugins/pdf_parse'
|
57
56
|
autoload :Pony, 'pwn/plugins/pony'
|
@@ -77,6 +76,7 @@ module PWN
|
|
77
76
|
autoload :Voice, 'pwn/plugins/voice'
|
78
77
|
autoload :Vsphere, 'pwn/plugins/vsphere'
|
79
78
|
autoload :XXD, 'pwn/plugins/xxd'
|
79
|
+
autoload :Zaproxy, 'pwn/plugins/zaproxy'
|
80
80
|
|
81
81
|
# Display a List of Every PWN::Plugins Module
|
82
82
|
|
data/lib/pwn/version.rb
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe PWN::Plugins::
|
5
|
+
describe PWN::Plugins::Zaproxy do
|
6
6
|
it 'should display information for authors' do
|
7
|
-
authors_response = PWN::Plugins::
|
7
|
+
authors_response = PWN::Plugins::Zaproxy
|
8
8
|
expect(authors_response).to respond_to :authors
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'should display information for existing help method' do
|
12
|
-
help_response = PWN::Plugins::
|
12
|
+
help_response = PWN::Plugins::Zaproxy
|
13
13
|
expect(help_response).to respond_to :help
|
14
14
|
end
|
15
15
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pwn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.399
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0day Inc.
|
@@ -1308,7 +1308,6 @@ executables:
|
|
1308
1308
|
- pwn_nexpose
|
1309
1309
|
- pwn_nmap_discover_tcp_udp
|
1310
1310
|
- pwn_openvas_vulnscan
|
1311
|
-
- pwn_owasp_zap_active_scan
|
1312
1311
|
- pwn_pastebin_sample_filter
|
1313
1312
|
- pwn_phone
|
1314
1313
|
- pwn_rdoc_to_jsonl
|
@@ -1324,6 +1323,8 @@ executables:
|
|
1324
1323
|
- pwn_www_checkip
|
1325
1324
|
- pwn_www_uri_buster
|
1326
1325
|
- pwn_xss_dom_vectors
|
1326
|
+
- pwn_zaproxy_active_rest_api_scan
|
1327
|
+
- pwn_zaproxy_active_scan
|
1327
1328
|
extensions: []
|
1328
1329
|
extra_rdoc_files: []
|
1329
1330
|
files:
|
@@ -1378,7 +1379,6 @@ files:
|
|
1378
1379
|
- bin/pwn_nexpose
|
1379
1380
|
- bin/pwn_nmap_discover_tcp_udp
|
1380
1381
|
- bin/pwn_openvas_vulnscan
|
1381
|
-
- bin/pwn_owasp_zap_active_scan
|
1382
1382
|
- bin/pwn_pastebin_sample_filter
|
1383
1383
|
- bin/pwn_phone
|
1384
1384
|
- bin/pwn_rdoc_to_jsonl
|
@@ -1394,6 +1394,8 @@ files:
|
|
1394
1394
|
- bin/pwn_www_checkip
|
1395
1395
|
- bin/pwn_www_uri_buster
|
1396
1396
|
- bin/pwn_xss_dom_vectors
|
1397
|
+
- bin/pwn_zaproxy_active_rest_api_scan
|
1398
|
+
- bin/pwn_zaproxy_active_scan
|
1397
1399
|
- build_pwn_gem.sh
|
1398
1400
|
- documentation/PWN.png
|
1399
1401
|
- documentation/PWN_Contributors_and_Users.png
|
@@ -1873,7 +1875,6 @@ files:
|
|
1873
1875
|
- lib/pwn/plugins/ocr.rb
|
1874
1876
|
- lib/pwn/plugins/open_api.rb
|
1875
1877
|
- lib/pwn/plugins/openvas.rb
|
1876
|
-
- lib/pwn/plugins/owasp_zap.rb
|
1877
1878
|
- lib/pwn/plugins/packet.rb
|
1878
1879
|
- lib/pwn/plugins/pdf_parse.rb
|
1879
1880
|
- lib/pwn/plugins/pony.rb
|
@@ -1900,6 +1901,7 @@ files:
|
|
1900
1901
|
- lib/pwn/plugins/voice.rb
|
1901
1902
|
- lib/pwn/plugins/vsphere.rb
|
1902
1903
|
- lib/pwn/plugins/xxd.rb
|
1904
|
+
- lib/pwn/plugins/zaproxy.rb
|
1903
1905
|
- lib/pwn/reports.rb
|
1904
1906
|
- lib/pwn/reports/fuzz.rb
|
1905
1907
|
- lib/pwn/reports/html_footer.rb
|
@@ -2217,7 +2219,6 @@ files:
|
|
2217
2219
|
- spec/lib/pwn/plugins/ocr_spec.rb
|
2218
2220
|
- spec/lib/pwn/plugins/open_api_spec.rb
|
2219
2221
|
- spec/lib/pwn/plugins/openvas_spec.rb
|
2220
|
-
- spec/lib/pwn/plugins/owasp_zap_spec.rb
|
2221
2222
|
- spec/lib/pwn/plugins/packet_spec.rb
|
2222
2223
|
- spec/lib/pwn/plugins/pdf_parse_spec.rb
|
2223
2224
|
- spec/lib/pwn/plugins/pony_spec.rb
|
@@ -2244,6 +2245,7 @@ files:
|
|
2244
2245
|
- spec/lib/pwn/plugins/voice_spec.rb
|
2245
2246
|
- spec/lib/pwn/plugins/vsphere_spec.rb
|
2246
2247
|
- spec/lib/pwn/plugins/xxd_spec.rb
|
2248
|
+
- spec/lib/pwn/plugins/zaproxy_spec.rb
|
2247
2249
|
- spec/lib/pwn/plugins_spec.rb
|
2248
2250
|
- spec/lib/pwn/reports/fuzz_spec.rb
|
2249
2251
|
- spec/lib/pwn/reports/html_footer_spec.rb
|