pwn 0.5.532 → 0.5.534

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: 1ac373c33f4440155c8497862905fccff4a379c9ead0e5db1aa47f3239cbb5f3
4
- data.tar.gz: 23a97347a0f5cf48a8c29ba9c06a0e946cb27976b2c9d3b224e025d20e48447a
3
+ metadata.gz: db3ea69e1f438111e509b6804f35881807e884b9fc78f24ce1709b7b9eb48a81
4
+ data.tar.gz: abc44bd86a1c8e7e96021a01781695cc042d42ae80268e9f3628809c8952db3e
5
5
  SHA512:
6
- metadata.gz: 49124cf7885e5208523b3c9cd03f7f033e05121abb21dd2087cbebe67dc9924753e5cd4758fb0a3cc9aa49c39fd0da952be85d31b37127acba419fad792fb6e5
7
- data.tar.gz: dc46bce0905a436a7395f0d1c04dd4b69af82f44d3970dda76232466090f736eaee6cf40aed0dc5b4fb15114c7a0d4492044cc88422faa76f57ea72ca582148c
6
+ metadata.gz: a4d6cb9b3a97311baad192e618e0124cbfa11d29b172860cbbc247109d62de675f0f9279ebc487b923b5cb2d482d478a6261e7cbd6bf6fcd3b498dcef59fb89f
7
+ data.tar.gz: 4e44bdb57b158c6b5129b969dd3411f6a47c2cb15f663399a68df5043ad5bf48f50a20c484e20a05c16607d752d64ae5d1381cdaf53aadf5342ba10a09941cf6
data/.rubocop.yml CHANGED
@@ -18,7 +18,7 @@ Metrics/CyclomaticComplexity:
18
18
  Metrics/MethodLength:
19
19
  Max: 733
20
20
  Metrics/ModuleLength:
21
- Max: 1563
21
+ Max: 1574
22
22
  Metrics/PerceivedComplexity:
23
23
  Max: 157
24
24
  Style/HashEachMethods:
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2025-11-24 21:22:25 UTC using RuboCop version 1.81.7.
3
+ # on 2026-01-26 19:15:57 UTC using RuboCop version 1.82.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -30,7 +30,13 @@ Lint/RedundantTypeConversion:
30
30
  - 'lib/pwn/plugins/jenkins.rb'
31
31
  - 'lib/pwn/plugins/repl.rb'
32
32
 
33
- # Offense count: 294
33
+ # Offense count: 4
34
+ Lint/ShadowedException:
35
+ Exclude:
36
+ - 'lib/pwn/sdr/decoder/flex.rb'
37
+ - 'lib/pwn/sdr/decoder/pocsag.rb'
38
+
39
+ # Offense count: 301
34
40
  # This cop supports safe autocorrection (--autocorrect).
35
41
  Lint/UselessAssignment:
36
42
  Enabled: false
@@ -137,11 +143,13 @@ Style/MultipleComparison:
137
143
  - 'lib/pwn/www/duckduckgo.rb'
138
144
  - 'lib/pwn/www/twitter.rb'
139
145
 
140
- # Offense count: 1
146
+ # Offense count: 5
141
147
  # This cop supports safe autocorrection (--autocorrect).
142
148
  Style/RedundantBegin:
143
149
  Exclude:
144
150
  - 'lib/pwn/plugins/transparent_browser.rb'
151
+ - 'lib/pwn/sdr/decoder/flex.rb'
152
+ - 'lib/pwn/sdr/decoder/pocsag.rb'
145
153
 
146
154
  # Offense count: 94
147
155
  # This cop supports safe autocorrection (--autocorrect).
@@ -151,6 +159,13 @@ Style/RedundantCondition:
151
159
  Exclude:
152
160
  - 'lib/pwn/plugins/packet.rb'
153
161
 
