pwn 0.5.504 → 0.5.505

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: 62c1bc05c91ca9fccd91e490059fdd2ca01fb402d92858f08bacae5123f7d874
4
- data.tar.gz: 0636fbce91309aac818e5b805390cafebcf3538d92af18164632c320ca21cfa1
3
+ metadata.gz: bee5101dd6376bc129ed438a7e5afdf0fb2fb71612ff4663aa9747b9b538c639
4
+ data.tar.gz: ceac8682de6d7347a350ed8fd3598f371c6a4d1df107f471920bfd8ca7da8520
5
5
  SHA512:
6
- metadata.gz: 47556a1d0032c65354d9536a4ace20309d2f958a3d832cfa29cedda089d07345b0b77dbf08c3bf5b1cbb4f67a75499b595f98be4cadd8cab00be774df8e7dee9
7
- data.tar.gz: 1b7d7de1768368b94a1aa601e53e16bf59a2743b16b7070fbda38ce88ba1c0d41b66d8de1a2b926b647838aea988dbdb2423759acb91250ec1349299c949d4b7
6
+ metadata.gz: 4791d10076ceda124e859a7cc92efa78822ede231a3d47acd05e5cd80526aff75d3679f857d2a0c89e52245191fb1f5b211c74e415e3307325f9e8e1f19be331
7
+ data.tar.gz: d039ccf4f5b7ee4fafa39b444fccf29ded52d294d70ef29f4b8df16f170328896885ef9babd5dd0b19588bcbbe24a63bd79f7cab739819e0cad1343e7a2d9d46
data/.rubocop.yml CHANGED
@@ -18,7 +18,7 @@ Metrics/CyclomaticComplexity:
18
18
  Metrics/MethodLength:
19
19
  Max: 565
20
20
  Metrics/ModuleLength:
21
- Max: 1549
21
+ Max: 1561
22
22
  Metrics/PerceivedComplexity:
23
23
  Max: 157
24
24
  Style/HashEachMethods:
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.504]:001 >>> PWN.help
40
+ pwn[v0.5.505]: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.504]:001 >>> PWN.help
55
+ pwn[v0.5.505]: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.504]:001 >>> PWN.help
65
+ pwn[v0.5.505]: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:
@@ -46,7 +46,7 @@ module PWN
46
46
  # Supported Method Parameters::
47
47
  # burp_obj = PWN::Plugins::BurpSuite.init_introspection_thread(
48
48
  # burp_obj: 'required - burp_obj returned by #start method',
49
- # enumerable_array: 'required - array of items to process in the thread'
49
+ # type: 'required - type of history to introspect (:sitemap, :proxy_history, :websocket_history)'
50
50
  # )
51
51
  private_class_method def self.init_introspection_thread(opts = {})
52
52
  # if PWN::Env[:ai][:introspection] is true,
@@ -60,7 +60,12 @@ module PWN
60
60
  burp_obj = opts[:burp_obj]
61
61
  raise 'ERROR: burp_obj parameter is required' unless burp_obj.is_a?(Hash)
62
62
 
63
+ valid_types = %i[sitemap proxy_history websocket_history]
64
+ type = opts[:type]
65
+ raise "ERROR: type parameter is required and must be one of: #{valid_types.join(', ')}" unless valid_types.include?(type)
66
+
63
67
  if PWN::Env[:ai][:introspection]
68
+ introspection_thread_arr = burp_obj[:introspection_threads] ||= []
64
69
  introspection_thread = Thread.new do
65
70
  system_role_content = '
66
71
  Your expertise lies in dissecting HTTP request/response pairs and WebSocket messages to identify high-impact vulnerabilities, including but not limited to XSS (reflected, stored, DOM-based), CSRF, SSRF, IDOR, open redirects, CORS misconfigurations, authentication bypasses, SQLi/NoSQLi, command/code injection, business logic flaws, race conditions, and API abuse. You prioritize zero-days and novel chains, always focusing on exploitability, impact (e.g., account takeover, data exfiltration, RCE), and reproducibility.
@@ -119,95 +124,128 @@ module PWN
119
124
  highlight_color
120
125
  end
121
126
 
122
- proxy_history = []
123
127
  loop do
