pwn 0.5.710 → 0.5.712

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: bb2089e549bccd1c21a643fd22719f13cb3a7519c1580f9cbd3e425c66f2be91
4
- data.tar.gz: d27e48a928750b279f8315e8a578071bed21403728ae7f8c5474015f75ff557e
3
+ metadata.gz: 24bf2b4c619ee3d57fe991bff09ab97838506283144fbcde635d39c7e368a3b1
4
+ data.tar.gz: 1ed8d4f63cfc8331fd494172e65724037131a378cd42716df2d36e22dfdce6d5
5
5
  SHA512:
6
- metadata.gz: 37c74e1e2ab80b6a872f0d533ec402b520bffd70dc1198114574b3bbe90383c9dbebe6ac9b844e79023eed1cdeefc6cb8df4cca964b186cff1e25bc718384b12
7
- data.tar.gz: 703c871173f4a754b9a515b45c4fd6aa4d3e2b1590f397168a53869d7eed5a77243a69e635f3894ce61be401b4c260395b0be7b435d6dc0613067b7b9047345c
6
+ metadata.gz: d8ce0b58ac26c52adacedd0ae58df169357d87d53f1e5040d9c6eba4083bf83545065c8e504a6f2e7baebb84409b807af99fa6ef2cfd148682e898962794b67e
7
+ data.tar.gz: 712a254b7346e7eb3668634c1b47bf336dce6393e960ad1ed24e0d0abc812752ed1cd442f277c44bd6b1c3360472b8d44075418758909fd7bbf435ea2d8ebe2f
@@ -103,10 +103,14 @@ pwn setup --list-profiles
103
103
  `--deps` / `--profile` will:
104
104
 
105
105
  1. Resolve the profile → set of native gems + external binaries.
106
- 2. Map those to OS packages for **your** package manager (data lives in
107
- `PWN::Setup::NATIVE_GEMS` / `::TOOLCHAIN` - versioned with the gem, so
108
- `gem install --verbose pwn`, git checkout, Docker, Packer and Vagrant all read the
109
- same table).
106
+ 2. Map those to OS packages for **this** distro and version
107
+ (`PWN::Plugins::DetectOS.distro` / `.version`, e.g. Kali `2026.3` vs Ubuntu
108
+ `24.04`) via `PWN::Setup.packages_for`. Family fallbacks still live in
109
+ `PWN::Setup::NATIVE_GEMS` / `::TOOLCHAIN`. Tools with no OS package on this
110
+ distro (Frida, one_gadget, ROPgadget, checksec, ropper, kube-hunter, or
111
+ Kali-only names on Ubuntu) install via `pipx` (Debian/Kali/Ubuntu) or `pip`
112
+ / `gem`, or are skipped so one missing apt name cannot abort the whole
113
+ profile. Each OS package is installed in its own `apt-get`/`dnf`/… command.
110
114
  3. Show the exact commands, prompt (unless `--yes`), run them, then
111
115
  `gem pristine` / `gem install` any native extension that still fails to
112
116
  load, and re-run the doctor.
@@ -12,7 +12,7 @@ metadata:
12
12
 
13
13
  # PWN::Plugins::DetectOS
14
14
 
15
- This plugin converts images to readable text
15
+ Detect host OS family, distro flavor, and version string.
16
16
 
17
17
  ## When to use
18
18
 
@@ -36,6 +36,8 @@ PWN::Plugins::DetectOS.type(opts)
36
36
  - `type`
37
37
  - `arch`
38
38
  - `endian`
39
+ - `distro`
40
+ - `version`
39
41
  - `authors`
40
42
  - `help`
41
43
 
@@ -28,11 +28,12 @@ Class methods take `(opts = {})` and read `opts`.
28
28
 
29
29
  ```ruby
30
30
  PWN::Setup.help
31
- PWN::Setup.pkg_manager(opts)
31
+ PWN::Setup.packages_for(opts)
32
32
  ```
33
33
 
34
34
  ## Public methods
35
35
 
36
+ - `packages_for`
36
37
  - `pkg_manager`
37
38
  - `check`
38
39
  - `deps`
@@ -43,11 +44,15 @@ PWN::Setup.pkg_manager(opts)
43
44
  - `authors`
44
45
  - `help`
45
46
 
47
+ ## References
48
+
49
+ - `references/urls.md` — URLs from source
50
+
46
51
  ## Source
47
52
 
48
53
  `pwn/setup.rb`
49
54
 
50
55
  ## Verification
51
56
 
52
- `PWN::Setup.respond_to?(:pkg_manager)` after the
57
+ `PWN::Setup.respond_to?(:packages_for)` after the
53
58
  module is loaded. Read the source for parameter names.
@@ -0,0 +1,3 @@
1
+ # PWN::Setup source links
2
+
3
+ - https://install.pwndbg.re
@@ -10,7 +10,7 @@ module PWN
10
10
  WORDLISTS = File.join(Dir.home, '.pwn', 'wordlists')
11
11
 
12
12
  public_class_method def self.required_bins
13
- []
13
+ %w[hydra john hashcat medusa]
14
14
  end
15
15
 
16
16
  public_class_method def self.wordlist_dir(opts = {})
@@ -4,10 +4,28 @@ require 'os'
4
4
 
5
5
  module PWN
6
6
  module Plugins
7
- # This plugin converts images to readable text
7
+ # Detect host OS family, distro flavor, and version string.
8
8
  module DetectOS
9
- # Supported Method Parameters::
10
- # PWN::Plugins::DetectOS.type
9
+ ID_ALIASES = {
10
+ 'chromiumos' => :chromeos,
11
+ 'chromeos' => :chromeos,
12
+ 'pop_os' => :pop,
13
+ 'pop' => :pop,
14
+ 'ol' => :oracle,
15
+ 'opensuse-leap' => :opensuse,
16
+ 'opensuse-tumbleweed' => :opensuse,
17
+ 'sles' => :suse,
18
+ 'darwin' => :macos,
19
+ 'osx' => :macos,
20
+ 'macos' => :macos,
21
+ 'iphoneos' => :ios,
22
+ 'ipados' => :ios,
23
+ 'ios' => :ios,
24
+ 'win32' => :windows,
25
+ 'mingw32' => :windows,
26
+ 'mingw' => :windows,
27
+ 'mswin' => :windows
28
+ }.freeze
11
29
 
12
30
  public_class_method def self.type
13
31
  os = :cygwin if OS.cygwin?
@@ -23,18 +41,12 @@ module PWN
23
41
  raise e
24
42
  end
25
43
 
26
- # Supported Method Parameters::
27
- # PWN::Plugins::DetectOS.arch
28
-
29
44
  public_class_method def self.arch
30
45
  OS.host_cpu
31
46
  rescue StandardError => e
32
47
  raise e
33
48
  end
34
49
 
35
- # Supported Method Parameters::
36
- # PWN::Plugins::DetectOS.endian
37
-
38
50
  public_class_method def self.endian
39
51
  if [1].pack('I') == [1].pack('N')
40
52
  :big
@@ -45,7 +57,99 @@ module PWN
45
57
  raise e
46
58
  end
47
59
 