162
+ # Offense count: 2
163
+ # This cop supports safe autocorrection (--autocorrect).
164
+ Style/RedundantSelf:
165
+ Exclude:
166
+ - 'lib/pwn/sdr/decoder/flex.rb'
167
+ - 'lib/pwn/sdr/decoder/pocsag.rb'
168
+
154
169
  # Offense count: 12
155
170
  # This cop supports safe autocorrection (--autocorrect).
156
171
  Style/RedundantStringEscape:
@@ -161,6 +176,13 @@ Style/RedundantStringEscape:
161
176
  - 'lib/pwn/sast/redos.rb'
162
177
  - 'vagrant/provisioners/kali_customize.rb'
163
178
 
179
+ # Offense count: 6
180
+ # This cop supports safe autocorrection (--autocorrect).
181
+ Style/RescueModifier:
182
+ Exclude:
183
+ - 'lib/pwn/sdr/decoder/flex.rb'
184
+ - 'lib/pwn/sdr/decoder/pocsag.rb'
185
+
164
186
  # Offense count: 19
165
187
  # This cop supports unsafe autocorrection (--autocorrect-all).
166
188
  Style/SlicingWithRange:
data/Gemfile CHANGED
@@ -20,7 +20,7 @@ gem 'base32', '0.3.4'
20
20
  gem 'bitcoin-ruby', '0.0.20'
21
21
  gem 'brakeman', '7.1.2'
22
22
  gem 'bson', '5.2.0'
23
- gem 'bundler', '>=4.0.3'
23
+ gem 'bundler', '>=4.0.4'
24
24
  gem 'bundler-audit', '>=0.9.3'
25
25
  gem 'bunny', '2.24.0'
26
26
  gem 'colorize', '1.1.0'
@@ -29,7 +29,7 @@ gem 'curses', '1.5.3'
29
29
  gem 'diffy', '3.4.4'
30
30
  gem 'eventmachine', '1.2.7'
31
31
  gem 'executable-hooks', '1.7.1'
32
- gem 'faker', '3.5.3'
32
+ gem 'faker', '3.6.0'
33
33
  gem 'faye-websocket', '0.12.0'
34
34
  gem 'ffi', '1.17.3'
35
35
  # gem 'fftw3', '0.3'
@@ -49,6 +49,7 @@ gem 'jwt', '3.1.2'
49
49
  gem 'libusb', '0.7.2'
50
50
  gem 'luhn', '3.0.0'
51
51
  gem 'mail', '2.9.0'
52
+ gem 'mcp', '0.6.0'
52
53
  gem 'meshtastic', '0.0.151'
53
54
  gem 'metasm', '1.0.5'
54
55
  gem 'mongo', '2.22.0'
@@ -69,11 +70,11 @@ gem 'packetgen', '4.1.1'
69
70
  gem 'pdf-reader', '2.15.1'
70
71
  gem 'pg', '1.6.3'
71
72
  gem 'pry', '0.16.0'
72
- gem 'pry-doc', '1.6.0'
73
+ gem 'pry-doc', '1.7.0'
73
74
  gem 'rake', '13.3.1'
74
75
  gem 'rb-readline', '0.5.5'
75
76
  gem 'rbvmomi2', '3.8.0'
76
- gem 'rdoc', '7.0.3'
77
+ gem 'rdoc', '7.1.0'
77
78
  gem 'rest-client', '2.1.0'
78
79
  gem 'rex', '2.0.13'
79
80
  gem 'rmagick', '6.1.5'
@@ -89,7 +90,7 @@ gem 'ruby-saml', '1.18.1'
89
90
  gem 'rvm', '1.11.3.9'
90
91
  gem 'savon', '2.15.1'
91
92
  gem 'selenium-devtools', '0.143.0'
92
- gem 'selenium-webdriver', '4.39.0'
93
+ gem 'selenium-webdriver', '4.40.0'
93
94
  gem 'slack-ruby-client', '3.1.0'
94
95
  gem 'socksify', '1.8.1'
