pwn 0.5.709 → 0.5.710

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/documentation/Installation.md +1 -1
  4. data/etc/default_skills/exploitdev/SKILL.md +38 -0
  5. data/etc/default_skills/pwn/plugins/aflplusplus/SKILL.md +1 -0
  6. data/etc/default_skills/pwn/plugins/credential_attack/SKILL.md +7 -0
  7. data/etc/default_skills/pwn/plugins/credential_attack/references/urls.md +3 -0
  8. data/etc/default_skills/pwn/plugins/exploit_db/SKILL.md +49 -0
  9. data/etc/default_skills/pwn/plugins/exploit_dev/SKILL.md +2 -0
  10. data/etc/default_skills/pwn/plugins/frida/SKILL.md +2 -0
  11. data/etc/default_skills/pwn/plugins/fuzz/SKILL.md +2 -0
  12. data/etc/default_skills/pwn/plugins/gdb/SKILL.md +1 -0
  13. data/etc/default_skills/pwn/plugins/k8s/SKILL.md +51 -0
  14. data/etc/default_skills/pwn/plugins/nuclei/SKILL.md +2 -0
  15. data/etc/default_skills/pwn/plugins/{doctor → preflight_checker}/SKILL.md +13 -11
  16. data/etc/default_skills/pwn/plugins/process_tube/SKILL.md +1 -0
  17. data/etc/default_skills/pwn/plugins/recon/SKILL.md +2 -0
  18. data/etc/default_skills/pwn/plugins/recon/references/urls.md +1 -0
  19. data/etc/default_skills/pwn/plugins/semgrep/SKILL.md +48 -0
  20. data/etc/default_skills/pwn/plugins/volatility/SKILL.md +1 -0
  21. data/lib/pwn/ai/agent/prompt_builder.rb +1 -1
  22. data/lib/pwn/ai/agent/tools/sessions.rb +8 -1
  23. data/lib/pwn/ffi/stdio.rb +3 -1
  24. data/lib/pwn/plugins/aflplusplus.rb +21 -1
  25. data/lib/pwn/plugins/android.rb +9 -3
  26. data/lib/pwn/plugins/credential_attack.rb +62 -3
  27. data/lib/pwn/plugins/exploit_db.rb +69 -0
  28. data/lib/pwn/plugins/exploit_dev.rb +69 -3
  29. data/lib/pwn/plugins/frida.rb +60 -9
  30. data/lib/pwn/plugins/fuzz.rb +33 -0
  31. data/lib/pwn/plugins/gdb.rb +25 -5
  32. data/lib/pwn/plugins/jobs.rb +1 -0
  33. data/lib/pwn/plugins/k8s.rb +73 -0
  34. data/lib/pwn/plugins/nuclei.rb +36 -3
  35. data/lib/pwn/plugins/packet.rb +1 -1
  36. data/lib/pwn/plugins/{doctor.rb → preflight_checker.rb} +22 -5
  37. data/lib/pwn/plugins/process_tube.rb +20 -1
  38. data/lib/pwn/plugins/radare2.rb +1 -1
  39. data/lib/pwn/plugins/recon.rb +39 -4
  40. data/lib/pwn/plugins/semgrep.rb +61 -0
  41. data/lib/pwn/plugins/sock.rb +1 -0
  42. data/lib/pwn/plugins/sqlmap.rb +1 -1
  43. data/lib/pwn/plugins/volatility.rb +21 -2
  44. data/lib/pwn/plugins.rb +4 -1
  45. data/lib/pwn/setup.rb +13 -1
  46. data/lib/pwn/version.rb +1 -1
  47. data/spec/integration/help_contract_spec.rb +2 -0
  48. data/spec/lib/pwn/plugins/exploit_db_spec.rb +13 -0
  49. data/spec/lib/pwn/plugins/k8s_spec.rb +13 -0
  50. data/spec/lib/pwn/plugins/{doctor_spec.rb → preflight_checker_spec.rb} +1 -1
  51. data/spec/lib/pwn/plugins/semgrep_spec.rb +13 -0
  52. data/spec/lib/pwn/req_queue_spec.rb +168 -0
  53. data/third_party/pwn_rdoc.jsonl +43 -9
  54. metadata +20 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a21d92ef6104c4aec2f54470689f0398fda97a2894bb9a61b1034a72b5291e1f