48
- # Author(s):: 0day Inc. <support@0dayinc.com>
60
+ # Supported Method Parameters::
61
+ # PWN::Plugins::DetectOS.distro(
62
+ # os_release: 'optional - /etc/os-release body (defaults to reading the file)',
63
+ # lsb_release: 'optional - /etc/lsb-release body',
64
+ # build_prop: 'optional - Android /system/build.prop body',
65
+ # type: 'optional - OS family from #type (e.g. :linux :osx :windows :freebsd)',
66
+ # platform: 'optional - RUBY_PLATFORM override',
67
+ # uname: 'optional - uname -s string',
68
+ # sw_vers: 'optional - macOS/iOS product version string',
69
+ # win_ver: 'optional - Windows ver command output'
70
+ # )
71
+
72
+ public_class_method def self.distro(opts = {})
73
+ return normalize_id(id: opts[:distro]) if opts[:distro]
74
+
75
+ platform = (opts[:platform] || RUBY_PLATFORM).to_s.downcase
76
+ uname = (opts[:uname] || live_uname_s).to_s.downcase
77
+ os_type = opts[:type] || type
78
+ osr = parse_kv(content: opts[:os_release] || read_if_present(path: '/etc/os-release') || read_if_present(path: '/usr/lib/os-release'))
79
+ lsb = parse_kv(content: opts[:lsb_release] || read_if_present(path: '/etc/lsb-release'))
80
+ prop = parse_kv(content: opts[:build_prop] || read_if_present(path: '/system/build.prop'))
81
+
82
+ return :ios if ios_host?(platform: platform, uname: uname)
83
+ return :android if android_host?(osr: osr, prop: prop, uname: uname)
84
+ return :chromeos if chromeos_host?(osr: osr, lsb: lsb)
85
+ return :macos if os_type == :osx || platform.include?('darwin')
86
+ return :windows if os_type == :windows || platform.match?(/mswin|mingw|cygwin/)
87
+ return :freebsd if os_type == :freebsd || uname.include?('freebsd')
88
+ return :openbsd if os_type == :openbsd || uname.include?('openbsd')
89
+ return :netbsd if os_type == :netbsd || uname.include?('netbsd')
90
+ return :dragonfly if uname.include?('dragonfly')
91
+ return :cygwin if os_type == :cygwin
92
+
93
+ id = osr['ID'].to_s
94
+ return normalize_id(id: id) unless id.empty?
95
+
96
+ like = osr['ID_LIKE'].to_s.downcase
97
+ return :debian if like.include?('debian')
98
+ return :fedora if like.include?('fedora') || like.include?('rhel')
99
+ return :arch if like.include?('arch')
100
+ return :suse if like.include?('suse')
101
+
102
+ os_type || :unknown
103
+ end
104
+
105
+ # Supported Method Parameters::
106
+ # PWN::Plugins::DetectOS.version(
107
+ # os_release: 'optional - /etc/os-release body',
108
+ # lsb_release: 'optional - /etc/lsb-release body',
109
+ # build_prop: 'optional - Android build.prop body',
110
+ # sw_vers: 'optional - macOS/iOS product version',
111
+ # win_ver: 'optional - Windows ver output',
112
+ # uname_r: 'optional - uname -r string',
113
+ # type: 'optional - OS family from #type'
114
+ # )
115
+
116
+ public_class_method def self.version(opts = {})
117
+ return opts[:version].to_s if opts[:version]
118
+
119
+ injected = %i[os_release lsb_release build_prop sw_vers win_ver uname_r].any? { |k| opts.key?(k) }
120
+ os_type = opts[:type] || type
121
+ osr = parse_kv(content: opts[:os_release] || (injected ? nil : read_if_present(path: '/etc/os-release') || read_if_present(path: '/usr/lib/os-release')))
122
+ lsb = parse_kv(content: opts[:lsb_release] || (injected ? nil : read_if_present(path: '/etc/lsb-release')))
123
+ prop = parse_kv(content: opts[:build_prop] || (injected ? nil : read_if_present(path: '/system/build.prop')))
124
+
125
+ from_osr = osr['VERSION_ID'].to_s
126
+ return from_osr unless from_osr.empty?
127
+
128
+ chrome = lsb['CHROMEOS_RELEASE_VERSION'].to_s
129
+ return chrome unless chrome.empty?
130
+
131
+ android = prop['ro.build.version.release'].to_s
132
+ return android unless android.empty?
133
+
134
+ if os_type == :osx || opts[:sw_vers]
135
+ mac = (opts[:sw_vers] || live_sw_vers).to_s.strip
136
+ return mac unless mac.empty?
137
+ end
138
+
139
+ if os_type == :windows || opts[:win_ver]
140
+ win = (opts[:win_ver] || live_win_ver).to_s
141
+ m = win.match(/\[Version\s+([^\]]+)\]/i) || win.match(/(\d+\.\d+(?:\.\d+)*)/)
142
+ return m[1] if m
143
+ end
144
+
145
+ rel = (opts[:uname_r] || live_uname_r).to_s.strip
146
+ return rel if %i[freebsd openbsd netbsd].include?(os_type) && !rel.empty?
147
+
148
+ debian = read_if_present(path: '/etc/debian_version').to_s.strip
149
+ return debian unless debian.empty?
150
+
151
+ osr['VERSION'].to_s
152
+ end
49
153
 
50
154
  public_class_method def self.authors
51
155
  "AUTHOR(S):
@@ -53,24 +157,129 @@ module PWN
53
157
  "
54
158
  end
55
159
 
56
- # Display Usage for this Module
57
-
58
160
  public_class_method def self.help
59
161
  puts "USAGE:
60
- # Run type and return its result
162
+ # Return the OS family as a symbol (:linux :osx :windows :freebsd :openbsd :netbsd :cygwin).
61
163
  #{self}.type
62
164
 
63
- # Run arch and return its result
165
+ # Return the CPU architecture string from the host (e.g. x86_64, arm64).
64
166
  #{self}.arch
65
167
 
66
- # Run endian and return its result
168
+ # Return CPU endianness as :little or :big.
67
169
  #{self}.endian
68
170
 
171
+ # Return the distro flavor as a lowercase symbol (:kali :ubuntu :macos :windows :freebsd …).
172
+ #{self}.distro(
173
+ os_release: 'optional - /etc/os-release body (defaults to reading the file)',
174
+ lsb_release: 'optional - /etc/lsb-release body',
175
+ build_prop: 'optional - Android /system/build.prop body',
176
+ type: 'optional - OS family from #type (e.g. :linux :osx :windows :freebsd)',
177
+ platform: 'optional - RUBY_PLATFORM override (detect iOS/Android/Windows)',
178
+ uname: 'optional - uname -s string',
179
+ sw_vers: 'optional - macOS/iOS product version string',
180
+ win_ver: 'optional - Windows ver command output',
181
+ distro: 'optional - force a distro id instead of detecting'
182
+ )
183
+
184
+ # Return the distro version as a string (e.g. 2026.3, 24.04, 15.1, 14.1-RELEASE).
185
+ #{self}.version(
186
+ os_release: 'optional - /etc/os-release body',
187
+ lsb_release: 'optional - /etc/lsb-release body',
188
+ build_prop: 'optional - Android build.prop body',
189
+ sw_vers: 'optional - macOS/iOS product version',
190
+ win_ver: 'optional - Windows ver output',
191
+ uname_r: 'optional - uname -r string',
192
+ type: 'optional - OS family from #type',
193
+ version: 'optional - force a version string instead of detecting'
194
+ )
195
+
69
196
  # Print the AUTHOR(S) string for this module.
70
197
  #{self}.authors
71
198
  "
72
199
  constants.sort
73
200
  end
