pwn 0.5.504 → 0.5.506

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: ff5a5cd8f4d9e0ce9d23468de01cb6c0f685ed4c9541e08af39dcb05b8c50d67
4
+ data.tar.gz: e9afe048562d6d832972c9990a24db2b78a6d5c76e95959079ac4412e959c152
5
5
  SHA512:
6
- metadata.gz: 47556a1d0032c65354d9536a4ace20309d2f958a3d832cfa29cedda089d07345b0b77dbf08c3bf5b1cbb4f67a75499b595f98be4cadd8cab00be774df8e7dee9
7
- data.tar.gz: 1b7d7de1768368b94a1aa601e53e16bf59a2743b16b7070fbda38ce88ba1c0d41b66d8de1a2b926b647838aea988dbdb2423759acb91250ec1349299c949d4b7
6
+ metadata.gz: 30d268063617d51deeed10b035ed8566913eebf114247ea8f4d988347a447faff622105e032f103ece1a56a69145e8ade0a79a6c9b0ec183f075065ca9d25818
7
+ data.tar.gz: 1c8deccd120888637f7a257cd3304374caac61bb9276a6f48b7c20a68e00087a7ec952a2c823745e62aa87c720c478b99f69e367ad95151365d06f644cfd49a0
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: 1563
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.506]: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.506]: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.506]: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[proxy_history sitemap 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,130 @@ 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 :proxy_history
133
+ sitemap = get_sitemap(burp_obj: burp_obj)
134
+ proxy_history = get_proxy_history(burp_obj: burp_obj)
135
+ proxy_history.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
+ # If sitemap comment and highlight color exists, use that instead of re-analyzing
146
+ sitemap_entry = nil
147
+ if sitemap.any?
148
+ sitemap_entry = sitemap.find do |site|
149
+ next unless site.key?(:http_service) && site.key?(:request)
150
+
151
+ site[:http_service][:host] == host &&
152
+ site[:http_service][:port] == port &&
153
+ site[:http_service][:protocol] == protocol &&
154
+ site[:request] == entry[:request]
155
+ end
148
156
  end
149
- end
150
157
 
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
162
- )
158
+ if sitemap_entry.is_a?(Hash) && sitemap_entry[:comment].length.positive?
159
+ entry[:comment] = sitemap_entry[:comment]
160
+ entry[:highlight] = sitemap_entry[:highlight]
161
+ else
162
+ request = Base64.strict_decode64(request)
163
+ response = Base64.strict_decode64(response)
163
164
 
164
- next if ai_analysis.nil? || ai_analysis.strip.empty?
165
+ http_request_response = PWN::Plugins::Char.force_utf8("#{request}\r\n\r\n#{response}")
166
+ ai_analysis = PWN::AI::Introspection.reflect_on(
167
+ system_role_content: system_role_content,
168
+ request: http_request_response,
169
+ suppress_pii_warning: true
170
+ )
165
171
 
166
- entry[:comment] = ai_analysis
167
- entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
168
- end
172
+ next if ai_analysis.nil? || ai_analysis.strip.empty?
169
173
 
170
- update_sitemap(
171
- burp_obj: burp_obj,
172
- entry: entry
173
- )
174
- end
174
+ entry[:comment] = ai_analysis
175
+ entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
176
+ end
177
+
178
+ update_proxy_history(
179
+ burp_obj: burp_obj,
180
+ entry: entry
181
+ )
182
+ end
183
+ sleep Random.rand(30..60)
184
+
185
+ when :sitemap
186
+ proxy_history = get_proxy_history(burp_obj: burp_obj)
187
+ sitemap = get_sitemap(burp_obj: burp_obj)
188
+ sitemap.each do |entry|
189
+ next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
190
+
191
+ request = entry[:request]
192
+ response = entry[:response]
193
+ host = entry[:http_service][:host]
194
+ port = entry[:http_service][:port]
195
+ protocol = entry[:http_service][:protocol]
196
+ next if request.nil? || response.nil? || host.nil? || port.nil? || protocol.nil?
197
+
198
+ proxy_history_entry = nil
199
+ if proxy_history.any?
200
+ proxy_history_entry = proxy_history.find do |proxy_entry|
201
+ next unless proxy_entry.key?(:http_service) && proxy_entry.key?(:request)
202
+
203
+ proxy_entry[:http_service][:host] == host &&
204
+ proxy_entry[:http_service][:port] == port &&
205
+ proxy_entry[:http_service][:protocol] == protocol &&
206
+ proxy_entry[:request] == entry[:request]
207
+ end
208
+ end
175
209
 
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]
210
+ if proxy_history_entry.is_a?(Hash) && proxy_history_entry[:comment].length.positive?
211
+ entry[:comment] = proxy_history_entry[:comment]
212
+ entry[:highlight] = proxy_history_entry[:highlight]
213
+ else
214
+ request = Base64.strict_decode64(request)
215
+ response = Base64.strict_decode64(response)
216
+ http_request_response = PWN::Plugins::Char.force_utf8("#{request}\r\n\r\n#{response}")
217
+ ai_analysis = PWN::AI::Introspection.reflect_on(
218
+ system_role_content: system_role_content,
219
+ request: http_request_response,
220
+ suppress_pii_warning: true
221
+ )
222
+
223
+ next if ai_analysis.nil? || ai_analysis.strip.empty?
224
+
225
+ entry[:comment] = ai_analysis
226
+ entry[:highlight] = get_highlight_color.call(ai_analysis: ai_analysis)
197
227
  end