95
96
  gem 'spreadsheet', '1.3.4'
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.532]:001 >>> PWN.help
40
+ pwn[v0.5.534]: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-4.0.0@pwn
52
52
  $ gem uninstall --all --executables pwn
53
53
  $ gem install --verbose pwn
54
54
  $ pwn
55
- pwn[v0.5.532]:001 >>> PWN.help
55
+ pwn[v0.5.534]: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-4.0.0@pwn
62
62
  $ rvmsudo gem uninstall --all --executables pwn
63
63
  $ rvmsudo gem install --verbose pwn
64
64
  $ pwn
65
- pwn[v0.5.532]:001 >>> PWN.help
65
+ pwn[v0.5.534]: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:
@@ -124,6 +124,7 @@ module PWN
124
124
  highlight_color
125
125
  end
126
126
 
127
+ default_http_ports = [80, 443]
127
128
  loop do
128
129
  # TODO: Implement repeater into the loop? This reduces load to LLM but is slooow.
129
130
  # Repeater should analyze the reqesut/response pair and suggest
@@ -133,15 +134,20 @@ module PWN
133
134
  sitemap = get_sitemap(burp_obj: burp_obj)
134
135
  proxy_history = get_proxy_history(burp_obj: burp_obj)
135
136
  proxy_history.each do |entry|
136
- next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
137
-
138
137
  request = entry[:request]
139
138
  response = entry[:response]
140
- host = entry[:http_service][:host]
141
- port = entry[:http_service][:port]
142
- protocol = entry[:http_service][:protocol]
139
+ http_service = entry[:http_service]
140
+ protocol = http_service[:protocol]
141
+ host = http_service[:host]
142
+ port = http_service[:port]
143
143
  next if request.nil? || response.nil? || host.nil? || port.nil? || protocol.nil?
144
144
 
145
+ uri = "#{protocol}://#{host}"
146
+ uri = "#{protocol}://#{host}:#{port}" unless default_http_ports.include?(port)
147
+ next unless in_scope(burp_obj: burp_obj, uri: uri)
148
+
149
+ next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
150
+
145
151
  # If sitemap comment and highlight color exists, use that instead of re-analyzing
146
152
  sitemap_entry = nil
147
153
  if sitemap.any?
@@ -186,15 +192,20 @@ module PWN
186
192
  proxy_history = get_proxy_history(burp_obj: burp_obj)
187
193
  sitemap = get_sitemap(burp_obj: burp_obj)
188
194
  sitemap.each do |entry|
189
- next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
190
-
191
195
  request = entry[:request]
192
196
  response = entry[:response]
193
- host = entry[:http_service][:host]
194
- port = entry[:http_service][:port]
195
- protocol = entry[:http_service][:protocol]
197
+ http_service = entry[:http_service]
198
+ protocol = http_service[:protocol]
199
+ host = http_service[:host]
200
+ port = http_service[:port]
196
201
  next if request.nil? || response.nil? || host.nil? || port.nil? || protocol.nil?
197
202
 
203
+ uri = "#{protocol}://#{host}"
204
+ uri = "#{protocol}://#{host}:#{port}" unless default_http_ports.include?(port)
205
+ next unless in_scope(burp_obj: burp_obj, uri: uri)
206
+
207
+ next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
208
+
198
209
  proxy_history_entry = nil
199
210
  if proxy_history.any?
200
211
  proxy_history_entry = proxy_history.find do |proxy_entry|
@@ -236,6 +247,9 @@ module PWN
236
247
  when :websocket_history
237
248
  websocket_history = get_websocket_history(burp_obj: burp_obj)
238
249
  websocket_history.each do |entry|
250
+ uri = entry[:url]
251
+ next unless in_scope(burp_obj: burp_obj, uri: uri)
252
+
239
253
  next unless entry.key?(:comment) && entry[:comment].to_s.strip.empty?
240
254
 
241
255
  web_socket_id = entry[:web_socket_id]