201
+
202
+ private_class_method def self.normalize_id(opts = {})
203
+ raw = opts[:id].to_s.downcase.strip.gsub(/["']/, '')
204
+ return :unknown if raw.empty?
205
+
206
+ ID_ALIASES[raw] || raw.tr('-', '_').to_sym
207
+ end
208
+
209
+ private_class_method def self.parse_kv(opts = {})
210
+ content = opts[:content].to_s
211
+ return {} if content.empty?
212
+
213
+ content.each_line.with_object({}) do |line, acc|
214
+ next if line.strip.empty? || line.strip.start_with?('#')
215
+
216
+ key, val = line.split('=', 2)
217
+ next unless val
218
+
219
+ acc[key.strip] = val.strip.gsub(/\A["']|["']\z/, '')
220
+ end
221
+ end
222
+
223
+ private_class_method def self.read_if_present(opts = {})
224
+ path = opts[:path].to_s
225
+ return unless File.readable?(path)
226
+
227
+ File.read(path)
228
+ rescue StandardError
229
+ nil
230
+ end
231
+
232
+ private_class_method def self.ios_host?(opts = {})
233
+ blob = "#{opts[:platform]} #{opts[:uname]}"
234
+ blob.match?(/iphone|ipad|ios/)
235
+ end
236
+
237
+ private_class_method def self.android_host?(opts = {})
238
+ osr = opts[:osr] || {}
239
+ prop = opts[:prop] || {}
240
+ uname = opts[:uname].to_s
241
+ osr['ID'].to_s.downcase == 'android' ||
242
+ !prop['ro.build.version.release'].to_s.empty? ||
243
+ uname.include?('android') ||
244
+ File.exist?('/system/build.prop')
245
+ end
246
+
247
+ private_class_method def self.chromeos_host?(opts = {})
248
+ osr = opts[:osr] || {}
249
+ lsb = opts[:lsb] || {}
250
+ id = osr['ID'].to_s.downcase
251
+ id == 'chromeos' || id == 'chromiumos' ||
252
+ !lsb['CHROMEOS_RELEASE_NAME'].to_s.empty? ||
253
+ !lsb['CHROMEOS_RELEASE_VERSION'].to_s.empty?
254
+ end
255
+
256
+ private_class_method def self.live_uname_s(opts = {})
257
+ opts[:skip]
258
+ `uname -s 2>/dev/null`.to_s
259
+ rescue StandardError
260
+ ''
261
+ end
262
+
263
+ private_class_method def self.live_uname_r(opts = {})
264
+ opts[:skip]
265
+ `uname -r 2>/dev/null`.to_s
266
+ rescue StandardError
267
+ ''
268
+ end
269
+
270
+ private_class_method def self.live_sw_vers(opts = {})
271
+ opts[:skip]
272
+ `sw_vers -productVersion 2>/dev/null`.to_s
273
+ rescue StandardError
274
+ ''
275
+ end
276
+
277
+ private_class_method def self.live_win_ver(opts = {})
278
+ opts[:skip]
279
+ `ver 2>NUL`.to_s
280
+ rescue StandardError
281
+ ''
282
+ end
74
283
  end
75
284
  end
76
285
  end
@@ -23,7 +23,11 @@ module PWN
23
23
  'PWN::Plugins::BurpSuite' => { bins: %w[burpsuite] },
24
24
  'PWN::Plugins::Zaproxy' => { bins: %w[zaproxy] },
25
25
  'PWN::Plugins::Packet' => { bins: [], caps: %w[CAP_NET_RAW] },
26
- 'PWN::Plugins::K8s' => { bins: %w[trivy], services: [{ name: 'docker', path: '/var/run/docker.sock' }] }
26
+ 'PWN::Plugins::K8s' => { bins: %w[trivy], services: [{ name: 'docker', path: '/var/run/docker.sock' }] },
27
+ 'PWN::Plugins::Semgrep' => { bins: %w[semgrep] },
28
+ 'PWN::Plugins::ExploitDB' => { bins: %w[searchsploit] },
29
+ 'PWN::Plugins::Recon' => { bins: %w[subfinder httpx] },
30
+ 'PWN::Plugins::CredentialAttack' => { bins: %w[hydra john hashcat] }
27
31
  }.freeze
28
32
 
29
33
  public_class_method def self.required_bins
@@ -13,7 +13,7 @@ module PWN
13
13
  UA = 'pwn-recon/1.0'
14
14
 
15
15
  public_class_method def self.required_bins
16
- []
16
+ %w[subfinder httpx masscan amass]
17
17
  end
18
18
 
19
19
  public_class_method def self.subdomains(opts = {})
data/lib/pwn/setup.rb CHANGED
@@ -160,7 +160,7 @@ module PWN
160
160
  },
161
161
  'sqlmap' => {
162
162
  apt: %w[sqlmap], dnf: %w[sqlmap], pacman: %w[sqlmap], brew: %w[sqlmap], port: %w[],
163
- plugins: %w[PWN::Plugins::Fuzz]
163
+ plugins: %w[PWN::Plugins::Sqlmap PWN::Plugins::Fuzz]
164
164
  },
165
165
  'tor' => {
166
166
  apt: %w[tor], dnf: %w[tor], pacman: %w[tor], brew: %w[tor], port: %w[tor],
@@ -246,23 +246,28 @@ module PWN
246
246
  plugins: %w[PWN::Plugins::Radare2]
247
247
  },
248
248
  'checksec' => {
249
- apt: %w[], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
249
+ apt: %w[], dnf: %w[], pacman: %w[checksec], brew: %w[], port: %w[],
250
+ pip: 'checksec.py',
250
251
  plugins: %w[PWN::Plugins::GDB PWN::Plugins::ExploitDev]
251
252
  },
252
253
  'ROPgadget' => {
253
254
  apt: %w[], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
255
+ pip: 'ROPGadget',
254
256
  plugins: %w[PWN::Plugins::ExploitDev]
255
257
  },
256
258
  'one_gadget' => {
257
259
  apt: %w[], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
260
+ gem: 'one_gadget',
258
261
  plugins: %w[PWN::Plugins::ExploitDev]
259
262
  },
260
263
  'pwndbg' => {
261
264
  apt: %w[pwndbg], dnf: %w[], pacman: %w[pwndbg], brew: %w[], port: %w[],
265
+ script: "curl --proto '=https' --tlsv1.2 -LsSf 'https://install.pwndbg.re' | sh -s -- -t pwndbg-gdb",
262
266
  plugins: %w[PWN::Plugins::GDB]
263
267
  },
264
268
  'ropper' => {
265
269
  apt: %w[], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
270
+ pip: 'ropper',
266
271
  plugins: %w[PWN::Plugins::ExploitDev]
267
272
  },
268
273
  'rizin' => {
@@ -280,6 +285,7 @@ module PWN
280
285
  },
281
286
  'frida' => {
282
287
  apt: %w[], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
288
+ pip: 'frida-tools',
283
289
  plugins: %w[PWN::Plugins::Frida]
284
290
  },
285
291
  'apktool' => {
@@ -297,8 +303,90 @@ module PWN
297
303
  'hydra' => {
298
304
  apt: %w[hydra], dnf: %w[hydra], pacman: %w[hydra], brew: %w[thc-hydra], port: %w[],
299
305
  plugins: %w[PWN::Plugins::CredentialAttack]
306
+ },
307
+ 'afl-fuzz' => {
308
+ apt: %w[afl++], dnf: %w[afl++], pacman: %w[afl++], brew: %w[afl++], port: %w[],
309
+ plugins: %w[PWN::Plugins::AFLplusplus]
310
+ },
311
+ 'searchsploit' => {
312
+ apt: %w[exploitdb], dnf: %w[], pacman: %w[exploitdb], brew: %w[], port: %w[],
313
+ plugins: %w[PWN::Plugins::ExploitDB]
314
+ },
315
+ 'trivy' => {
316
+ apt: %w[trivy], dnf: %w[trivy], pacman: %w[trivy], brew: %w[trivy], port: %w[],
317
+ plugins: %w[PWN::Plugins::K8s]
318
+ },
319
+ 'kube-hunter' => {
320
+ apt: %w[], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
321
+ pip: 'kube-hunter',
322
+ plugins: %w[PWN::Plugins::K8s]
323
+ },
324
+ 'semgrep' => {
325
+ apt: %w[semgrep], dnf: %w[], pacman: %w[], brew: %w[semgrep], port: %w[],
326
+ pip: 'semgrep',
327
+ plugins: %w[PWN::Plugins::Semgrep]
328
+ },
329
+ 'vol' => {
330
+ apt: %w[volatility3], dnf: %w[], pacman: %w[volatility3], brew: %w[], port: %w[],
331
+ pip: 'volatility3',
332
+ plugins: %w[PWN::Plugins::Volatility]
333
+ },
334
+ 'subfinder' => {
335
+ apt: %w[subfinder], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
336
+ plugins: %w[PWN::Plugins::Recon]
337
+ },
338
+ 'httpx' => {
339
+ apt: %w[httpx-toolkit], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
340
+ plugins: %w[PWN::Plugins::Recon]
341
+ },
342
+ 'masscan' => {
343
+ apt: %w[masscan], dnf: %w[masscan], pacman: %w[masscan], brew: %w[masscan], port: %w[],
344
+ plugins: %w[PWN::Plugins::Recon]
345
+ },
346
+ 'naabu' => {
347
+ apt: %w[naabu], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
348
+ plugins: %w[PWN::Plugins::Recon]
349
+ },
350
+ 'amass' => {
351
+ apt: %w[amass], dnf: %w[], pacman: %w[], brew: %w[amass], port: %w[],
352
+ plugins: %w[PWN::Plugins::Recon]
353
+ },
354
+ 'john' => {
355
+ apt: %w[john], dnf: %w[john], pacman: %w[john], brew: %w[john], port: %w[john],
356
+ plugins: %w[PWN::Plugins::CredentialAttack]
357
+ },
358
+ 'hashcat' => {
359
+ apt: %w[hashcat], dnf: %w[hashcat], pacman: %w[hashcat], brew: %w[hashcat], port: %w[],
360
+ plugins: %w[PWN::Plugins::CredentialAttack]
361
+ },
362
+ 'medusa' => {
363
+ apt: %w[medusa], dnf: %w[medusa], pacman: %w[medusa], brew: %w[], port: %w[],
364
+ plugins: %w[PWN::Plugins::CredentialAttack]
365
+ },
366
+ 'hashid' => {
367
+ apt: %w[hashid], dnf: %w[], pacman: %w[], brew: %w[], port: %w[],
368
+ pip: 'hashid',
369
+ plugins: %w[PWN::Plugins::CredentialAttack]
300
370
  }
301
- }.freeze
371
+ }.tap do |t|
372
+ %w[burpsuite zaproxy msfconsole nuclei searchsploit httpx subfinder naabu amass apktool jadx rizin pwndbg trivy semgrep vol hashid].each do |bin|
373
+ next unless t[bin]
374
+
375
+ t[bin] = t[bin].merge(ubuntu: [], debian: [])
376
+ end
377
+ {
378
+ 'checksec' => %w[checksec],
379
+ 'ROPgadget' => %w[python3-ropgadget],
380
+ 'ropper' => %w[ropper],
381
+ 'pwndbg' => [],
382
+ 'semgrep' => [],
383
+ 'vol' => []
384
+ }.each do |bin, pkgs|
385
+ next unless t[bin]
386
+
387
+ t[bin] = t[bin].merge(kali: pkgs)
388
+ end
389
+ end.freeze
302
390
 
303
391
  # Capability profiles — how you get the ergonomics of `pwn-full`
304
392
  # without shipping a second gem. `pwn setup --profile <name>`.
@@ -368,6 +456,27 @@ module PWN
368
456
  OK = "\e[32mok\e[0m"
369
457
  MISS = "\e[31mMISSING\e[0m"
370
458
 
459
+ # Supported Method Parameters::
460
+ # PWN::Setup.packages_for(
461
+ # bin: 'required - TOOLCHAIN key (e.g. nmap or burpsuite)',
462
+ # distro: 'optional - DetectOS.distro symbol (defaults to live detect)',
463
+ # version: 'optional - DetectOS.version string (defaults to live detect)',
464
+ # pm_key: 'optional - package-manager family (:apt :dnf :pacman :brew :port :pkg …)'
465
+ # )
466
+
467
+ public_class_method def self.packages_for(opts = {})
468
+ bin = opts[:bin].to_s
469
+ meta = TOOLCHAIN[bin] || {}
470
+ distro = (opts[:distro] || PWN::Plugins::DetectOS.distro).to_s.to_sym
471
+ version = (opts[:version] || PWN::Plugins::DetectOS.version).to_s
472
+ pm_key = opts[:pm_key] || pkg_manager[:key]
473
+ ver_key = :"#{distro}/#{version}"
474
+ return Array(meta[ver_key]) if meta.key?(ver_key)
475
+ return Array(meta[distro]) if meta.key?(distro)
476
+
477
+ Array(meta[pm_key])
478
+ end
479
+
371
480
  # Supported Method Parameters::
372
481
  # PWN::Setup.pkg_manager
373
482
 
@@ -385,13 +494,39 @@ module PWN
385
494
  end
386
495
  sudo = root || !bin?(name: 'sudo') ? '' : 'sudo '
387
496
 
497
+ distro = begin
498
+ PWN::Plugins::DetectOS.distro
499
+ rescue StandardError
500
+ nil
501
+ end
502
+
388
503
  @pkg_manager =
389
- if bin?(name: 'apt-get') then { key: :apt, install: "#{sudo}apt-get install -y", sudo: !sudo.empty? }
390
- elsif bin?(name: 'dnf') then { key: :dnf, install: "#{sudo}dnf install -y", sudo: !sudo.empty? }
391
- elsif bin?(name: 'pacman') then { key: :pacman, install: "#{sudo}pacman -S --noconfirm", sudo: !sudo.empty? }
392
- elsif bin?(name: 'brew') then { key: :brew, install: 'brew install', sudo: false }
393
- elsif bin?(name: 'port') then { key: :port, install: "#{sudo}port -N install", sudo: !sudo.empty? }
394
- else { key: :unknown, install: nil, sudo: false }
504
+ if distro == :freebsd && bin?(name: 'pkg')
505
+ { key: :pkg, install: "#{sudo}pkg install -y", sudo: !sudo.empty? }
506
+ elsif distro == :openbsd && bin?(name: 'pkg_add')
507
+ { key: :pkg_add, install: "#{sudo}pkg_add", sudo: !sudo.empty? }
508
+ elsif distro == :netbsd && bin?(name: 'pkgin')
509
+ { key: :pkgin, install: "#{sudo}pkgin -y install", sudo: !sudo.empty? }
510
+ elsif distro == :alpine && bin?(name: 'apk')
511
+ { key: :apk, install: "#{sudo}apk add", sudo: !sudo.empty? }
512
+ elsif distro == :android && bin?(name: 'pkg')
513
+ { key: :pkg, install: 'pkg install -y', sudo: false }
514
+ elsif distro == :windows && bin?(name: 'winget')
515
+ { key: :winget, install: 'winget install -e --accept-package-agreements --accept-source-agreements', sudo: false }
516
+ elsif distro == :windows && bin?(name: 'choco')
517
+ { key: :choco, install: 'choco install -y', sudo: false }
518
+ elsif bin?(name: 'apt-get')
519
+ { key: :apt, install: "#{sudo}apt-get install -y", sudo: !sudo.empty? }
520
+ elsif bin?(name: 'dnf')
521
+ { key: :dnf, install: "#{sudo}dnf install -y", sudo: !sudo.empty? }
522
+ elsif bin?(name: 'pacman')
523
+ { key: :pacman, install: "#{sudo}pacman -S --noconfirm", sudo: !sudo.empty? }
524
+ elsif bin?(name: 'brew')
525
+ { key: :brew, install: 'brew install', sudo: false }
526
+ elsif bin?(name: 'port')
527
+ { key: :port, install: "#{sudo}port -N install", sudo: !sudo.empty? }
528
+ else
529
+ { key: :unknown, install: nil, sudo: false }
395
530
  end
396
531
  end
397
532
 
@@ -506,12 +641,14 @@ module PWN
506
641
  profile = (opts[:profile] || :full).to_sym
507
642
  yes = opts[:yes] ? true : false
508
643
  dry_run = opts[:dry_run] ? true : false
644
+ distro = opts[:distro] || PWN::Plugins::DetectOS.distro
645
+ version = opts[:version] || PWN::Plugins::DetectOS.version
509
646
  io = opts[:io] || $stdout
510
647
 
511
648
  raise "Unknown profile '#{profile}'. Known: #{PROFILES.keys.join(', ')}" unless PROFILES.key?(profile)
512
649
 
513
650
  pm = pkg_manager
514
- raise 'No supported package manager found (apt / dnf / pacman / brew / port).' if pm[:key] == :unknown
651
+ raise 'No supported package manager found (apt / dnf / pacman / brew / port / pkg / winget / choco).' if pm[:key] == :unknown
515
652
 
516
653
  prof = PROFILES[profile]
517
654
  gems = Array(prof[:gems])
@@ -527,22 +664,25 @@ module PWN
527
664
  bins = Array(prof[:bins])
528
665
  os_pkgs = []
529
666
  gems.each { |g| os_pkgs.concat(Array(NATIVE_GEMS.dig(g, pm[:key]))) }
530
- bins.each { |b| os_pkgs.concat(Array(TOOLCHAIN.dig(b, pm[:key]))) }
667
+ bins.each { |b| os_pkgs.concat(packages_for(bin: b, distro: distro, version: version, pm_key: pm[:key])) }
531
668
  os_pkgs = os_pkgs.reject(&:empty?).uniq
669
+ alts = alt_install_cmds(bins: bins, pm_key: pm[:key], distro: distro, version: version)
670
+ os_pkgs = (['pipx'] + os_pkgs).uniq if pm[:key] == :apt && alts.any? { |c| c.include?('pipx install') }
532
671
 
533
672
  io.puts "Profile : #{profile} — #{prof[:desc]}"
673
+ io.puts "Distro : #{distro} #{version}"
534
674
  io.puts "Pkg mgr : #{pm[:key]}"
535
675
  io.puts "OS pkgs : #{os_pkgs.empty? ? '(none)' : os_pkgs.join(' ')}"
536
676
  io.puts "Ruby exts : #{gems.empty? ? '(none)' : gems.join(' ')}"
537
677
  io.puts
538
678
 
539
- cmds = []
540
- cmds << "#{pm[:install]} #{os_pkgs.map { |p| Shellwords.escape(p) }.join(' ')}" unless os_pkgs.empty?
679
+ cmds = os_pkgs.map { |pkg| "#{pm[:install]} #{Shellwords.escape(pkg)}" }
541
680
  unless gems.empty?
542
681
  broken = gems.reject { |g| gem_loadable?(name: g) }
543
682
  cmds << "gem pristine #{broken.map { |g| Shellwords.escape(g) }.join(' ')}" unless broken.empty?
544
683
  cmds << "gem install #{broken.map { |g| Shellwords.escape(g) }.join(' ')}" unless broken.empty?
545
684
  end
685
+ cmds.concat(alts)
546
686
 
547
687
  if cmds.empty?
548
688
  io.puts "Nothing to do — profile '#{profile}' is already satisfied."
@@ -786,6 +926,35 @@ module PWN
786
926
  false
787
927
  end
788
928
 
929
+ private_class_method def self.alt_install_cmds(opts = {})
930
+ bins = Array(opts[:bins])
931
+ pm_key = opts[:pm_key]
932
+ distro = opts[:distro]
933
+ version = opts[:version]
934
+ bins.filter_map do |b|
935
+ meta = TOOLCHAIN[b] || {}
936
+ next if packages_for(bin: b, pm_key: pm_key, distro: distro, version: version).any?
937
+
938
+ if meta[:pip].to_s != ''
939
+ pip_install_cmd(pkg: meta[:pip], distro: distro)
940
+ elsif meta[:gem].to_s != ''
941
+ "gem install #{Shellwords.escape(meta[:gem])}"
942
+ elsif meta[:script].to_s != ''
943
+ meta[:script].to_s
944
+ end
945
+ end
946
+ end
947
+
948
+ private_class_method def self.pip_install_cmd(opts = {})
949
+ pkg = opts[:pkg].to_s
950
+ distro = opts[:distro].to_s.to_sym
951
+ if %i[kali debian ubuntu mint pop chromeos].include?(distro)
952
+ "pipx install #{Shellwords.escape(pkg)}"
953
+ else
954
+ "python3 -m pip install --user #{Shellwords.escape(pkg)}"
955
+ end
956
+ end
957
+
789
958
  private_class_method def self.bin?(opts = {})
790
959
  !which(name: opts[:name]).empty?
791
960
  end
@@ -935,21 +1104,31 @@ module PWN
935
1104
 
936
1105
  public_class_method def self.help
937
1106
  puts "USAGE:
938
- # Run pkg manager and return its result
1107
+ # Detect this host's package manager (apt, dnf, pacman, brew, pkg, winget, …).
939
1108
  #{self}.pkg_manager
940
1109
 
1110
+ # Resolve OS package names for a TOOLCHAIN binary on this distro/version.
1111
+ #{self}.packages_for(
1112
+ bin: 'required - TOOLCHAIN key (e.g. nmap or burpsuite)',
1113
+ distro: 'optional - DetectOS.distro symbol (defaults to live detect)',
1114
+ version: 'optional - DetectOS.version string (defaults to live detect)',
1115
+ pm_key: 'optional - package-manager family (:apt :dnf :pacman :brew :port :pkg)'
1116
+ )
1117
+
941
1118
  # Run check and return its result