124
- # TODO: Implement sitemap and repeater into the loop.
125
- # Sitemap should work the same as proxy history.
128
+ # TODO: Implement repeater into the loop? This reduces load to LLM but is slooow.
126
129
  # Repeater should analyze the reqesut/response pair and suggest
127
- # modifications to the request to further probe for vulnerabilities.
128
- sitemap = get_sitemap(burp_obj: burp_obj)
129
- sitemap.each do |entry|
130
- next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
131
-
132
- request = entry[:request]
133
- response = entry[:response]
134
- host = entry[:http_service][:host]
135
- port = entry[:http_service][:port]
136
- protocol = entry[:http_service][:protocol]
137
- next if request.nil? || response.nil? || host.nil? || port.nil? || protocol.nil?
138
-
139
- proxy_history_entry = nil
140
- if proxy_history.any?
141
- proxy_history_entry = proxy_history.find do |proxy_entry|
142
- next unless proxy_entry.key?(:http_service) && proxy_entry.key?(:request)
143
-
144
- proxy_entry[:http_service][:host] == host &&
145
- proxy_entry[:http_service][:port] == port &&
146
- proxy_entry[:http_service][:protocol] == protocol &&
147
- proxy_entry[:request] == entry[:request]
130
+ # modifications to the request to further probe for vulnerabilities _quickly_.
131
+ case type
132
+ when :sitemap
133
+ proxy_history = get_proxy_history(burp_obj: burp_obj)
134
+ sitemap = get_sitemap(burp_obj: burp_obj)
135
+ sitemap.each do |entry|
136
+ next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
137
+
138
+ request = entry[:request]
139
+ response = entry[:response]
140
+ host = entry[:http_service][:host]
141
+ port = entry[:http_service][:port]
142
+ protocol = entry[:http_service][:protocol]
143
+ next if request.nil? || response.nil? || host.nil? || port.nil? || protocol.nil?
144
+
145
+ proxy_history_entry = nil
146
+ if proxy_history.any?
147
+ proxy_history_entry = proxy_history.find do |proxy_entry|
148
+ next unless proxy_entry.key?(:http_service) && proxy_entry.key?(:request)
149
+
150
+ proxy_entry[:http_service][:host] == host &&
151
+ proxy_entry[:http_service][:port] == port &&
152
+ proxy_entry[:http_service][:protocol] == protocol &&
153
+ proxy_entry[:request] == entry[:request]
154
+ end
148
155
  end
149
- end
150
156
 