@@ -60,6 +60,50 @@ module PWN
60
60
  raise e
61
61
  end
62
62
 
63
+ # Supported Method Parameters:
64
+ # PWN::Plugins::FileFu.shift_file_up(
65
+ # path: 'required - path to file to shift up',
66
+ # bytes: 'required - number of bytes to shift up (remove from beginning)',
67
+ # buffer_size: 'optional - buffer size to use when shifting (default: 256KB)'
68
+ # )
69
+
70
+ public_class_method def self.shift_file_up(opts = {})
71
+ path = opts[:path].to_s.scrub
72
+ raise "PWN Error: File #{path} does not exist" unless File.exist?(path)
73
+
74
+ bytes = opts[:bytes].to_i
75
+ raise 'PWN Error: bytes must be greater than or equal to 0' unless bytes >= 0
76
+
77
+ # Default buffer size = 256 KiB — good general-purpose value
78
+ buffer_size = (opts[:buffer_size] || (256 * 1024)).to_i
79
+ raise 'PWN Error: buffer_size must be greater than 0' unless buffer_size.positive?
80
+
81
+ # 'r+b' = read/write + binary mode
82
+ File.open(path, 'r+b') do |f|
83
+ size = f.stat.size
84
+ break if bytes >= size
85
+
86
+ read_pos = bytes
87
+ write_pos = 0
88
+ buffer = String.new(capacity: buffer_size)
89
+
90
+ while read_pos < size
91
+ f.seek(read_pos)
92
+ chunk = f.read(buffer_size, buffer) or break
93
+
94
+ bytes_read = chunk.bytesize
95
+
96
+ f.seek(write_pos)
97
+ f.write(buffer.byteslice(0, bytes_read))
98
+
99
+ read_pos += bytes_read
100
+ write_pos += bytes_read
101
+ end
102
+
103
+ f.truncate(size - bytes)
104
+ end
105
+ end
106
+
63
107
  # Author(s):: 0day Inc. <support@0dayinc.com>
64
108
 
65
109
  public_class_method def self.authors
@@ -85,6 +129,12 @@ module PWN
85
129
  destination: 'required - destination folder to save extracted contents'
86
130
  )
87
131
 
132
+ #{self}.shift_file_up(
133
+ path: 'required - path to file to shift up',
134
+ bytes: 'required - number of bytes to shift up',
135
+ buffer_size: 'optional - buffer size to use when shifting file up (default: 256 * 1024 / i.e 256KB)'
136
+ )
137
+
88
138
  #{self}.authors
89
139
  "
90
140
  end
@@ -113,89 +113,151 @@ module PWN
113
113
 
114
114
  # Supported Method Parameters::
115
115
  # PWN::Plugins::Sock.check_port_in_use(
116
- # server_ip: 'optional - target host or ip to check (Defaults to 127.0.0.1)',
117
116
  # port: 'required - target port',
117
+ # server_ip: 'optional - target host or ip to check (Defaults to 127.0.0.1)',
118
118
  # protocol: 'optional - :tcp || :udp (defaults to tcp)'
119
119
  # )
120
120
 
121
121
  public_class_method def self.check_port_in_use(opts = {})
122
- server_ip = opts[:server_ip]
123
- server_ip ||= '127.0.0.1'
124
- port = opts[:port]
125
- protocol = opts[:protocol]
126
- protocol ||= :tcp
122
+ server_ip = opts[:server_ip] ||= '127.0.0.1'
123
+ port = opts[:port]
124
+ protocol = (opts[:protocol] ||= :tcp).to_s.downcase.to_sym
127
125
 
128
- # TODO: Add proxy support
126
+ ct = 0.5 # connect timeout in seconds
129
127
 