942
1119
  #{self}.check(
943
1120
  io: 'optional - IO to write the report to (default $stdout)',
944
1121
  profile: 'optional - profile value consumed by #check'
945
1122
  )
946
1123
 
947
- # Run deps and return its result
1124
+ # Install OS packages + native gems for a capability profile.
948
1125
  #{self}.deps(
949
1126
  profile: 'optional - one of PROFILES.keys (default :full)',
950
1127
  yes: 'optional - non-interactive; assume yes to prompts (default false)',
951
1128
  dry_run: 'optional - print commands only, do not execute (default false)',
952
- io: 'optional - IO to write to (default $stdout)'
1129
+ io: 'optional - IO to write to (default $stdout)',
1130
+ distro: 'optional - DetectOS.distro override (e.g. :kali :ubuntu :macos)',
1131
+ version: 'optional - DetectOS.version override (e.g. 2026.3 or 24.04)'
953
1132
  )
954
1133
 
955
1134
  # Opt-in installer for SHIFT+ENTER multi-line support in the pwn-ai /
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.710'
4
+ VERSION = '0.5.712'
5
5
  end
@@ -146,7 +146,7 @@ RSpec.describe 'documentation/Installation.md' do
146
146
  pm = PWN::Setup.pkg_manager[:key]
147
147
  # every :net bin's package appears in the plan
