pwn 0.5.404 → 0.5.405

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: a4b31134e90c20f44f69f6b1fbf8b6e4c8e7911bbec857597c729c0801578d5f
4
+ data.tar.gz: 8774dc902ef4eadf6d32303cac8efe5fea2a909997a4d7d2c0fdb2e8c137e58a
5
5
  SHA512:
6
- metadata.gz: 6bad0c2f1b20916b4245dc95a8b7a42f9a686e386fe475238b3890ea2287331e737d794b2a88e32437b50355fe4a3786420b3a756b40bc3f99b5fd76f3ce0496
7
- data.tar.gz: fd6cb93dad15d5e55e824a6bdbe13a3260612a015054d4cff6637b5469f5aa88ce7bdbe5409f83f4102f0023ba4ba2c9ca486ffaf3bddd8a94db37d98c761506
6
+ metadata.gz: a583c93c1288496cb703e5b4e48a9a70f258c955b05d0dbbf9ffa27b1be25c0d1c2568537379ebe65ae63a423bf31cc022221074e3d8cdbfe100c59739d25099
7
+ data.tar.gz: b9b3af817aa7ccd08a05cbc6cbe1107c5760db93b6ec9343a01b74d3b7d992d6f72abe4c11ef5d156f96649268a51b3b1177daa97fff2b04d7c759c781a69884
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.405]: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.405]: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.405]: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:
@@ -204,6 +204,192 @@ module PWN
204
204
  raise e
205
205
  end
206
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
+ # Supported Method Parameters::
308
+ # json_sitemap = PWN::Plugins::Zaproxy.get_sitemap(
309
+ # zap_obj: 'required - zap_obj returned from #open method'
310
+ # )
311
+
312
+ public_class_method def self.get_sitemap(opts = {})
313
+ zap_obj = opts[:zap_obj]
314
+ api_key = zap_obj[:api_key].to_s.scrub
315
+
316
+ entries = []
317
+ start = 0
318
+ count = 1000
319
+
320
+ loop do
321
+ params = { apikey: api_key, start: start, count: count }
322
+
323
+ response = zap_rest_call(
324
+ zap_obj: zap_obj,
325
+ rest_call: 'OTHER/exim/other/exportHar/',
326
+ params: params
327
+ )
328
+
329
+ har_data = JSON.parse(response.body, symbolize_names: true)
330
+ new_entries = har_data[:log][:entries]
331
+ break if new_entries.empty?
332
+
333
+ entries += new_entries
334
+ start += count
335
+ end
336
+
337
+ # Deduplicate entries based on method + url
338
+ seen = Set.new
339
+ converted_messages = []
340
+
341
+ entries.each do |entry|
342
+ req = entry[:request]
343
+ key = [req[:method], req[:url]]
344
+ next if seen.include?(key)
345
+
346
+ seen.add(key)
347
+
348
+ # Build full request string
349
+ req_line = "#{req[:method]} #{req[:url]} #{req[:httpVersion]}\r\n"
350
+ req_headers = req[:headers].map { |h| "#{h[:name]}: #{h[:value]}\r\n" }.join
351
+ req_body = ''
352
+ if req[:postData] && req[:postData][:text]
353
+ req_body = req[:postData][:text]
354
+ req_body = Base64.decode64(req_body) if req[:postData][:encoding] == 'base64'
355
+ end
356
+ full_req = "#{req_line}#{req_headers}\r\n#{req_body}".force_encoding('ASCII-8BIT')
357
+ encoded_req = Base64.strict_encode64(full_req)
358
+
359
+ # Build full response string
360
+ res = entry[:response]
361
+ res_line = "#{res[:httpVersion]} #{res[:status]} #{res[:statusText]}\r\n"
362
+ res_headers = res[:headers].map { |h| "#{h[:name]}: #{h[:value]}\r\n" }.join
363
+ res_body = ''
364
+ if res[:content] && res[:content][:text]
365
+ res_body = res[:content][:text]
366
+ res_body = Base64.decode64(res_body) if res[:content][:encoding] == 'base64'
367
+ end
368
+ full_res = "#{res_line}#{res_headers}\r\n#{res_body}".force_encoding('ASCII-8BIT')
369
+ encoded_res = Base64.strict_encode64(full_res)
370
+
371
+ # Extract http_service
372
+ uri = URI.parse(req[:url])
373
+ http_service = {
374
+ host: uri.host,
375
+ port: uri.port,
376
+ protocol: uri.scheme
377
+ }
378
+
379
+ # Add to array
380
+ converted_messages << {
381
+ request: encoded_req,
382
+ response: encoded_res,
383
+ http_service: http_service
384
+ }
385
+ end
386
+
387
+ converted_messages
388
+ rescue StandardError, SystemExit, Interrupt => e
389
+ stop(zap_obj: zap_obj) unless zap_obj.nil?
390
+ raise e
391
+ end
392
+
207
393
  # Supported Method Parameters::