151
- if proxy_history_entry.is_a?(Hash) && proxy_history_entry[:comment].length.positive?
152
- entry[:comment] = proxy_history_entry[:comment]
153
- entry[:highlight] = proxy_history_entry[:highlight]
154
- else
155
- request = Base64.strict_decode64(request)
156
- response = Base64.strict_decode64(response)
157
- http_request_response = PWN::Plugins::Char.force_utf8("#{request}\r\n\r\n#{response}")
158
- ai_analysis = PWN::AI::Introspection.reflect_on(
159
- system_role_content: system_role_content,
160
- request: http_request_response,
161
- suppress_pii_warning: true
157
+ if proxy_history_entry.is_a?(Hash) && proxy_history_entry[:comment].length.positive?
158
+ entry[:comment] = proxy_history_entry[:comment]
159
+ entry[:highlight] = proxy_history_entry[:highlight]
160
+ else
161
+ request = Base64.strict_decode64(request)
162
+ response = Base64.strict_decode64(response)
163
+ http_request_response = PWN::Plugins::Char.force_utf8("#{request}\r\n\r\n#{response}")
164
+ ai_analysis = PWN::AI::Introspection.reflect_on(
165
+ system_role_content: system_role_content,
166
+ request: http_request_response,
167
+ suppress_pii_warning: true
168
+ )
169
+
170
+ next if ai_analysis.nil? || ai_analysis.strip.empty?
171
+
172
+ entry[:comment] = ai_analysis
173
+ entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
174
+ end
175
+
176
+ update_sitemap(
177
+ burp_obj: burp_obj,
178
+ entry: entry
162
179
  )
180
+ end
163
181
 
164
- next if ai_analysis.nil? || ai_analysis.strip.empty?
182
+ when :proxy_history
183
+ sitemap = get_sitemap(burp_obj: burp_obj)
184
+ proxy_history = get_proxy_history(burp_obj: burp_obj)
185
+ proxy_history.each do |entry|
186
+ next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
187
+
188
+ request = entry[:request]
189
+ response = entry[:response]
190
+ host = entry[:http_service][:host]
191
+ port = entry[:http_service][:port]
192
+ protocol = entry[:http_service][:protocol]
193
+ next if request.nil? || response.nil? || host.nil? || port.nil? || protocol.nil?
194
+
195
+ # If sitemap comment and highlight color exists, use that instead of re-analyzing
196
+ sitemap_entry = nil
197
+ if sitemap.any?
198
+ sitemap_entry = sitemap.find do |site|
199
+ next unless site.key?(:http_service) && site.key?(:request)
200
+
201
+ site[:http_service][:host] == host &&
202
+ site[:http_service][:port] == port &&
203
+ site[:http_service][:protocol] == protocol &&
204
+ site[:request] == entry[:request]
205
+ end
206
+ end
165
207
 
166
- entry[:comment] = ai_analysis
167
- entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
168
- end
208
+ if sitemap_entry.is_a?(Hash) && sitemap_entry[:comment].length.positive?
209
+ entry[:comment] = sitemap_entry[:comment]
210
+ entry[:highlight] = sitemap_entry[:highlight]
211
+ else
212
+ request = Base64.strict_decode64(request)
213
+ response = Base64.strict_decode64(response)
169
214
 
170
- update_sitemap(
171
- burp_obj: burp_obj,
172
- entry: entry
173
- )
174
- end
215
+ http_request_response = PWN::Plugins::Char.force_utf8("#{request}\r\n\r\n#{response}")
216
+ ai_analysis = PWN::AI::Introspection.reflect_on(
217
+ system_role_content: system_role_content,
218
+ request: http_request_response,
219
+ suppress_pii_warning: true
220
+ )
175
221
 
176
- proxy_history = get_proxy_history(burp_obj: burp_obj)
177
- proxy_history.each do |entry|
178
- next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
179
-
180
- request = entry[:request]
181
- response = entry[:response]
182
- host = entry[:http_service][:host]
183
- port = entry[:http_service][:port]
184
- protocol = entry[:http_service][:protocol]
185
- next if request.nil? || response.nil? || host.nil? || port.nil? || protocol.nil?
186
-
187
- # If sitemap comment and highlight color exists, use that instead of re-analyzing
188
- sitemap_entry = nil
189
- if sitemap.any?
190
- sitemap_entry = sitemap.find do |site|
191
- next unless site.key?(:http_service) && site.key?(:request)
192
-
193
- site[:http_service][:host] == host &&
194
- site[:http_service][:port] == port &&
195
- site[:http_service][:protocol] == protocol &&
196
- site[:request] == entry[:request]
222
+ next if ai_analysis.nil? || ai_analysis.strip.empty?
223
+
224
+ entry[:comment] = ai_analysis
225
+ entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
197
226
  end
227
+
228
+ update_proxy_history(
229
+ burp_obj: burp_obj,
230
+ entry: entry
231
+ )
198
232
  end
199
233
 
200
- if sitemap_entry.is_a?(Hash) && sitemap_entry[:comment].length.positive?
201
- entry[:comment] = sitemap_entry[:comment]
202
- entry[:highlight] = sitemap_entry[:highlight]
203
- else
204
- request = Base64.strict_decode64(request)
205
- response = Base64.strict_decode64(response)
234
+ when :websocket_history
235
+ websocket_history = get_websocket_history(burp_obj: burp_obj)
236
+ websocket_history.each do |entry|
237
+ next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
238
+
239
+ web_socket_id = entry[:web_socket_id]
240
+ direction = entry[:direction]
241
+ payload = entry[:payload]
242
+ next if web_socket_id.nil? || direction.nil? || payload.nil?
206
243
 
207
- http_request_response = PWN::Plugins::Char.force_utf8("#{request}\r\n\r\n#{response}")
244
+ payload = Base64.strict_decode64(payload)
245
+ websocket_req = PWN::Plugins::Char.force_utf8("WebSocket ID: #{web_socket_id}\nDirection: #{direction}\nPayload:\n#{payload}")
208
246
  ai_analysis = PWN::AI::Introspection.reflect_on(
209
247
  system_role_content: system_role_content,
210
- request: http_request_response,
248
+ request: websocket_req,
211
249
  suppress_pii_warning: true
212
250
  )
213
251
 
@@ -215,43 +253,15 @@ module PWN
215
253
 
216
254
  entry[:comment] = ai_analysis
217
255
  entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
218
- end
219
-
220
- update_proxy_history(
221
- burp_obj: burp_obj,
222
- entry: entry
223
- )
224
- end
225
-
226
- websocket_history = get_websocket_history(burp_obj: burp_obj)
227
- websocket_history.each do |entry|
228
- next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
229
-
230
- web_socket_id = entry[:web_socket_id]
231
- direction = entry[:direction]
232
- payload = entry[:payload]
233
- next if web_socket_id.nil? || direction.nil? || payload.nil?
234
-
235
- payload = Base64.strict_decode64(payload)
236
- websocket_req = PWN::Plugins::Char.force_utf8("WebSocket ID: #{web_socket_id}\nDirection: #{direction}\nPayload:\n#{payload}")
237
- ai_analysis = PWN::AI::Introspection.reflect_on(
238
- system_role_content: system_role_content,
239
- request: websocket_req,
240
- suppress_pii_warning: true
241
- )
242
256
 
243
- next if ai_analysis.nil? || ai_analysis.strip.empty?
244
-
245
- entry[:comment] = ai_analysis
246
- entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
247
-
248
- update_websocket_history(
249
- burp_obj: burp_obj,
250
- entry: entry
251
- )
257
+ update_websocket_history(
258
+ burp_obj: burp_obj,
259
+ entry: entry
260
+ )
261
+ end
252
262
  end
253
263
 
254
- sleep 3
264
+ sleep Random.rand(30..60)
255
265
  end
256
266
  rescue Errno::ECONNREFUSED
257
267
  puts 'BurpSuite AI Introspection Thread >>> Terminating API Calls...'
@@ -263,7 +273,7 @@ module PWN
263
273
  puts 'BurpSuite AI Introspection Thread >>> Goodbye.'
264
274
  end
265
275
 
266
- burp_obj[:introspection_thread] = introspection_thread
276
+ burp_obj[:introspection_threads] = introspection_thread_arr.push(introspection_thread)
267
277
  end
268
278
 
269
279
  burp_obj
@@ -352,7 +362,9 @@ module PWN
352
362
  enabled: true
353
363
  )