148
148
  PWN::Setup::PROFILES[:net][:bins].each do |b|
149
- Array(PWN::Setup::TOOLCHAIN.dig(b, pm)).each do |pkg|
149
+ Array(PWN::Setup.packages_for(bin: b, pm_key: pm)).each do |pkg|
150
150
  expect(plan).to include(pkg), "profile :net missing own package '#{pkg}'"
151
151
  end
152
152
  end
@@ -4,12 +4,62 @@ require 'spec_helper'
4
4
 
5
5
  describe PWN::Plugins::DetectOS do
6
6
  it 'should display information for authors' do
7
- authors_response = PWN::Plugins::DetectOS
8
- expect(authors_response).to respond_to :authors
7
+ expect(described_class).to respond_to :authors
9
8
  end
10
9
 
11
10
  it 'should display information for existing help method' do
12
- help_response = PWN::Plugins::DetectOS
13
- expect(help_response).to respond_to :help
11
+ expect(described_class).to respond_to :help
12
+ end
13
+
14
+ describe '.distro' do
15
+ it 'returns a lowercase symbol on this host' do
16
+ expect(described_class.distro).to be_a(Symbol)
17
+ end
18
+
19
+ it 'reads Kali from os-release including rolling versions like 2026.3' do
20
+ body = <<~OS
21
+ ID=kali
22
+ VERSION_ID="2026.3"
23
+ ID_LIKE=debian
24
+ OS
25
+ expect(described_class.distro(os_release: body, type: :linux)).to eq(:kali)
26
+ expect(described_class.version(os_release: body, type: :linux)).to eq('2026.3')
27
+ end
28
+
29
+ it 'reads Ubuntu and Debian' do
30
+ expect(described_class.distro(os_release: "ID=ubuntu\nVERSION_ID=\"24.04\"\n", type: :linux)).to eq(:ubuntu)
31
+ expect(described_class.version(os_release: "ID=ubuntu\nVERSION_ID=\"24.04\"\n", type: :linux)).to eq('24.04')
32
+ expect(described_class.distro(os_release: "ID=debian\nVERSION_ID=\"12\"\n", type: :linux)).to eq(:debian)
33
+ end
34
+
35
+ it 'reads Fedora, Arch, Alpine' do
36
+ expect(described_class.distro(os_release: "ID=fedora\nVERSION_ID=41\n", type: :linux)).to eq(:fedora)
37
+ expect(described_class.distro(os_release: "ID=arch\n", type: :linux)).to eq(:arch)
38
+ expect(described_class.distro(os_release: "ID=alpine\nVERSION_ID=3.20.0\n", type: :linux)).to eq(:alpine)
39
+ end
40
+
41
+ it 'detects ChromeOS from lsb-release' do
42
+ lsb = "CHROMEOS_RELEASE_NAME=Chrome OS\nCHROMEOS_RELEASE_VERSION=15662.64.0\n"
43
+ expect(described_class.distro(lsb_release: lsb, os_release: "ID=chromeos\n", type: :linux)).to eq(:chromeos)
44
+ expect(described_class.version(lsb_release: lsb, os_release: "ID=chromeos\n", type: :linux)).to eq('15662.64.0')
45
+ end
46
+
47
+ it 'detects Android from build.prop' do
48
+ prop = "ro.build.version.release=14\nro.product.brand=google\n"
49
+ expect(described_class.distro(build_prop: prop, type: :linux)).to eq(:android)
50
+ expect(described_class.version(build_prop: prop, type: :linux)).to eq('14')
51
+ end
52
+
53
+ it 'detects macOS, iOS, Windows, and BSDs' do
54
+ expect(described_class.distro(type: :osx, sw_vers: '15.1')).to eq(:macos)
55
+ expect(described_class.version(type: :osx, sw_vers: '15.1')).to eq('15.1')
56
+ expect(described_class.distro(type: :linux, platform: 'arm64-darwin-ios')).to eq(:ios)
57
+ expect(described_class.distro(type: :windows, win_ver: 'Microsoft Windows [Version 10.0.26100.1742]')).to eq(:windows)
58
+ expect(described_class.version(type: :windows, win_ver: 'Microsoft Windows [Version 10.0.26100.1742]')).to eq('10.0.26100.1742')
59
+ expect(described_class.distro(type: :freebsd, uname: 'FreeBSD')).to eq(:freebsd)
60
+ expect(described_class.version(type: :freebsd, uname_r: '14.1-RELEASE')).to eq('14.1-RELEASE')
61
+ expect(described_class.distro(type: :openbsd, uname: 'OpenBSD')).to eq(:openbsd)
62
+ expect(described_class.distro(type: :netbsd, uname: 'NetBSD')).to eq(:netbsd)
63
+ end
14
64
  end