130
- ct = 1
131
- s = Socket.tcp(server_ip, port, connect_timeout: ct) if protocol == :tcp
132
- s = Socket.udp(server_ip, port, connect_timeout: ct) if protocol == :udp
133
- s.close
128
+ case protocol
129
+ when :tcp
130
+ # Use &:close intead of block
131
+ Socket.tcp(server_ip, port, connect_timeout: ct, &:close)
132
+ # Port is already in use (or no permission)
133
+ true
134
134
 
135
- true
136
- rescue Errno::ECONNREFUSED,
137
- Errno::EHOSTUNREACH,
138
- Errno::ETIMEDOUT
135
+ when :udp
136
+ socket = UDPSocket.new
137
+ socket.bind(server_ip, port)
138
+ # Port is NOT in use (or at least we can use it)
139
+ false
140
+ else
141
+ raise "Unsupported protocol: #{protocol}"
142
+ end
143
+ rescue Errno::EADDRINUSE, # address already in use
144
+ Errno::EACCES # permission denied
145
+
146
+ state = true if protocol == :udp
147
+ state = false if protocol == :tcp
148
+
149
+ state
150
+ rescue Errno::ECONNREFUSED, # connection refused (usually means port exists but no listener)
151
+ Errno::EHOSTUNREACH, # host unreachable
152
+ Errno::ETIMEDOUT # connection timed out
153
+
154
+ # Port is NOT in use (or at least we can use it)
155
+ false
156
+ rescue SocketError => e
157
+ # Usually means invalid address / interface
158
+ raise "Socket error while checking port #{port}: #{e.message}"
159
+ rescue StandardError => e
160
+ warn "[!] Unexpected error while checking port: #{e.class} – #{e.message}"
139
161
  false
162
+ ensure
163
+ socket.close if protocol == :udp && !socket.nil?
140
164
  end
141
165
 
142
166
  # Supported Method Parameters::
143
- # PWN::Plugins::Sock.listen(
144
- # server_ip: 'required - target host or ip to listen',
167
+ # listen_obj = PWN::Plugins::Sock.listen(
145
168
  # port: 'required - target port',
169
+ # server_ip: 'optional - target host or ip to listen (Defaults to 127.0.0.1')',
146
170
  # protocol: 'optional - :tcp || :udp (defaults to tcp)',
147
- # tls: 'optional - boolean listen on TLS-enabled socket (defaults to false)'
171
+ # tls: 'optional - boolean listen on TLS-enabled socket (defaults to false)',
172
+ # detach: 'optional - boolean to detach listener to background (defaults to false)'
148
173
  # )
149
174
 
150
175
  public_class_method def self.listen(opts = {})
151
- server_ip = opts[:server_ip].to_s.scrub
152
- port = opts[:port].to_i
153
- opts[:protocol].nil? ? protocol = :tcp : protocol = opts[:protocol].to_s.downcase.to_sym
154
- tls = true if opts[:tls]
155
- tls ||= false
176
+ port = opts[:port]
177
+ raise 'ERROR: Missing required parameter: port' if port.nil?
178
+
179
+ server_ip = opts[:server_ip] ||= '127.0.0.1'
180
+ protocol = (opts[:protocol] ||= :tcp).to_s.downcase.to_sym
181
+ tls = opts[:tls] || false
182
+ detach = opts[:detach] || false
183
+
184
+ listen_obj = nil
156
185
 
157
186
  case protocol
158
187
  when :tcp
188
+ server = TCPServer.open(server_ip, port)
189
+
159
190
  if tls
160
- # Multi-threaded - Not working
161
- sock = TCPServer.open(server_ip, port)
162
191
  tls_context = OpenSSL::SSL::SSLContext.new
163
192
  tls_context.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
164
- listen_obj = OpenSSL::SSL::SSLServer.new(sock, tls_context)
165
- # loop do
166
- # Thread.start(listen_obj.accept) do |client_thread|
167
- # while (client_input = client_thread.gets)
168
- # puts client_input
169
- # end
170
- # client_thread.close
171
- # end
172
- # end
193
+ # TODO: min_version, ciphers, etc.
194
+ listen_obj = OpenSSL::SSL::SSLServer.new(server, tls_context)
173
195
  else
