pwn 0.5.404 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43c98ee49b32ce9b04d3fdc660599c8b7fc47db6f5b5042169a1ffe96eb6bb77
4
- data.tar.gz: a577bdac165bd2e96ec1ed87bb51c0d434276a00e8234f58c200e037ef1b83c0
3
+ metadata.gz: 3a4875ea87dd3f0605bc2ac889621fc124d43016086b2ef914a71dd8104879ff
4
+ data.tar.gz: 68addc891a15eea06b39b9e575fd98ce3b9e5a4d3e490c20bdfbe138699b8f2e
5
5
  SHA512:
6
- metadata.gz: 6bad0c2f1b20916b4245dc95a8b7a42f9a686e386fe475238b3890ea2287331e737d794b2a88e32437b50355fe4a3786420b3a756b40bc3f99b5fd76f3ce0496
7
- data.tar.gz: fd6cb93dad15d5e55e824a6bdbe13a3260612a015054d4cff6637b5469f5aa88ce7bdbe5409f83f4102f0023ba4ba2c9ca486ffaf3bddd8a94db37d98c761506
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.404]:001 >>> PWN.help
40
+ pwn[v0.5.406]:001 >>> PWN.help
41
41
  ```
42
42
 
43
43
  [![Installing the pwn Security Automation Framework](https://raw.githubusercontent.com/0dayInc/pwn/master/documentation/pwn_install.png)](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.404]:001 >>> PWN.help
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.404]:001 >>> PWN.help
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 not found' unless File.exist?(openapi_spec)
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',
@@ -171,6 +171,95 @@ module PWN
171
171
  raise e
172
172
  end
173
173
 
174
+ # Supported Method Parameters::
175
+ # json_sitemap = PWN::Plugins::Zaproxy.get_sitemap(
176
+ # zap_obj: 'required - zap_obj returned from #open method',
177
+ # return_as: 'optional - :base64 or :har (defaults to :base64)'
178
+ # )
179
+
180
+ public_class_method def self.get_sitemap(opts = {})
181
+ zap_obj = opts[:zap_obj]
182
+ api_key = zap_obj[:api_key].to_s.scrub
183
+ return_as = opts[:return_as] ||= :base64
184
+
185
+ entries = []
186
+ start = 0
187
+ count = 1000
188
+
189
+ loop do
190
+ params = { apikey: api_key, start: start, count: count }
191
+
192
+ response = zap_rest_call(
193
+ zap_obj: zap_obj,
194
+ rest_call: 'OTHER/exim/other/exportHar/',
195
+ params: params
196
+ )
197
+
198
+ har_data = JSON.parse(response.body, symbolize_names: true)
199
+ new_entries = har_data[:log][:entries]
200
+ break if new_entries.empty?
201
+
202
+ entries += new_entries
203
+ start += count
204
+ end
205
+ return entries if return_as == :har
206
+
207
+ # Deduplicate entries based on method + url
208
+ seen = Set.new
209
+ converted_messages = []
210
+
211
+ entries.each do |entry|
212
+ req = entry[:request]
213
+ key = [req[:method], req[:url]]
214
+ next if seen.include?(key)
215
+
216
+ seen.add(key)
217
+
218
+ # Build full request string
219
+ req_line = "#{req[:method]} #{req[:url]} #{req[:httpVersion]}\r\n"
220
+ req_headers = req[:headers].map { |h| "#{h[:name]}: #{h[:value]}\r\n" }.join
221
+ req_body = ''
222
+ if req[:postData] && req[:postData][:text]
223
+ req_body = req[:postData][:text]
224
+ req_body = Base64.decode64(req_body) if req[:postData][:encoding] == 'base64'
225
+ end
226
+ full_req = "#{req_line}#{req_headers}\r\n#{req_body}".force_encoding('ASCII-8BIT')
227
+ encoded_req = Base64.strict_encode64(full_req)
228
+
229
+ # Build full response string
230
+ res = entry[:response]
231
+ res_line = "#{res[:httpVersion]} #{res[:status]} #{res[:statusText]}\r\n"
232
+ res_headers = res[:headers].map { |h| "#{h[:name]}: #{h[:value]}\r\n" }.join
233
+ res_body = ''
234
+ if res[:content] && res[:content][:text]
235
+ res_body = res[:content][:text]
236
+ res_body = Base64.decode64(res_body) if res[:content][:encoding] == 'base64'
237
+ end
238
+ full_res = "#{res_line}#{res_headers}\r\n#{res_body}".force_encoding('ASCII-8BIT')
239
+ encoded_res = Base64.strict_encode64(full_res)
240
+
241
+ # Extract http_service
242
+ uri = URI.parse(req[:url])
243
+ http_service = {
244
+ host: uri.host,
245
+ port: uri.port,
246
+ protocol: uri.scheme
247
+ }
248
+
249
+ # Add to array
250
+ converted_messages << {
251
+ request: encoded_req,
252
+ response: encoded_res,
253
+ http_service: http_service
254
+ }
255
+ end
256
+
257
+ converted_messages
258
+ rescue StandardError, SystemExit, Interrupt => e
259
+ stop(zap_obj: zap_obj) unless zap_obj.nil?
260
+ raise e
261
+ end
262
+
174
263
  # Supported Method Parameters::
175
264
  # PWN::Plugins::Zaproxy.add_to_scope(
176
265
  # zap_obj: 'required - zap_obj returned from #open method',
@@ -204,6 +293,86 @@ module PWN
204
293
  raise e
205
294
  end
206
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
+
207
376
  # Supported Method Parameters::
208
377
  # PWN::Plugins::Zaproxy.spider(
209
378
  # zap_obj: 'required - zap_obj returned from #open method',
@@ -273,14 +442,41 @@ module PWN
273
442
  headers = opts[:headers] ||= {}
274
443
  raise 'ERROR: headers must be provided' if headers.empty? || !headers.is_a?(Hash)
275
444
 
445
+ # Check if replacer rule already exists
446
+ params = { apikey: api_key }
447
+ response = zap_rest_call(
448
+ zap_obj: zap_obj,
449
+ rest_call: 'JSON/replacer/view/rules/',
450
+ params: params
451
+ )
452
+ replacer = JSON.parse(response.body, symbolize_names: true)
453
+
276
454
  replacer_resp_arr = []
277
455
  headers.each_key do |header_key|
456
+ this_header = { header: header_key }
457
+ rule_exists = replacer[:rules].any? { |rule| rule[:description] == header_key.to_s && rule[:url] == target_regex }
458
+
459
+ if rule_exists
460
+ # Remove existing rule first
461
+ puts "Removing existing replacer rule for header key: #{header_key}..."
462
+ params = {
463
+ apikey: api_key,
464
+ description: header_key
465
+ }
466
+ zap_rest_call(
467
+ zap_obj: zap_obj,
468
+ rest_call: 'JSON/replacer/action/removeRule/',
469
+ params: params
470
+ )
471
+ end
472
+
473
+ puts "Adding replacer rule for header key: #{header_key}..."
278
474
  params = {
279
475
  apikey: api_key,
280
476
  description: header_key,
281
- enabled: true,
477
+ enabled: 'true',
282
478
  matchType: 'REQ_HEADER',
283
- matchRegex: false,
479
+ matchRegex: 'false',
284
480
  matchString: header_key,
285
481
  replacement: headers[header_key],
286
482
  initiators: '',
@@ -294,7 +490,8 @@ module PWN
294
490
  )
295
491
 
296
492
  json_resp = JSON.parse(response.body, symbolize_names: true)
297
- replacer_resp_arr.push(json_resp)
493
+ this_header[:Result] = json_resp[:Result]
494
+ replacer_resp_arr.push(this_header)
298
495
  end
299
496
 
300
497
  replacer_resp_arr
@@ -571,12 +768,32 @@ module PWN
571
768
  openapi_spec: 'required - path to OpenAPI JSON or YAML spec file'
572
769
  )
573
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
+
574
776
  #{self}.add_to_scope(
575
777
  zap_obj: 'required - zap_obj returned from #open method',
576
778
  target_regex: 'required - url regex to add to scope (e.g. https://test.domain.local.*)',
577
779
  context_name: 'optional - context name to add target_regex to (defaults to Default Context)'
578
780
  )
579
781
 
782
+ #{self}.find_har_entries(
783
+ zap_obj: 'required - zap_obj returned from #open method',
784
+ request: 'required - base64 encoded request or HAR entry :request (e.g. from #get_sitemap method)'
785
+ )
786
+
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)'
791
+ )
792
+
793
+ json_sitemap = #{self}.spider(
794
+ zap_obj: 'required - zap_obj returned from #open method'
795
+ )
796
+
580
797
  #{self}.inject_additional_http_headers(
581
798
  zap_obj: 'required - zap_obj returned from #open method',
582
799
  target_regex: 'required - url regex to inject headers into (e.g. https://test.domain.local.*)',
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.404'
4
+ VERSION = '0.5.406'
5
5
  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.404
4
+ version: 0.5.406
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.