15
65
  end
@@ -101,4 +101,94 @@ describe PWN::Setup do
101
101
  expect(body.scan('PWN::Setup.ensure_cron').length).to eq(1)
102
102
  expect(body).to include('opts[:migrate] && running')
103
103
  end
104
+
105
+ it 'TOOLCHAIN covers every plugin required_bins name' do
106
+ plugin_bins = Dir[File.expand_path('../../../lib/pwn/plugins/*.rb', __dir__)].flat_map do |path|
107
+ src = File.read(path)
108
+ m = src.match(/public_class_method def self\.required_bins\n\s+%w\[([^\]]*)\]/)
109
+ next [] unless m
110
+
111
+ m[1].split
112
+ end.uniq
113
+ missing = plugin_bins - PWN::Setup::TOOLCHAIN.keys
114
+ expect(missing).to eq([]), "pwn setup TOOLCHAIN missing plugin bins: #{missing.join(', ')}"
115
+ end
116
+
117
+ it 'every TOOLCHAIN row has an OS package or pip/gem installer' do
118
+ PWN::Setup::TOOLCHAIN.each do |bin, meta|
119
+ has_pkg = %i[apt dnf pacman brew port].any? { |k| Array(meta[k]).any? }
120
+ has_alt = meta[:pip].to_s != '' || meta[:gem].to_s != '' || meta[:script].to_s != ''
121
+ expect(has_pkg || has_alt).to be(true), "#{bin} has no apt/dnf/pacman/brew/port/pip/gem installer"
122
+ end
123
+ end
124
+
125
+ it 'deps --profile full dry-run emits pipx/gem for bins with no distro package' do
126
+ io = StringIO.new
127
+ r = PWN::Setup.deps(profile: :full, dry_run: true, io: io)
128
+ cmds = Array(r[:ran]).map { |h| h[:cmd] }.join("\n")
129
+ expect(r[:skipped]).not_to be true
130
+ distro = PWN::Plugins::DetectOS.distro
131
+ version = PWN::Plugins::DetectOS.version
132
+ PWN::Setup::TOOLCHAIN.each do |bin, meta|
133
+ next if PWN::Setup.packages_for(bin: bin, distro: distro, version: version).any?
134
+
135
+ token = meta[:pip] || meta[:gem]
136
+ next unless token
137
+
138
+ expect(cmds).to include(token.to_s), "full dry-run missing installer for #{bin} (#{token})"
139
+ end
140
+ end
141
+
142
+ it 'packages_for prefers distro overrides then package-manager family' do
143
+ expect(
144
+ PWN::Setup.packages_for(bin: 'nmap', distro: :ubuntu, version: '24.04', pm_key: :apt)
145
+ ).to eq(%w[nmap])
146
+ expect(
147
+ PWN::Setup.packages_for(bin: 'burpsuite', distro: :kali, version: '2026.3', pm_key: :apt)
148
+ ).to eq(%w[burpsuite])
149
+ expect(
150
+ PWN::Setup.packages_for(bin: 'burpsuite', distro: :ubuntu, version: '24.04', pm_key: :apt)
151
+ ).to eq([])
152
+ end
153
+
154
+ it 'deps skips kali-only apt packages on ubuntu' do
155
+ io = StringIO.new
156
+ r = PWN::Setup.deps(profile: :web, dry_run: true, io: io, distro: :ubuntu, version: '24.04')
157
+ cmds = Array(r[:ran]).map { |h| h[:cmd] }.join(' ')
158
+ expect(cmds).not_to include('burpsuite')
159
+ expect(cmds).not_to include('zaproxy')
160
+ end
161
+
162
+ it 'maps Kali 2026.3 apt names for checksec ROPgadget ropper' do
163
+ k = { distro: :kali, version: '2026.3', pm_key: :apt }
164
+ expect(PWN::Setup.packages_for(k.merge(bin: 'checksec'))).to eq(%w[checksec])
165
+ expect(PWN::Setup.packages_for(k.merge(bin: 'ROPgadget'))).to eq(%w[python3-ropgadget])
166
+ expect(PWN::Setup.packages_for(k.merge(bin: 'ropper'))).to eq(%w[ropper])
167
+ end
168
+
169
+ it 'does not apt-get Kali-missing names and does not pip --user on Kali' do
170
+ k = { distro: :kali, version: '2026.3', pm_key: :apt }
171
+ %w[pwndbg semgrep vol].each do |b|
172
+ expect(PWN::Setup.packages_for(k.merge(bin: b))).to eq([])
173
+ end
174
+ r = PWN::Setup.deps(profile: :full, dry_run: true, io: StringIO.new, distro: :kali, version: '2026.3')
175
+ cmds = Array(r[:ran]).map { |h| h[:cmd] }
176
+ apt = cmds.select { |c| c.include?('apt-get') }.join("\n")
177
+ expect(apt).to include('checksec')
178
+ expect(apt).to include('python3-ropgadget')
179
+ expect(apt).to include('ropper')
180
+ expect(apt).not_to match(/\bpwndbg\b/)
181
+ expect(apt).not_to match(/\bsemgrep\b/)
182
+ expect(apt).not_to include('volatility3')
183
+ expect(cmds.join("\n")).not_to include('pip install --user')
184
+ expect(cmds.join("\n")).to include('install.pwndbg.re')
185
+ expect(cmds.join("\n")).to include('pwndbg-gdb')
186
+ end
187
+
188
+ it 'issues one apt-get per package so a missing name cannot abort the rest' do
189
+ r = PWN::Setup.deps(profile: :net, dry_run: true, io: StringIO.new, distro: :kali, version: '2026.3')
190
+ apt = Array(r[:ran]).map { |h| h[:cmd] }.select { |c| c.include?('apt-get install') }
191
+ expect(apt.length).to be > 1
192
+ apt.each { |c| expect(c).to match(/apt-get install -y \S+\z/) }
193
+ end
104
194
  end