4
- data.tar.gz: 19a47d2db6aae502ab6a2380853569f172ff393839187818b891f01272029f5f
3
+ metadata.gz: bb2089e549bccd1c21a643fd22719f13cb3a7519c1580f9cbd3e425c66f2be91
4
+ data.tar.gz: d27e48a928750b279f8315e8a578071bed21403728ae7f8c5474015f75ff557e
5
5
  SHA512:
6
- metadata.gz: 79f9a1ac713919b1e4cd239f5475b9d14f2b73dcc19152fc0b1e82312d6f1c25062bb90f45ffe5533bd3fda09769faf3207d946110a196d3d050847344ac3549
7
- data.tar.gz: 8718455cc9a5db44fa41ce916b26292a92889c4c7208ecaa74df310dddafeddfd4d8ba1983ea8c437b83c67a36bc589fb06d5c0d2729e6b104a3bff598c2a7c3
6
+ metadata.gz: 37c74e1e2ab80b6a872f0d533ec402b520bffd70dc1198114574b3bbe90383c9dbebe6ac9b844e79023eed1cdeefc6cb8df4cca964b186cff1e25bc718384b12
7
+ data.tar.gz: 703c871173f4a754b9a515b45c4fd6aa4d3e2b1590f397168a53869d7eed5a77243a69e635f3894ce61be401b4c260395b0be7b435d6dc0613067b7b9047345c
data/Gemfile CHANGED
@@ -22,7 +22,7 @@ gem 'brakeman', '8.0.6'
22
22
  gem 'bson', '5.2.0'
23
23
  gem 'bundler', '>=4.0.19'
24
24
  gem 'bundler-audit', '>=0.9.3'
25
- gem 'bunny', '3.2.0'
25
+ gem 'bunny', '3.3.0'
26
26
  gem 'colorize', '1.1.0'
27
27
  gem 'credit_card_validations', '9.0.0'
28
28
  gem 'curses', '1.7.0'
@@ -77,7 +77,7 @@ gem 'rbvmomi2', '3.10.0'
77
77
  gem 'rdoc', '7.0.4'
78
78
  gem 'rest-client', '2.1.0'
79
79
  gem 'rex', '2.0.13'
80
- gem 'rmagick', '7.1.1'
80
+ gem 'rmagick', '7.1.3'
81
81
  gem 'rqrcode', '3.2.0'
82
82
  gem 'rspec', '3.13.2'
83
83
  gem 'rtesseract', '3.1.4'
@@ -127,7 +127,7 @@ pwn setup --list-profiles
127
127
  | `voice` | `PWN::Plugins::Voice` · `extro_voice` · espeak-ng / sox |
128
128
  | `exploit` | `Metasploit` · `sqlmap` |
129
129
  | `hardware` | `Serial` · `BusPirate` · `Android` · `BareSIP` · `extro_serial` · `extro_telecomm` |
130
- | `re` | `Radare2` · `GDB` · `ExploitDev` · `Frida` · Android RE (`apktool`/`jadx`) |
130
+ | `re` | `Radare2` · `GDB` · `ExploitDev` · `Frida` · Android RE (`apktool`/`jadx`) · `pwndbg` · `ropper` · `rizin` |
131
131
  | `full` | everything above |
132
132
 