208
394
  # PWN::Plugins::Zaproxy.spider(
209
395
  # zap_obj: 'required - zap_obj returned from #open method',
@@ -273,14 +459,41 @@ module PWN
273
459
  headers = opts[:headers] ||= {}
274
460
  raise 'ERROR: headers must be provided' if headers.empty? || !headers.is_a?(Hash)
275
461
 
462
+ # Check if replacer rule already exists
463
+ params = { apikey: api_key }
464
+ response = zap_rest_call(
465
+ zap_obj: zap_obj,
466
+ rest_call: 'JSON/replacer/view/rules/',
467
+ params: params
468
+ )
469
+ replacer = JSON.parse(response.body, symbolize_names: true)
470
+
276
471
  replacer_resp_arr = []
277
472
  headers.each_key do |header_key|
473
+ this_header = { header: header_key }
474
+ rule_exists = replacer[:rules].any? { |rule| rule[:description] == header_key.to_s && rule[:url] == target_regex }
475
+
476
+ if rule_exists
477
+ # Remove existing rule first
478
+ puts "Removing existing replacer rule for header key: #{header_key}..."
479
+ params = {
480
+ apikey: api_key,
481
+ description: header_key
482
+ }
483
+ zap_rest_call(
484
+ zap_obj: zap_obj,
485
+ rest_call: 'JSON/replacer/action/removeRule/',
486
+ params: params
487
+ )
488
+ end
489
+
490
+ puts "Adding replacer rule for header key: #{header_key}..."
278
491
  params = {
279
492
  apikey: api_key,
280
493
  description: header_key,
281
- enabled: true,
494
+ enabled: 'true',
282
495
  matchType: 'REQ_HEADER',
283
- matchRegex: false,
496
+ matchRegex: 'false',
284
497
  matchString: header_key,
285
498
  replacement: headers[header_key],
286
499
  initiators: '',
@@ -294,7 +507,8 @@ module PWN
294
507
  )
295
508
 
296
509
  json_resp = JSON.parse(response.body, symbolize_names: true)
297
- replacer_resp_arr.push(json_resp)
510
+ this_header[:Result] = json_resp[:Result]
511
+ replacer_resp_arr.push(this_header)
298
512
  end
299
513
 
300
514
  replacer_resp_arr
@@ -577,6 +791,19 @@ module PWN
577
791
  context_name: 'optional - context name to add target_regex to (defaults to Default Context)'
578
792
  )
579
793
 
794
+ #{self}.add_requester_tab(
795
+ zap_obj: 'required - zap_obj returned from #open method',
796
+ request: 'required - base64 encoded HTTP request (e.g. from #get_sitemap method)'
797
+ )
798
+
799
+ #{self}.get_sitemap(
800
+ zap_obj: 'required - zap_obj returned from #open method'
801
+ )
802
+
803
+ json_sitemap = #{self}.spider(
804
+ zap_obj: 'required - zap_obj returned from #open method'
805
+ )
806
+
580
807
  #{self}.inject_additional_http_headers(
581
808
  zap_obj: 'required - zap_obj returned from #open method',
582
809
  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.405'
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.405
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.