@@ -1933,11 +1933,23 @@
1933
1933
  {"messages":[{"role":"user","content":"PWN::Plugins::DefectDojo.tool_configuration_list Usage"},{"role":"assistant","content":"`PWN::Plugins::DefectDojo.tool_configuration_list`: Supported Method Parameters\n\ntool_configuration_list = PWN::Plugins::DefectDojo.tool_configuration_list(\n\ndd_obj: 'required dd_obj returned from #login method',\nid: 'optional - retrieve single test by id, otherwise return all'\n\n)\n"}]}
1934
1934
  {"messages":[{"role":"user","content":"PWN::Plugins::DefectDojo.tool_configuration_resource_uri_by_name Usage"},{"role":"assistant","content":"`PWN::Plugins::DefectDojo.tool_configuration_resource_uri_by_name`: Supported Method Parameters\n\ntool_configuration_resource_uri_by_name(\n\ndd_obj: 'required dd_obj returned from #login method',\ntool_config_name: 'required tool configuration name'\n\n)\n"}]}
1935
1935
  {"messages":[{"role":"user","content":"PWN::Plugins::DefectDojo.user_list Usage"},{"role":"assistant","content":"`PWN::Plugins::DefectDojo.user_list`: Supported Method Parameters\n\nuser_list = PWN::Plugins::DefectDojo.user_list(\n\ndd_obj: 'required dd_obj returned from #login method',\nid: 'optional - retrieve single user by id, otherwise return all'\n\n)\n"}]}