133
133
  ### All flags
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: exploitdev
3
+ description: "Exploit-dev SOP: packing, cyclic, ROP, one_gadget, libc offsets."
4
+ ---
5
+
6
+ # Exploit development
7
+
8
+ Use `PWN::Plugins::ExploitDev` from `pwn_eval` — do not shell out to pwntools unless a plugin method is missing.
9
+
10
+ ## Packing
11
+
12
+ ```ruby
13
+ PWN::Plugins::ExploitDev.p32(value: 0x41414141)
14
+ PWN::Plugins::ExploitDev.p64(value: addr, endian: :little)
15
+ PWN::Plugins::ExploitDev.flat(parts: [0xdeadbeef, "A" * 32, 0x401000])
16
+ ```
17
+
18
+ ## Cyclic
19
+
20
+ ```ruby
21
+ pattern = PWN::Plugins::ExploitDev.cyclic(length: 200)
22
+ offset = PWN::Plugins::ExploitDev.cyclic_find(value: "Aa0A", length: 200)
23
+ ```
24
+
25
+ ## Shellcode / ROP
26
+
27
+ ```ruby
28
+ PWN::Plugins::ExploitDev.shellcode(arch: 'x86_64', kind: 'execve_bin_sh')
29
+ PWN::Plugins::ExploitDev.gadgets(path: '/path/to/binary')
30
+ PWN::Plugins::ExploitDev.one_gadget(path: '/lib/x86_64-linux-gnu/libc.so.6')
31
+ PWN::Plugins::ExploitDev.libc_offsets(path: '/lib/x86_64-linux-gnu/libc.so.6')
32
+ ```
33
+
34
+ ## Interactive
35
+
36
+ `PWN::Plugins::ProcessTube.spawn` or `.connect` then `write_line` / `recvuntil`.
37
+ `PWN::Plugins::GDB.run_to_crash` / `.breakpoints` / `.core`.
38
+ `PWN::Plugins::Radare2.open` then `cmd` (text) or `cmdj` (JSON).
@@ -35,6 +35,7 @@ PWN::Plugins::AFLplusplus.required_bins(opts)
35
35
 
36
36
  - `required_bins`
37
37
  - `fuzz`
38
+ - `crash_triage`
38
39
  - `authors`
39
40
  - `help`
40
41
 
@@ -38,9 +38,16 @@ PWN::Plugins::CredentialAttack.required_bins(opts)
38
38
  - `hydra`
39
39
  - `john`
40
40
  - `hashcat`
41
+ - `medusa`
42
+ - `identify_hash`
43
+ - `fetch_seclists`
41
44
  - `authors`
42
45
  - `help`
43
46
 
47
+ ## References
48
+
49
+ - `references/urls.md` — URLs from source
50
+
44
51
  ## Source
45
52
 
46
53
  `pwn/plugins/credential_attack.rb`
