pwn 0.5.405 → 0.5.406
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/lib/pwn/plugins/burp_suite.rb +26 -1
- data/lib/pwn/plugins/zaproxy.rb +128 -138
- data/lib/pwn/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a4875ea87dd3f0605bc2ac889621fc124d43016086b2ef914a71dd8104879ff
|
4
|
+
data.tar.gz: 68addc891a15eea06b39b9e575fd98ce3b9e5a4d3e490c20bdfbe138699b8f2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b9211d610152046dec2ddcb6c96687085ae3004d104713064831c511e7ce1aa490c5f4e69c12066bc6d11e4f81b47dd90e6b289d5df88a6a5d65abb67d24dd7
|
7
|
+
data.tar.gz: e43570d37f21c2a3dc4008da1b42ee0aa379f4aebe5880dd47bb1b4c881a767db74a85b4121a125fbcdb67a4fc7526e239dfb595fd2327dbc0742c67e76027c7
|
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.406]: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.406]: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.406]: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:
|
@@ -450,7 +450,7 @@ module PWN
|
|
450
450
|
raise 'ERROR: burp_obj parameter is required' unless burp_obj.is_a?(Hash)
|
451
451
|
|
452
452
|
openapi_spec = opts[:openapi_spec]
|
453
|
-
raise 'ERROR: openapi_spec parameter
|
453
|
+
raise 'ERROR: openapi_spec parameter is required' if openapi_spec.nil?
|
454
454
|
|
455
455
|
additional_http_headers = opts[:additional_http_headers] ||= {}
|
456
456
|
raise 'ERROR: additional_http_headers must be a Hash' unless additional_http_headers.is_a?(Hash)
|
@@ -1013,6 +1013,31 @@ module PWN
|
|
1013
1013
|
raise e
|
1014
1014
|
end
|
1015
1015
|
|
1016
|
+
# Supported Method Parameters::
|
1017
|
+
# repeater_id = PWN::Plugins::BurpSuite.find_sitemap_entries(
|
1018
|
+
# burp_obj: 'required - burp_obj returned by #start method',
|
1019
|
+
# search_string: 'required - string to search for in the sitemap entries'
|
1020
|
+
# )
|
1021
|
+
|
1022
|
+
public_class_method def self.find_sitemap_entries(opts = {})
|
1023
|
+
burp_obj = opts[:burp_obj]
|
1024
|
+
raise 'ERROR: burp_obj parameter is required' unless burp_obj.is_a?(Hash)
|
1025
|
+
|
1026
|
+
search_string = opts[:search_string]
|
1027
|
+
raise 'ERROR: search_string parameter is required' if search_string.nil?
|
1028
|
+
|
1029
|
+
rest_browser = burp_obj[:rest_browser]
|
1030
|
+
mitm_rest_api = burp_obj[:mitm_rest_api]
|
1031
|
+
|
1032
|
+
json_sitemap = get_sitemap(burp_obj: burp_obj)
|
1033
|
+
matching_entries = json_sitemap.select do |entry|
|
1034
|
+
decoded_request = Base64.strict_decode64(entry[:request])
|
1035
|
+
decoded_request.include?(search_string)
|
1036
|
+
end
|
1037
|
+
rescue StandardError => e
|
1038
|
+
raise e
|
1039
|
+
end
|
1040
|
+
|
1016
1041
|
# Supported Method Parameters::
|
1017
1042
|
# repeater_id = PWN::Plugins::BurpSuite.add_repeater_tab(
|
1018
1043
|
# burp_obj: 'required - burp_obj returned by #start method',
|
data/lib/pwn/plugins/zaproxy.rb
CHANGED
@@ -171,147 +171,16 @@ module PWN
|
|
171
171
|
raise e
|
172
172
|
end
|
173
173
|
|
174
|
-
# Supported Method Parameters::
|
175
|
-
# PWN::Plugins::Zaproxy.add_to_scope(
|
176
|
-
# zap_obj: 'required - zap_obj returned from #open method',
|
177
|
-
# target_regex: 'required - url regex to add to scope (e.g. https://test.domain.local.*)',
|
178
|
-
# context_name: 'optional - context name to add target_regex to (defaults to Default Context)'
|
179
|
-
# )
|
180
|
-
|
181
|
-
public_class_method def self.add_to_scope(opts = {})
|
182
|
-
zap_obj = opts[:zap_obj]
|
183
|
-
api_key = zap_obj[:api_key].to_s.scrub
|
184
|
-
target_regex = opts[:target_regex]
|
185
|
-
raise 'ERROR: target_url must be provided' if target_regex.nil?
|
186
|
-
|
187
|
-
context_name = opts[:context_name] ||= 'Default Context'
|
188
|
-
|
189
|
-
params = {
|
190
|
-
apikey: api_key,
|
191
|
-
contextName: context_name,
|
192
|
-
regex: target_regex
|
193
|
-
}
|
194
|
-
|
195
|
-
response = zap_rest_call(
|
196
|
-
zap_obj: zap_obj,
|
197
|
-
rest_call: 'JSON/context/action/includeInContext/',
|
198
|
-
params: params
|
199
|
-
)
|
200
|
-
|
201
|
-
JSON.parse(response.body, symbolize_names: true)
|
202
|
-
rescue StandardError, SystemExit, Interrupt => e
|
203
|
-
stop(zap_obj: zap_obj) unless zap_obj.nil?
|
204
|
-
raise e
|
205
|
-
end
|
206
|
-
|
207
|
-
# Supported Method Parameters::
|
208
|
-
# PWN::Plugins::Zaproxy.add_requester_tab(
|
209
|
-
# zap_obj: 'required - zap_obj returned from #open method',
|
210
|
-
# request: 'required - base64 encoded HTTP request (e.g. from #get_sitemap method)'
|
211
|
-
# )
|
212
|
-
|
213
|
-
public_class_method def self.add_requester_tab(opts = {})
|
214
|
-
zap_obj = opts[:zap_obj]
|
215
|
-
api_key = zap_obj[:api_key].to_s.scrub
|
216
|
-
request = opts[:request]
|
217
|
-
|
218
|
-
dec_request = Base64.strict_decode64(request).force_encoding('ASCII-8BIT')
|
219
|
-
|
220
|
-
# Parse the full request string
|
221
|
-
parts = dec_request.split("\r\n\r\n", 2)
|
222
|
-
headers_part = parts[0]
|
223
|
-
body = parts[1] || ''
|
224
|
-
|
225
|
-
header_lines = headers_part.split("\r\n")
|
226
|
-
first_line = header_lines.shift
|
227
|
-
method, full_url, http_version = first_line.split
|
228
|
-
|
229
|
-
headers = []
|
230
|
-
header_lines.each do |line|
|
231
|
-
name, value = line.split(': ', 2)
|
232
|
-
headers << { name: name, value: value }
|
233
|
-
end
|
234
|
-
|
235
|
-
# Parse URL for queryString and adjust url
|
236
|
-
uri = URI.parse(full_url)
|
237
|
-
query_string = []
|
238
|
-
if uri.query
|
239
|
-
URI.decode_www_form(uri.query).each do |name, value|
|
240
|
-
query_string << { name: name, value: value }
|
241
|
-
end
|
242
|
-
end
|
243
|
-
url = "#{uri.scheme}://#{uri.host}"
|
244
|
-
url += ":#{uri.port}" if uri.port && uri.port != (uri.scheme == 'https' ? 443 : 80)
|
245
|
-
url += uri.path
|
246
|
-
|
247
|
-
# Determine content-type
|
248
|
-
content_type_header = headers.find { |h| h[:name].downcase == 'content-type' }
|
249
|
-
mime_type = content_type_header ? content_type_header[:value] : 'application/octet-stream'
|
250
|
-
|
251
|
-
# Handle postData
|
252
|
-
post_data = nil
|
253
|
-
methods_with_body = %w[POST PUT PATCH]
|
254
|
-
if methods_with_body.include?(method) && !body.empty?
|
255
|
-
post_data = {
|
256
|
-
mimeType: mime_type,
|
257
|
-
params: [],
|
258
|
-
text: body
|
259
|
-
}
|
260
|
-
|
261
|
-
temp_body = body.dup.force_encoding('UTF-8')
|
262
|
-
if temp_body.valid_encoding?
|
263
|
-
if mime_type.include?('application/x-www-form-urlencoded')
|
264
|
-
URI.decode_www_form(temp_body).each do |name, value|
|
265
|
-
post_data[:params] << { name: name, value: value }
|
266
|
-
end
|
267
|
-
end
|
268
|
-
else
|
269
|
-
post_data[:text] = Base64.encode64(body)
|
270
|
-
post_data[:encoding] = 'base64'
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
# Construct HAR request
|
275
|
-
har_request = {
|
276
|
-
method: method,
|
277
|
-
url: url,
|
278
|
-
httpVersion: http_version,
|
279
|
-
cookies: [],
|
280
|
-
headers: headers,
|
281
|
-
queryString: query_string,
|
282
|
-
headersSize: -1,
|
283
|
-
bodySize: -1
|
284
|
-
}
|
285
|
-
har_request[:postData] = post_data if post_data
|
286
|
-
|
287
|
-
har_json = JSON.generate(har_request)
|
288
|
-
|
289
|
-
params = {
|
290
|
-
apikey: api_key,
|
291
|
-
request: har_json,
|
292
|
-
followRedirects: 'true'
|
293
|
-
}
|
294
|
-
|
295
|
-
response = zap_rest_call(
|
296
|
-
zap_obj: zap_obj,
|
297
|
-
rest_call: 'OTHER/core/other/sendHarRequest/',
|
298
|
-
params: params
|
299
|
-
)
|
300
|
-
|
301
|
-
JSON.parse(response.body, symbolize_names: true)
|
302
|
-
rescue StandardError, SystemExit, Interrupt => e
|
303
|
-
stop(zap_obj: zap_obj) unless zap_obj.nil?
|
304
|
-
raise e
|
305
|
-
end
|
306
|
-
|
307
174
|
# Supported Method Parameters::
|
308
175
|
# json_sitemap = PWN::Plugins::Zaproxy.get_sitemap(
|
309
|
-
# zap_obj: 'required - zap_obj returned from #open method'
|
176
|
+
# zap_obj: 'required - zap_obj returned from #open method',
|
177
|
+
# return_as: 'optional - :base64 or :har (defaults to :base64)'
|
310
178
|
# )
|
311
179
|
|
312
180
|
public_class_method def self.get_sitemap(opts = {})
|
313
181
|
zap_obj = opts[:zap_obj]
|
314
182
|
api_key = zap_obj[:api_key].to_s.scrub
|
183
|
+
return_as = opts[:return_as] ||= :base64
|
315
184
|
|
316
185
|
entries = []
|
317
186
|
start = 0
|
@@ -333,6 +202,7 @@ module PWN
|
|
333
202
|
entries += new_entries
|
334
203
|
start += count
|
335
204
|
end
|
205
|
+
return entries if return_as == :har
|
336
206
|
|
337
207
|
# Deduplicate entries based on method + url
|
338
208
|
seen = Set.new
|
@@ -390,6 +260,119 @@ module PWN
|
|
390
260
|
raise e
|
391
261
|
end
|
392
262
|
|
263
|
+
# Supported Method Parameters::
|
264
|
+
# PWN::Plugins::Zaproxy.add_to_scope(
|
265
|
+
# zap_obj: 'required - zap_obj returned from #open method',
|
266
|
+
# target_regex: 'required - url regex to add to scope (e.g. https://test.domain.local.*)',
|
267
|
+
# context_name: 'optional - context name to add target_regex to (defaults to Default Context)'
|
268
|
+
# )
|
269
|
+
|
270
|
+
public_class_method def self.add_to_scope(opts = {})
|
271
|
+
zap_obj = opts[:zap_obj]
|
272
|
+
api_key = zap_obj[:api_key].to_s.scrub
|
273
|
+
target_regex = opts[:target_regex]
|
274
|
+
raise 'ERROR: target_url must be provided' if target_regex.nil?
|
275
|
+
|
276
|
+
context_name = opts[:context_name] ||= 'Default Context'
|
277
|
+
|
278
|
+
params = {
|
279
|
+
apikey: api_key,
|
280
|
+
contextName: context_name,
|
281
|
+
regex: target_regex
|
282
|
+
}
|
283
|
+
|
284
|
+
response = zap_rest_call(
|
285
|
+
zap_obj: zap_obj,
|
286
|
+
rest_call: 'JSON/context/action/includeInContext/',
|
287
|
+
params: params
|
288
|
+
)
|
289
|
+
|
290
|
+
JSON.parse(response.body, symbolize_names: true)
|
291
|
+
rescue StandardError, SystemExit, Interrupt => e
|
292
|
+
stop(zap_obj: zap_obj) unless zap_obj.nil?
|
293
|
+
raise e
|
294
|
+
end
|
295
|
+
|
296
|
+
# Supported Method Parameters::
|
297
|
+
# PWN::Plugins::Zaproxy.find_har_entries(
|
298
|
+
# zap_obj: 'required - zap_obj returned from #open method',
|
299
|
+
# request: 'required - base64 encoded request or HAR entry :request (e.g. from #get_sitemap method)'
|
300
|
+
# )
|
301
|
+
|
302
|
+
public_class_method def self.find_har_entries(opts = {})
|
303
|
+
zap_obj = opts[:zap_obj]
|
304
|
+
api_key = zap_obj[:api_key].to_s.scrub
|
305
|
+
request = opts[:request]
|
306
|
+
raise 'ERROR: request must be provided' if request.nil?
|
307
|
+
|
308
|
+
har_sitemap = get_sitemap(
|
309
|
+
zap_obj: zap_obj,
|
310
|
+
return_as: :har
|
311
|
+
)
|
312
|
+
|
313
|
+
# HAR entry
|
314
|
+
if request.is_a?(Hash) && request.key?(:method) && request.key?(:url) && request.key?(:httpVersion)
|
315
|
+
har_entries = har_sitemap.select { |entry| entry[:request] == request }
|
316
|
+
else
|
317
|
+
# Base64 encoded string
|
318
|
+
dec_request = Base64.strict_decode64(request).force_encoding('ASCII-8BIT') unless dec_request.is_a?(Hash)
|
319
|
+
|
320
|
+
# Find the har request for the given base64 decoded dec_request value
|
321
|
+
har_entries = har_sitemap.select do |entry|
|
322
|
+
req = entry[:request]
|
323
|
+
req_line = "#{req[:method]} #{req[:url]} #{req[:httpVersion]}\r\n"
|
324
|
+
req_headers = req[:headers].map { |h| "#{h[:name]}: #{h[:value]}\r\n" }.join
|
325
|
+
req_body = ''
|
326
|
+
if req[:postData] && req[:postData][:text]
|
327
|
+
req_body = req[:postData][:text]
|
328
|
+
req_body = Base64.decode64(req_body) if req[:postData][:encoding] == 'base64'
|
329
|
+
end
|
330
|
+
full_req = "#{req_line}#{req_headers}\r\n#{req_body}".force_encoding('ASCII-8BIT')
|
331
|
+
full_req == dec_request
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
har_entries
|
336
|
+
rescue StandardError, SystemExit, Interrupt => e
|
337
|
+
stop(zap_obj: zap_obj) unless zap_obj.nil?
|
338
|
+
raise e
|
339
|
+
end
|
340
|
+
|
341
|
+
# Supported Method Parameters::
|
342
|
+
# PWN::Plugins::Zaproxy.requester(
|
343
|
+
# zap_obj: 'required - zap_obj returned from #open method',
|
344
|
+
# har_entry: 'required - har entry (e.g. from #get_sitemap method or #find_har_entries method)',
|
345
|
+
# redirect: 'optional - follow redirects if set to true (defaults to false)'
|
346
|
+
# )
|
347
|
+
|
348
|
+
public_class_method def self.requester(opts = {})
|
349
|
+
zap_obj = opts[:zap_obj]
|
350
|
+
api_key = zap_obj[:api_key].to_s.scrub
|
351
|
+
har_entry = opts[:har_entry]
|
352
|
+
raise 'ERROR: har_entry must be provided and be a valid HAR entry' unless har_entry.is_a?(Hash) && har_entry.key?(:request) && har_entry.key?(:response)
|
353
|
+
|
354
|
+
redirect = opts[:redirect] || false
|
355
|
+
raise 'ERROR: redirect must be a boolean' unless redirect.is_a?(TrueClass) || redirect.is_a?(FalseClass)
|
356
|
+
|
357
|
+
har_json = har_entry.to_json
|
358
|
+
params = {
|
359
|
+
apikey: api_key,
|
360
|
+
request: har_json,
|
361
|
+
followRedirects: redirect.to_s
|
362
|
+
}
|
363
|
+
|
364
|
+
response = zap_rest_call(
|
365
|
+
zap_obj: zap_obj,
|
366
|
+
rest_call: 'OTHER/exim/other/sendHarRequest/',
|
367
|
+
params: params
|
368
|
+
)
|
369
|
+
|
370
|
+
JSON.parse(response.body, symbolize_names: true)
|
371
|
+
rescue StandardError, SystemExit, Interrupt => e
|
372
|
+
stop(zap_obj: zap_obj) unless zap_obj.nil?
|
373
|
+
raise e
|
374
|
+
end
|
375
|
+
|
393
376
|
# Supported Method Parameters::
|
394
377
|
# PWN::Plugins::Zaproxy.spider(
|
395
378
|
# zap_obj: 'required - zap_obj returned from #open method',
|
@@ -785,19 +768,26 @@ module PWN
|
|
785
768
|
openapi_spec: 'required - path to OpenAPI JSON or YAML spec file'
|
786
769
|
)
|
787
770
|
|
771
|
+
#{self}.get_sitemap(
|
772
|
+
zap_obj: 'required - zap_obj returned from #open method',
|
773
|
+
return_as: 'optional - :base64 or :har (defaults to :base64)'
|
774
|
+
)
|
775
|
+
|
788
776
|
#{self}.add_to_scope(
|
789
777
|
zap_obj: 'required - zap_obj returned from #open method',
|
790
778
|
target_regex: 'required - url regex to add to scope (e.g. https://test.domain.local.*)',
|
791
779
|
context_name: 'optional - context name to add target_regex to (defaults to Default Context)'
|
792
780
|
)
|
793
781
|
|
794
|
-
#{self}.
|
782
|
+
#{self}.find_har_entries(
|
795
783
|
zap_obj: 'required - zap_obj returned from #open method',
|
796
|
-
request: 'required - base64 encoded
|
784
|
+
request: 'required - base64 encoded request or HAR entry :request (e.g. from #get_sitemap method)'
|
797
785
|
)
|
798
786
|
|
799
|
-
#{self}.
|
800
|
-
zap_obj: 'required - zap_obj returned from #open method'
|
787
|
+
#{self}.requester(
|
788
|
+
zap_obj: 'required - zap_obj returned from #open method',
|
789
|
+
har_entry: 'required - har entry (e.g. from #get_sitemap method or #find_har_entries method)',
|
790
|
+
redirect: 'optional - follow redirects if set to true (defaults to true)'
|
801
791
|
)
|
802
792
|
|
803
793
|
json_sitemap = #{self}.spider(
|
data/lib/pwn/version.rb
CHANGED