1936
- {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.arch Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.arch`: Supported Method Parameters\n\nPWN::Plugins::DetectOS.arch\n"}]}
1937
- {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.authors Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
1938
- {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.endian Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.endian`: Supported Method Parameters\n\nPWN::Plugins::DetectOS.endian\n"}]}
1936
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.android_host? Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.android_host?`: "}]}
1937
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.arch Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.arch`: "}]}
1938
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.authors Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.authors`: "}]}
1939
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.chromeos_host? Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.chromeos_host?`: "}]}
1940
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.distro Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.distro`: Supported Method Parameters\n\nPWN::Plugins::DetectOS.distro(\n\nos_release: 'optional - /etc/os-release body (defaults to reading the file)',\nlsb_release: 'optional - /etc/lsb-release body',\nbuild_prop: 'optional - Android /system/build.prop body',\ntype: 'optional - OS family from #type (e.g. :linux :osx :windows :freebsd)',\nplatform: 'optional - RUBY_PLATFORM override',\nuname: 'optional - uname -s string',\nsw_vers: 'optional - macOS/iOS product version string',\nwin_ver: 'optional - Windows ver command output'\n\n)\n"}]}
1941
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.endian Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.endian`: "}]}
1939
1942
  {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.help Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.help`: "}]}
1940
- {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.type Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.type`: Supported Method Parameters\n\nPWN::Plugins::DetectOS.type\n"}]}
1943
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.ios_host? Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.ios_host?`: "}]}
1944
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.live_sw_vers Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.live_sw_vers`: "}]}
1945
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.live_uname_r Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.live_uname_r`: "}]}
1946
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.live_uname_s Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.live_uname_s`: "}]}
1947
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.live_win_ver Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.live_win_ver`: "}]}
1948
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.normalize_id Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.normalize_id`: "}]}
1949
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.parse_kv Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.parse_kv`: "}]}
1950
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.read_if_present Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.read_if_present`: "}]}
1951
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.type Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.type`: "}]}
1952
+ {"messages":[{"role":"user","content":"PWN::Plugins::DetectOS.version Usage"},{"role":"assistant","content":"`PWN::Plugins::DetectOS.version`: Supported Method Parameters\n\nPWN::Plugins::DetectOS.version(\n\nos_release: 'optional - /etc/os-release body',\nlsb_release: 'optional - /etc/lsb-release body',\nbuild_prop: 'optional - Android build.prop body',\nsw_vers: 'optional - macOS/iOS product version',\nwin_ver: 'optional - Windows ver output',\nuname_r: 'optional - uname -r string',\ntype: 'optional - OS family from #type'\n\n)\n"}]}
1941
1953
  {"messages":[{"role":"user","content":"PWN::Plugins::EIN.authors Usage"},{"role":"assistant","content":"`PWN::Plugins::EIN.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
1942
1954
  {"messages":[{"role":"user","content":"PWN::Plugins::EIN.generate Usage"},{"role":"assistant","content":"`PWN::Plugins::EIN.generate`: Supported Method Parameters\n\nPWN::Plugins::EIN.generate(\n\ncount: 'required - number of EIN numbers to generate'\n\n)\n"}]}
1943
1955
  {"messages":[{"role":"user","content":"PWN::Plugins::EIN.help Usage"},{"role":"assistant","content":"`PWN::Plugins::EIN.help`: "}]}
@@ -3171,6 +3183,7 @@
3171
3183
  {"messages":[{"role":"user","content":"PWN::Sessions.to_response_history Usage"},{"role":"assistant","content":"`PWN::Sessions.to_response_history`: Supported Method Parameters\n\nhistory_for_ai = PWN::Sessions.to_response_history(session_id:) (converts transcript to the response_history format used by PWN::AI::* .chat)\n"}]}
3172
3184
  {"messages":[{"role":"user","content":"PWN::Setup.ai_active_engine Usage"},{"role":"assistant","content":"`PWN::Setup.ai_active_engine`: "}]}
3173
3185
  {"messages":[{"role":"user","content":"PWN::Setup.ai_key_configured? Usage"},{"role":"assistant","content":"`PWN::Setup.ai_key_configured?`: "}]}
3186
+ {"messages":[{"role":"user","content":"PWN::Setup.alt_install_cmds Usage"},{"role":"assistant","content":"`PWN::Setup.alt_install_cmds`: "}]}
3174
3187
  {"messages":[{"role":"user","content":"PWN::Setup.authors Usage"},{"role":"assistant","content":"`PWN::Setup.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
3175
3188
  {"messages":[{"role":"user","content":"PWN::Setup.bin? Usage"},{"role":"assistant","content":"`PWN::Setup.bin?`: "}]}
3176
3189
  {"messages":[{"role":"user","content":"PWN::Setup.check Usage"},{"role":"assistant","content":"`PWN::Setup.check`: Supported Method Parameters\n\nPWN::Setup.check(\n\nio: 'optional - IO to write the report to (default $stdout)'\n\n)\n"}]}
@@ -3181,6 +3194,8 @@
3181
3194
  {"messages":[{"role":"user","content":"PWN::Setup.help Usage"},{"role":"assistant","content":"`PWN::Setup.help`: "}]}
3182
3195
  {"messages":[{"role":"user","content":"PWN::Setup.list_profiles Usage"},{"role":"assistant","content":"`PWN::Setup.list_profiles`: Supported Method Parameters\n\nPWN::Setup.list_profiles(\n\nio: 'optional - IO to write to (default $stdout)'\n\n)\n"}]}
3183
3196
  {"messages":[{"role":"user","content":"PWN::Setup.migrate Usage"},{"role":"assistant","content":"`PWN::Setup.migrate`: Supported Method Parameters\n\nPWN::Setup.migrate(\n\nfix: 'optional - also autofix incompatible ~/.pwn files (default false)',\ndry_run: 'optional - print what WOULD happen (default false)',\nyes: 'optional - alias for fix:true (CI-friendly)',\nio: 'optional - IO to write to (default $stdout)'\n\n)\n\nDelegate to PWN::Migrate.run — verify every ~/.pwn state file is compatible with THIS pwn release and (optionally) autofix it. A timestamped backup of ~/.pwn is taken first. See ‘PWN::Migrate.help`.\n"}]}
3197
+ {"messages":[{"role":"user","content":"PWN::Setup.packages_for Usage"},{"role":"assistant","content":"`PWN::Setup.packages_for`: Supported Method Parameters\n\nPWN::Setup.packages_for(\n\nbin: 'required - TOOLCHAIN key (e.g. nmap or burpsuite)',\ndistro: 'optional - DetectOS.distro symbol (defaults to live detect)',\nversion: 'optional - DetectOS.version string (defaults to live detect)',\npm_key: 'optional - package-manager family (:apt :dnf :pacman :brew :port :pkg …)'\n\n)\n"}]}
3198
+ {"messages":[{"role":"user","content":"PWN::Setup.pip_install_cmd Usage"},{"role":"assistant","content":"`PWN::Setup.pip_install_cmd`: "}]}
3184
3199
  {"messages":[{"role":"user","content":"PWN::Setup.pkg_manager Usage"},{"role":"assistant","content":"`PWN::Setup.pkg_manager`: Supported Method Parameters\n\nPWN::Setup.pkg_manager\n"}]}
3185
3200
  {"messages":[{"role":"user","content":"PWN::Setup.terminal Usage"},{"role":"assistant","content":"`PWN::Setup.terminal`: Supported Method Parameters\n\nPWN::Setup.terminal(\n\nyes: 'optional - assume yes; non-interactive (default false)',\ndry_run: 'optional - print what WOULD happen (default false)',\nio: 'optional - IO to write to (default $stdout)'\n\n)\n\nOpt-in installer for SHIFT+ENTER multi-line support in the pwn-ai / pwn-asm REPL. Never runs implicitly — the user invokes it with ‘pwn setup –terminal` after PWNMultiLineInput#ensure_vte_shift_enter tells them their emulator can’t distinguish Shift+Enter from Enter.\n\nWhat it does:\n\n1. Prints the two `~/.tmux.conf` lines that persist the runtime\n `tmux set -s` calls PWNMultiLineInput already makes.\n2. If running under Terminator (a VTE host), copies\n third_party/terminator/pwn_shift_enter.py to\n ~/.config/terminator/plugins/ and enables the PWNShiftEnter\n plugin in ~/.config/terminator/config — WITH confirmation and\n a .pwnbak backup. This is the only VTE emulator we can fix at\n the GTK layer without patching libvte itself.\n\nEverything here is host-config mutation, which is why it lives in ‘pwn setup` and NOT in the REPL’s runtime path. See GNOME/vte issues #2601 / #2607 for why VTE can’t be fixed with escape sequences alone.\n"}]}
3186
3201
  {"messages":[{"role":"user","content":"PWN::Setup.which Usage"},{"role":"assistant","content":"`PWN::Setup.which`: "}]}
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.710
4
+ version: 0.5.712
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
@@ -5478,6 +5478,7 @@ files:
5478
5478
  - etc/default_skills/pwn/sdr/son_micro_rfid/SKILL.md
5479
5479
  - etc/default_skills/pwn/sessions/SKILL.md
5480
5480
  - etc/default_skills/pwn/setup/SKILL.md
5481
+ - etc/default_skills/pwn/setup/references/urls.md
5481
5482
  - etc/default_skills/pwn/version/SKILL.md
5482
5483
  - etc/default_skills/pwn/www/SKILL.md
5483
5484
  - etc/default_skills/pwn/www/app_cobalt_io/SKILL.md