@@ -0,0 +1,3 @@
1
+ # PWN::Plugins::CredentialAttack source links
2
+
3
+ - https://github.com/danielmiessler/SecLists.git
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: pwn-plugins-exploitdb
3
+ description: Drive PWN::Plugins::ExploitDB from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Plugins::ExploitDB
10
+ source: pwn/plugins/exploit_db.rb
11
+ ---
12
+
13
+ # PWN::Plugins::ExploitDB
14
+
15
+ searchsploit / ExploitDB plus a CPE string builder for nmap versions.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Plugins::ExploitDB` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/plugins/exploit_db.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Plugins::ExploitDB.help
31
+ PWN::Plugins::ExploitDB.required_bins(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `required_bins`
37
+ - `search`
38
+ - `cve_for_cpe`
39
+ - `authors`
40
+ - `help`
41
+
42
+ ## Source
43
+
44
+ `pwn/plugins/exploit_db.rb`
45
+
46
+ ## Verification
47
+
48
+ `PWN::Plugins::ExploitDB.respond_to?(:required_bins)` after the
49
+ module is loaded. Read the source for parameter names.
@@ -46,6 +46,8 @@ PWN::Plugins::ExploitDev.required_bins(opts)
46
46
  - `cyclic_find`
47
47
  - `flat`
48
48
  - `shellcode`
49
+ - `one_gadget`
50
+ - `libc_offsets`
49
51
  - `fmt_writes`
50
52
  - `gadgets`
51
53
  - `authors`
@@ -36,6 +36,8 @@ PWN::Plugins::Frida.required_bins(opts)
36
36
  - `required_bins`
37
37
  - `ps`
38
38
  - `attach`
39
+ - `spawn`
40
+ - `ssl_pinning_script`
39
41
  - `authors`
40
42
  - `help`
41
43
 
@@ -34,6 +34,8 @@ PWN::Plugins::Fuzz.socket(opts)
34
34
  ## Public methods
35
35
 
36
36
  - `socket`
37
+ - `http`
38
+ - `file_format`
37
39
  - `authors`
38
40
  - `help`
39
41
 
@@ -39,6 +39,7 @@ PWN::Plugins::GDB.required_bins(opts)
39
39
  - `registers`
40
40
  - `mitigations`
41
41
  - `core`
42
+ - `breakpoints`
42
43
  - `authors`
43
44
  - `help`
44
45
 
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: pwn-plugins-k8s
3
+ description: Drive PWN::Plugins::K8s from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Plugins::K8s
10
+ source: pwn/plugins/k8s.rb
11
+ ---
12
+
13
+ # PWN::Plugins::K8s
14
+
15
+ trivy / kube-hunter wrappers plus docker-socket preflight.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Plugins::K8s` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/plugins/k8s.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Plugins::K8s.help
31
+ PWN::Plugins::K8s.required_bins(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `required_bins`
37
+ - `trivy`
38
+ - `kube_hunter`
39
+ - `docker_socket`
40
+ - `authors`
41
+ - `help`
42
+ - `docker_socket?`
43
+
44
+ ## Source
45
+
46
+ `pwn/plugins/k8s.rb`
47
+
48
+ ## Verification
49
+
50
+ `PWN::Plugins::K8s.respond_to?(:required_bins)` after the
51
+ module is loaded. Read the source for parameter names.
@@ -35,6 +35,8 @@ PWN::Plugins::Nuclei.required_bins(opts)
35
35
 
36
36
  - `required_bins`
37
37
  - `scan`
38
+ - `to_findings`
39
+ - `to_defectdojo`
38
40
  - `authors`
39
41
  - `help`
40
42
 
@@ -1,34 +1,34 @@
1
1
  ---
2
- name: pwn-plugins-doctor
3
- description: Drive PWN::Plugins::Doctor from pwn_eval.
2
+ name: pwn-plugins-preflightchecker
3
+ description: Drive PWN::Plugins::PreflightChecker from pwn_eval.
4
4
  license: MIT
5
5
  allowed-tools: [pwn, pwn_eval]
6
6
  metadata:
7
7
  bundled: true
8
8
  generated: true
9
- module: PWN::Plugins::Doctor
10
- source: pwn/plugins/doctor.rb
9
+ module: PWN::Plugins::PreflightChecker
10
+ source: pwn/plugins/preflight_checker.rb
11
11
  ---
12
12
 
13
- # PWN::Plugins::Doctor
13
+ # PWN::Plugins::PreflightChecker
14
14
 
15
15
  Plugin/binary/capability preflight. Plugins declare required_bins / required_caps; HOST summaries list degraded modules without autoloading the whole plugin tree.
16
16
 
17
17
  ## When to use
18
18
 
19
- Call `PWN::Plugins::Doctor` from `pwn_eval` when the task needs this module.
19
+ Call `PWN::Plugins::PreflightChecker` from `pwn_eval` when the task needs this module.
20
20
  Do not reimplement it in shell.
21
21
 
22
22
  ## Methodologies
23
23
 
24
- Generated from `pwn/plugins/doctor.rb`. Prefer the public class methods below.
24
+ Generated from `pwn/plugins/preflight_checker.rb`. Prefer the public class methods below.
25
25
  Class methods take `(opts = {})` and read `opts`.
26
26
 
27
27
  ## How to call
28
28
 
29
29
  ```ruby
30
- PWN::Plugins::Doctor.help
31
- PWN::Plugins::Doctor.required_bins(opts)
30
+ PWN::Plugins::PreflightChecker.help
31
+ PWN::Plugins::PreflightChecker.required_bins(opts)
32
32
  ```
33
33
 
34
34
  ## Public methods
@@ -38,6 +38,7 @@ PWN::Plugins::Doctor.required_bins(opts)
38
38
  - `require_bin`
39
39
  - `cap_net_raw`
40
40
  - `require_cap_net_raw`
41
+ - `service`
41
42
  - `check`
42
43
  - `host_summary`
43
44
  - `authors`
@@ -46,12 +47,13 @@ PWN::Plugins::Doctor.required_bins(opts)
46
47
  - `cap_net_raw?`
47
48
  - `require_bin!`
48
49
  - `require_cap_net_raw!`
50
+ - `service?`
49
51
 
50
52
  ## Source
51
53
 
52
- `pwn/plugins/doctor.rb`
54
+ `pwn/plugins/preflight_checker.rb`
53
55
 
54
56
  ## Verification
55
57
 
56
- `PWN::Plugins::Doctor.respond_to?(:required_bins)` after the
58
+ `PWN::Plugins::PreflightChecker.respond_to?(:required_bins)` after the
57
59
  module is loaded. Read the source for parameter names.
@@ -35,6 +35,7 @@ PWN::Plugins::ProcessTube.required_bins(opts)
35
35
 
36
36
  - `required_bins`
37
37
  - `spawn`
38
+ - `connect`
38
39
  - `write_line`
39
40
  - `recvuntil`
40
41
  - `recvline`
@@ -38,6 +38,8 @@ PWN::Plugins::Recon.required_bins(opts)
38
38
  - `httpx`
39
39
  - `masscan`
40
40
  - `crt_sh`
41
+ - `amass`
42
+ - `passive_dns`
41
43
  - `authors`
42
44
  - `help`
43
45
 
@@ -3,3 +3,4 @@
3
3
  - https://api.certspotter.com/v1/issuances?domain=#{URI.encode_www_form_component(domain
4
4
  - https://crt.sh/?q=#{URI.encode_www_form_component(domain
5
5
  - https://crt.sh/?q=#{URI.encode_www_form_component(
6
+ - https://api.hackertarget.com/hostsearch/?q=#{URI.encode_www_form_component(domain
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: pwn-plugins-semgrep
3
+ description: Drive PWN::Plugins::Semgrep from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Plugins::Semgrep
10
+ source: pwn/plugins/semgrep.rb
11
+ ---
12
+
13
+ # PWN::Plugins::Semgrep
14
+
15
+ semgrep wrapper feeding SAST-shaped findings.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Plugins::Semgrep` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/plugins/semgrep.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Plugins::Semgrep.help
31
+ PWN::Plugins::Semgrep.required_bins(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `required_bins`
37
+ - `scan`
38
+ - `authors`
39
+ - `help`
40
+
41
+ ## Source
42
+
43
+ `pwn/plugins/semgrep.rb`
44
+
45
+ ## Verification
46
+
47
+ `PWN::Plugins::Semgrep.respond_to?(:required_bins)` after the
48
+ module is loaded. Read the source for parameter names.
@@ -35,6 +35,7 @@ PWN::Plugins::Volatility.required_bins(opts)
35
35
 
36
36
  - `required_bins`
37
37
  - `run`
38
+ - `yara`
38
39
  - `authors`
39
40
  - `help`
40
41
 
@@ -199,7 +199,7 @@ module PWN
199
199
  eval_s = ToolGuard.deadline_s(kind: :eval) if defined?(ToolGuard)
200
200
  shell_s = ToolGuard.deadline_s(kind: :shell) if defined?(ToolGuard)
201
201
  load_line = "load1=#{snap[:load1]} ncpu=#{snap[:ncpu]} mem_avail_mb=#{snap[:mem_avail_mb]}"
202
- doc = (PWN::Plugins::Doctor.host_summary if defined?(PWN::Plugins::Doctor))
202
+ doc = (PWN::Plugins::PreflightChecker.host_summary if defined?(PWN::Plugins::PreflightChecker))
203
203
  "#{load_line} pwn_eval/shell timeout = conservative seconds for this host " \
204
204
  "(defaults eval=#{eval_s || 20}s shell=#{shell_s || 30}s, clamped). " \
205
205
  "#{doc}"
@@ -31,7 +31,14 @@ PWN::AI::Agent::Registry.register(
31
31
  limit: args[:limit] || 12,
32
32
  exclude_session_id: exclude,
33
33
  include_current: args[:include_current] == true
34
- )
34
+ ).tap do |hits|
35
+ sid = exclude.to_s
36
+ next if sid.empty? || !defined?(PWN::Plugins::ArtifactRegistry)
37
+
38
+ artifacts = PWN::Plugins::ArtifactRegistry.list(session_id: sid)
39
+ hits[:artifacts] = artifacts if hits.is_a?(Hash)
40
+ hits << { artifacts: artifacts } if hits.is_a?(Array) && artifacts.any?
41
+ end
35
42
  }
36
43
  )
37
44
 
data/lib/pwn/ffi/stdio.rb CHANGED
@@ -34,7 +34,9 @@ module PWN
34
34
  # Display Usage for this Module
35
35
 
36
36
  public_class_method def self.help
37
- puts "USAGE:
37
+ # libc `puts` is attached on this module; use Kernel so $stdout capture
38
+ # (rspec help_contract) and the REPL both see Ruby IO, not fd 1 raw.
39
+ Kernel.puts "USAGE:
38
40
  # Run available and return its result
39
41
  #{self}.available?
40
42
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'open3'
4
+ require 'digest'
4
5
 
5
6
  module PWN
6
7
  module Plugins
@@ -11,7 +12,7 @@ module PWN
11
12
  end
12
13
 
13
14
  public_class_method def self.fuzz(opts = {})
14
- PWN::Plugins::Doctor.require_bin!(name: 'afl-fuzz')
15
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'afl-fuzz')
15
16
  in_dir = opts[:in_dir] || opts[:corpus]
16
17
  out_dir = opts[:out_dir] || opts[:output]
17
18
  target = opts[:target]
@@ -23,6 +24,19 @@ module PWN
23
24
  { stdout: stdout, stderr: stderr, exit: status.exitstatus }
24
25
  end
25
26
 
27
+ public_class_method def self.crash_triage(opts = {})
28
+ out_dir = (opts[:out_dir] || opts[:output]).to_s
29
+ raise 'ERROR: out_dir is required' if out_dir.empty?
30
+
31
+ crashes = Dir[File.join(out_dir, '**/crashes/id:*')]
32
+ hashes = crashes.map { |p| [p, Digest::SHA256.file(p).hexdigest] }
33
+ {
34
+ crashes: crashes,
35
+ unique: hashes.map(&:last).uniq,
36
+ asan: crashes.any? { |p| File.binread(p).include?('AddressSanitizer') }
37
+ }
38
+ end
39
+
26
40
  public_class_method def self.authors
27
41
  "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
28
42
  end
@@ -42,6 +56,12 @@ module PWN
42
56
  args: 'optional - Array args value consumed by #fuzz'
43
57
  )
44
58
 
59
+ # Dedup AFL++ crash files by sha256 and note AddressSanitizer hits.
60
+ #{self}.crash_triage(
61
+ out_dir: 'required - AFL output directory containing crashes/',
62
+ output: 'optional - alias for out_dir'
63
+ )
64
+
45
65
  # Print the AUTHOR(S) string for this module.
46
66
  #{self}.authors
47
67
  "
@@ -1286,16 +1286,22 @@ module PWN
1286
1286
  decoded = File.join(out, 'apktool')
1287
1287
  jadx_out = File.join(out, 'jadx')
1288
1288
  steps = []
1289
- if PWN::Plugins::Doctor.bin?(name: 'apktool')
1289
+ if PWN::Plugins::PreflightChecker.bin?(name: 'apktool')
1290
1290
  system('apktool', 'd', '-f', '-o', decoded, apk)
1291
1291
  steps << :apktool
1292
1292
  end
1293
- if PWN::Plugins::Doctor.bin?(name: 'jadx')
1293
+ if PWN::Plugins::PreflightChecker.bin?(name: 'jadx')
1294
1294
  FileUtils.mkdir_p(jadx_out)
1295
1295
  system('jadx', '-d', jadx_out, apk)
1296
1296
  steps << :jadx
1297
1297
  end
1298
- { out_dir: out, steps: steps, apk: apk }
1298
+ manifest = File.join(decoded, 'AndroidManifest.xml')
1299
+ perms = []
1300
+ if File.file?(manifest)
1301
+ txt = File.read(manifest)
1302
+ perms = txt.scan(/android:name="([^"]+)"/).flatten.grep(/PERMISSION|permission/)
1303
+ end
1304
+ { out_dir: out, steps: steps, apk: apk, permissions: perms, manifest: (File.file?(manifest) ? manifest : nil) }
1299
1305
  end
1300
1306
 
1301
1307
  # Author(s):: 0day Inc. <support@0dayinc.com>
@@ -19,7 +19,7 @@ module PWN
19
19
  end
20
20
 
21
21
  public_class_method def self.hydra(opts = {})
22
- PWN::Plugins::Doctor.require_bin!(name: 'hydra')
22
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'hydra')
23
23
  target = opts[:target].to_s
24
24
  service = (opts[:service] || 'ssh').to_s
25
25
  user = opts[:user] || opts[:login]
@@ -33,7 +33,7 @@ module PWN
33
33
  end
34
34
 
35
35
  public_class_method def self.john(opts = {})
36
- PWN::Plugins::Doctor.require_bin!(name: 'john')
36
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'john')
37
37
  hashfile = opts[:hashfile] || opts[:file]
38
38
  raise 'ERROR: hashfile is required' if hashfile.to_s.empty?
39
39
 
@@ -42,7 +42,7 @@ module PWN
42
42
  end
43
43
 
44
44
  public_class_method def self.hashcat(opts = {})
45
- PWN::Plugins::Doctor.require_bin!(name: 'hashcat')
45
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'hashcat')
46
46
  hashfile = opts[:hashfile] || opts[:file]
47
47
  mode = (opts[:mode] || 0).to_i
48
48
  wordlist = opts[:wordlist] || File.join(WORDLISTS, 'rockyou.txt')
@@ -50,6 +50,45 @@ module PWN
50
50
  { stdout: stdout, stderr: stderr, exit: status.exitstatus }
51
51
  end
52
52
 
53
+ public_class_method def self.medusa(opts = {})
54
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'medusa')
55
+ target = opts[:target].to_s
56
+ raise 'ERROR: target is required' if target.empty?
57
+
58
+ cmd = ['medusa', '-h', target, '-u', (opts[:user] || 'root').to_s, '-P', (opts[:wordlist] || File.join(WORDLISTS, 'rockyou.txt')).to_s, '-M', (opts[:module] || 'ssh').to_s]
59
+ stdout, stderr, status = Open3.capture3(*cmd)
60
+ { stdout: stdout, stderr: stderr, exit: status.exitstatus }
61
+ end
62
+
63
+ public_class_method def self.identify_hash(opts = {})
64
+ sample = (opts[:hash] || opts[:sample]).to_s
65
+ raise 'ERROR: hash is required' if sample.empty?
66
+
67
+ if PWN::Plugins::PreflightChecker.bin?(name: 'hashid')
68
+ stdout, = Open3.capture3('hashid', sample)
69
+ return { hash: sample, tool: 'hashid', stdout: stdout }
70
+ end
71
+
72
+ kind = case sample
73
+ when /\A\$2[aby]\$/ then 'bcrypt'
74
+ when /\A[a-f0-9]{32}\z/i then 'md5'
75
+ when /\A[a-f0-9]{40}\z/i then 'sha1'
76
+ when /\A[a-f0-9]{64}\z/i then 'sha256'
77
+ else 'unknown'
78
+ end
79
+ { hash: sample, kind: kind }
80
+ end
81
+
82
+ public_class_method def self.fetch_seclists(opts = {})
83
+ dest = (opts[:dest] || File.join(WORDLISTS, 'SecLists')).to_s
84
+ return dest if Dir.exist?(dest)
85
+
86
+ FileUtils.mkdir_p(File.dirname(dest))
87
+ url = opts[:url] || 'https://github.com/danielmiessler/SecLists.git'
88
+ stdout, stderr, status = Open3.capture3('git', 'clone', '--depth', '1', url, dest)
89
+ { dest: dest, stdout: stdout, stderr: stderr, exit: status.exitstatus }
90
+ end
91
+
53
92
  public_class_method def self.authors
54
93
  "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
55
94
  end
@@ -89,6 +128,26 @@ module PWN
89
128
  wordlist: 'optional - wordlist value consumed by #hashcat'
90
129
  )
91
130
 
131
+ # Run medusa against a host (lockout-aware: keep -t low).
132
+ #{self}.medusa(
133
+ target: 'required - hostname or IP',
134
+ user: 'optional - username (defaults to root)',
135
+ wordlist: 'optional - password list path',
136
+ module: 'optional - medusa module name (defaults to ssh)'
137
+ )
138
+
139
+ # Guess a hash type from a sample (hashid if present, else length heuristics).
140
+ #{self}.identify_hash(
141
+ hash: 'required - hash string to identify',
142
+ sample: 'optional - alias for hash'
143
+ )
144
+
145
+ # Clone SecLists into ~/.pwn/wordlists/SecLists when missing.
146
+ #{self}.fetch_seclists(
147
+ dest: 'optional - destination directory',
148
+ url: 'optional - git URL (defaults to danielmiessler/SecLists)'
149
+ )
150
+
92
151
  # Print the AUTHOR(S) string for this module.
93
152
  #{self}.authors
94
153
  "