174
- # Multi-threaded
175
- listen_obj = TCPServer.open(server_ip, port)
196
+ listen_obj = server
197
+ end
198
+
199
+ unless detach
200
+ # Default blocking mode - simple accept-and-handle loop
201
+ # puts "[*] Listening on #{server_ip}:#{port} (#{tls ? 'TLS' : 'plain'} TCP)..."
202
+
176
203
  loop do
177
- Thread.start(listen_obj.accept) do |client_thread|
178
- while (client_input = client_thread.gets)
179
- puts client_input
204
+ client = listen_obj.accept
205
+ Thread.new(client) do |c|
206
+ peer = c.peeraddr
207
+ puts "[+] Connection from #{peer}"
208
+
209
+ while (data = c.gets)
210
+ puts "[#{peer}] #{data.strip}"
211
+ # Optional: echo back
212
+ # c.puts "ECHO: #{data}"
180
213
  end
181
- client_thread.close
214
+ rescue Errno::ECONNRESET, Errno::EPIPE, IOError
215
+ # Client disconnected
216
+ ensure
217
+ client.close unless client.nil?
182
218
  end
183
219
  end
184
220
  end
221
+
185
222
  when :udp
186
- # Single Threaded
187
223
  listen_obj = UDPSocket.new
188
224
  listen_obj.bind(server_ip, port)
189
- while (client_input = listen_obj.recvmsg)
190
- puts client_input[0]
225
+
226
+ # puts "[*] Listening on #{server_ip}:#{port} (UDP)..."
227
+
228
+ unless detach
229
+ # Simple single-threaded UDP receive loop
230
+ loop do
231
+ msg, addrinfo = listen_obj.recvmsg
232
+ next unless msg && !msg.empty?
233
+
234
+ peer = "#{addrinfo.ip_address}:#{addrinfo.ip_port}"
235
+ puts "[#{peer}] #{msg.inspect}"
236
+ # Optional: echo back
237
+ # listen_obj.send("ECHO: #{msg}", 0, addrinfo.ip_address, addrinfo.ip_port)
238
+ end
191
239
  end
240
+
192
241
  else
193
242
  raise "Unsupported protocol: #{protocol}"
194
243
  end
244
+
245
+ loop do
246
+ listening = check_port_in_use(
247
+ server_ip: server_ip,
248
+ port: port,
249
+ protocol: protocol
250
+ )
251
+ break if listening
252
+ end
253
+
254
+ listen_obj
255
+ rescue Interrupt
256
+ puts "\n[!] Caught interrupt, shutting down listener..."
195
257
  rescue StandardError => e
196
- raise e
258
+ raise
197
259
  ensure
198
- listen_obj = disconnect(sock_obj: listen_obj) unless listen_obj.nil?
260
+ listen_obj.close unless listen_obj.nil? || detach
199
261
  end
200
262
 
201
263
  # Supported Method Parameters::
@@ -275,11 +337,12 @@ module PWN
275
337
  protocol: 'optional - :tcp || :udp (defaults to tcp)'
276
338
  )
277
339
 
278
- #{self}.listen(
279
- server_ip: 'required - target host or ip to listen',
340
+ listen_obj = #{self}.listen(
280
341
  port: 'required - target port',
342
+ server_ip: 'optional - target host or ip to listen (Defaults to 127.0.0.1')',
281
343
  protocol: 'optional - :tcp || :udp (defaults to tcp)',
282
- tls: 'optional - boolean listen on TLS-enabled socket (defaults to false)'
344
+ tls: 'optional - boolean listen on TLS-enabled socket (defaults to false)',
345
+ detach: 'optional - boolean to detach listener to background (defaults to false)'
283
346
  )
284
347
 
285
348
  cert_obj = #{self}.get_tls_cert(