354
364
 
355
- init_introspection_thread(burp_obj: burp_obj)
365
+ burp_obj = init_introspection_thread(burp_obj: burp_obj, type: :sitemap)
366
+ burp_obj = init_introspection_thread(burp_obj: burp_obj, type: :proxy_history)
367
+ init_introspection_thread(burp_obj: burp_obj, type: :websocket_history)
356
368
  rescue StandardError => e
357
369
  stop(burp_obj: burp_obj) unless burp_obj.nil?
358
370
  raise e
@@ -1994,8 +2006,9 @@ module PWN
1994
2006
  browser_obj = burp_obj[:mitm_browser]
1995
2007
  rest_browser = burp_obj[:rest_browser]
1996
2008
  mitm_rest_api = burp_obj[:mitm_rest_api]
1997
- introspection_thread = burp_obj[:introspection_thread]
1998
- introspection_thread.kill unless introspection_thread.nil?
2009
+ introspection_thread_arr = burp_obj[:introspection_threads]
2010
+ introspection_thread_arr.each(&:kill) if introspection_thread_arr.is_a?(Array) && introspection_thread_arr.any?
2011
+ # introspection_thread.kill unless introspection_thread.nil?
1999
2012
 
2000
2013
  PWN::Plugins::TransparentBrowser.close(browser_obj: browser_obj)
2001
2014
  rest_browser.post("http://#{mitm_rest_api}/shutdown", '')
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.504'
4
+ VERSION = '0.5.505'
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.504
4
+ version: 0.5.505
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.