228
+
229
+ update_sitemap(
230
+ burp_obj: burp_obj,
231
+ entry: entry
232
+ )
198
233
  end
234
+ sleep Random.rand(60..90)
199
235
 
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)
236
+ when :websocket_history
237
+ websocket_history = get_websocket_history(burp_obj: burp_obj)
238
+ websocket_history.each do |entry|
239
+ next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
206
240
 
207
- http_request_response = PWN::Plugins::Char.force_utf8("#{request}\r\n\r\n#{response}")
241
+ web_socket_id = entry[:web_socket_id]
242
+ direction = entry[:direction]
243
+ payload = entry[:payload]
244
+ next if web_socket_id.nil? || direction.nil? || payload.nil?
245
+
246
+ payload = Base64.strict_decode64(payload)
247
+ websocket_req = PWN::Plugins::Char.force_utf8("WebSocket ID: #{web_socket_id}\nDirection: #{direction}\nPayload:\n#{payload}")
208
248
  ai_analysis = PWN::AI::Introspection.reflect_on(
209
249
  system_role_content: system_role_content,
210
- request: http_request_response,
250
+ request: websocket_req,
211
251
  suppress_pii_warning: true
212
252
  )
213
253
 
@@ -215,43 +255,14 @@ module PWN
215
255
 
216
256
  entry[:comment] = ai_analysis
217
257
  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
258
 
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
-
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
- )
259
+ update_websocket_history(
260
+ burp_obj: burp_obj,
261
+ entry: entry
262
+ )
263
+ end
264
+ sleep Random.rand(3..10)
252
265
  end
253
-
254
- sleep 3
255
266
  end
256
267
  rescue Errno::ECONNREFUSED
257
268
  puts 'BurpSuite AI Introspection Thread >>> Terminating API Calls...'
@@ -263,7 +274,7 @@ module PWN
263
274
  puts 'BurpSuite AI Introspection Thread >>> Goodbye.'
264
275
  end
265
276
 
266
- burp_obj[:introspection_thread] = introspection_thread
277
+ burp_obj[:introspection_threads] = introspection_thread_arr.push(introspection_thread)
267
278
  end
268
279
 
269
280
  burp_obj
@@ -352,7 +363,9 @@ module PWN
352
363
  enabled: true
353
364
  )
354
365
 
355
- init_introspection_thread(burp_obj: burp_obj)
366
+ burp_obj = init_introspection_thread(burp_obj: burp_obj, type: :sitemap)
367
+ burp_obj = init_introspection_thread(burp_obj: burp_obj, type: :proxy_history)
368
+ init_introspection_thread(burp_obj: burp_obj, type: :websocket_history)
356
369
  rescue StandardError => e
357
370
  stop(burp_obj: burp_obj) unless burp_obj.nil?
358
371
  raise e
@@ -1994,8 +2007,9 @@ module PWN
1994
2007
  browser_obj = burp_obj[:mitm_browser]
1995
2008
  rest_browser = burp_obj[:rest_browser]
1996
2009
  mitm_rest_api = burp_obj[:mitm_rest_api]
1997
- introspection_thread = burp_obj[:introspection_thread]
1998
- introspection_thread.kill unless introspection_thread.nil?
2010
+ introspection_thread_arr = burp_obj[:introspection_threads]
2011
+ introspection_thread_arr.each(&:kill) if introspection_thread_arr.is_a?(Array) && introspection_thread_arr.any?
2012
+ # introspection_thread.kill unless introspection_thread.nil?
1999
2013
 
2000
2014
  PWN::Plugins::TransparentBrowser.close(browser_obj: browser_obj)
2001
2015
  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.506'
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.506
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.