pwn 0.5.428 → 0.5.430
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 +4 -4
- data/Gemfile +1 -1
- data/README.md +3 -3
- data/bin/pwn +4 -4
- data/bin/pwn_sast +20 -48
- data/etc/pwn.yaml.EXAMPLE +27 -22
- data/lib/pwn/ai/grok.rb +7 -0
- data/lib/pwn/ai/ollama.rb +7 -0
- data/lib/pwn/ai/open_ai.rb +7 -0
- data/lib/pwn/config.rb +81 -0
- data/lib/pwn/plugins/repl.rb +37 -53
- data/lib/pwn/plugins/vault.rb +1 -85
- data/lib/pwn/reports/sast.rb +45 -55
- data/lib/pwn/version.rb +1 -1
- data/lib/pwn.rb +5 -2
- data/spec/lib/pwn/config_spec.rb +10 -0
- data/third_party/pwn_rdoc.jsonl +12 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eecc95f7ab850f845600203b3fed19bb77d5d3737233a7f7f98df09b84154737
|
4
|
+
data.tar.gz: d838e72b716e9fc50e604a95600f1c9e43db9a42772e76073adc2f4cd673e96b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81dea57ae53b6401b7b5fa2784d5dc64e8b2a311ad1fc89c20c18e1024739ed66502db92be54ece95695df3b7a3fb25bbacd3aa311ac69d71bf5c2f4b23496c6
|
7
|
+
data.tar.gz: 071b3ac7ac65e4f282e3f59d223ec4c68c2f9b61b62442e613b4aa347ed6ab836cca10eafee0a148b79446c2adaf3e1a5bf60107b4871165d04d3017ef7b2fb3
|
data/Gemfile
CHANGED
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.
|
40
|
+
pwn[v0.5.430]:001 >>> PWN.help
|
41
41
|
```
|
42
42
|
|
43
43
|
[](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.
|
55
|
+
pwn[v0.5.430]: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.
|
65
|
+
pwn[v0.5.430]: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:
|
data/bin/pwn
CHANGED
@@ -10,12 +10,12 @@ OptionParser.new do |options|
|
|
10
10
|
#{File.basename($PROGRAM_NAME)} [opts]
|
11
11
|
"
|
12
12
|
|
13
|
-
options.on('-
|
14
|
-
opts[:
|
13
|
+
options.on('-YPATH', '--pwn-config=PATH', '<Optional - PWN YAML File>') do |p|
|
14
|
+
opts[:pwn_config_path] = p
|
15
15
|
end
|
16
16
|
|
17
|
-
options.on('-
|
18
|
-
opts[:
|
17
|
+
options.on('-ZPATH', '--pwn-decryptor=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
|
18
|
+
opts[:pwn_decryptor_path] = d
|
19
19
|
end
|
20
20
|
end.parse!
|
21
21
|
|
data/bin/pwn_sast
CHANGED
@@ -11,6 +11,15 @@ OptionParser.new do |options|
|
|
11
11
|
#{File.basename($PROGRAM_NAME)} [opts]
|
12
12
|
"
|
13
13
|
|
14
|
+
# TODO: HOW TO LOAD THE pwn.yaml CONFIGURATION FILE FOR EVERYTHING UNLESS OVERRIDDEN???
|
15
|
+
options.on('-YPATH', '--pwn-config=PATH', '<Optional - PWN YAML File>') do |p|
|
16
|
+
opts[:pwn_config_path] = p
|
17
|
+
end
|
18
|
+
|
19
|
+
options.on('-ZPATH', '--pwn-decryptor=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
|
20
|
+
opts[:pwn_decryptor_path] = d
|
21
|
+
end
|
22
|
+
|
14
23
|
options.on('-uGITURI', '--uri-source-root=GITURI', '<Required - HTTP URI of Git Repo Scanned e.g. https://github.com/0dayInc/pwn/tree/master>') do |u|
|
15
24
|
opts[:uri_source_root] = u
|
16
25
|
end
|
@@ -35,30 +44,6 @@ OptionParser.new do |options|
|
|
35
44
|
opts[:report_name] = n
|
36
45
|
end
|
37
46
|
|
38
|
-
options.on('-aENGINE', '--ai-engine=ENGINE', '<Optional AI Engine to Analyze Results (grok, ollama, openai) [WARNING: CAN DRAMATICALLY INCREASE AI USAGE COSTS AND/OR SCAN DURATIONS]>') do |a|
|
39
|
-
opts[:ai_engine] = a
|
40
|
-
end
|
41
|
-
|
42
|
-
options.on('-bURI', '--ai-base-uri=URI', '<Optional AI Base API URI (Only Required for "ollama" AI Engine. Supported by other LLMs when hosted privately)>') do |b|
|
43
|
-
opts[:ai_base_uri] = b
|
44
|
-
end
|
45
|
-
|
46
|
-
options.on('-mMODEL', '--ai-model=MODEL', '<Optional AI Model to Use for Respective AI Engine (e.g., grok-4-0709, grok-3-mini-fast, gpt5-chat-latest, chargpt-4o-latest, llama-3.1, etc.)>') do |m|
|
47
|
-
opts[:ai_model] = m
|
48
|
-
end
|
49
|
-
|
50
|
-
options.on('-kTOKEN', '--ai-key=TOKEN', '<Optional AI Key/Token for Respective AI Engine>') do |k|
|
51
|
-
opts[:ai_key] = k
|
52
|
-
end
|
53
|
-
|
54
|
-
options.on('-SCONTENT', '--ai-system-content=CONTENT', '<Optional AI System Role Content for Respective AI Engine (Defaults to, "Confidence score of 0-10 this is vulnerable (0 being not vulnerable, moving upwards in confidence of exploitation). Provide additional context to assist penetration tester assessment.")>') do |s|
|
55
|
-
opts[:ai_system_role_content] = s
|
56
|
-
end
|
57
|
-
|
58
|
-
options.on('-FTEMP', '--ai-temp=TEMP', '<Optional AI Temperature for Respective AI Engine (Default 0.9)>') do |t|
|
59
|
-
opts[:ai_temp] = t
|
60
|
-
end
|
61
|
-
|
62
47
|
options.on('-s', '--[no-]start-reporting-server', '<Optional - Start Simple HTTP Server for Reporting>') do |s|
|
63
48
|
opts[:start_reporting_server] = s
|
64
49
|
end
|
@@ -71,6 +56,16 @@ end
|
|
71
56
|
|
72
57
|
begin
|
73
58
|
timestamp = Time.now.strftime('%Y-%m-%d_%H:%M:%S%z')
|
59
|
+
|
60
|
+
pwn_config_path = opts[:pwn_config_path]
|
61
|
+
pwn_decryptor_path = opts[:pwn_decryptor_path]
|
62
|
+
if pwn_config_path
|
63
|
+
PWN::Config.refresh(
|
64
|
+
pwn_config_path: pwn_config_path,
|
65
|
+
pwn_decryptor_path: pwn_decryptor_path
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
74
69
|
previous_dir = Dir.pwd
|
75
70
|
|
76
71
|
pwn_provider = 'ruby-gem'
|
@@ -95,23 +90,6 @@ begin
|
|
95
90
|
report_name ||= "#{File.basename(Dir.pwd)}-#{timestamp}" if dir_path == '.'
|
96
91
|
report_name ||= "#{File.basename(dir_path)}-#{timestamp}" unless dir_path == '.'
|
97
92
|
|
98
|
-
ai_engine = opts[:ai_engine]
|
99
|
-
if ai_engine
|
100
|
-
ai_engine = ai_engine.to_s.to_sym
|
101
|
-
valid_ai_engines = %i[grok ollama openai]
|
102
|
-
raise "ERROR: Invalid AI Engine. Valid options are: #{valid_ai_engines.join(', ')}" unless valid_ai_engines.include?(ai_engine)
|
103
|
-
|
104
|
-
ai_base_uri = opts[:ai_base_uri]
|
105
|
-
raise 'ERROR: --base-uri Parameter for Ollama AI engine is required.' if ai_engine == :ollama && ai_base_uri.nil?
|
106
|
-
|
107
|
-
ai_model = opts[:ai_model]
|
108
|
-
raise 'ERROR: AI Model is required for AI engine ollama.' if ai_engine == :ollama && ai_model.nil?
|
109
|
-
|
110
|
-
ai_key = opts[:ai_key] ||= PWN::Plugins::AuthenticationHelper.mask_password(prompt: "#{ai_engine} Token")
|
111
|
-
ai_system_role_content = opts[:ai_system_role_content]
|
112
|
-
ai_temp = opts[:ai_temp]
|
113
|
-
end
|
114
|
-
|
115
93
|
start_reporting_server = opts[:start_reporting_server]
|
116
94
|
|
117
95
|
# Define Test Cases to Run & Start Thread Pool
|
@@ -202,13 +180,7 @@ begin
|
|
202
180
|
PWN::Reports::SAST.generate(
|
203
181
|
dir_path: dir_path,
|
204
182
|
results_hash: results_hash,
|
205
|
-
report_name: report_name
|
206
|
-
ai_engine: ai_engine,
|
207
|
-
ai_model: ai_model,
|
208
|
-
ai_key: ai_key,
|
209
|
-
ai_base_uri: ai_base_uri,
|
210
|
-
ai_system_role_content: ai_system_role_content,
|
211
|
-
ai_temp: ai_temp
|
183
|
+
report_name: report_name
|
212
184
|
)
|
213
185
|
puts 'complete.'
|
214
186
|
|
data/etc/pwn.yaml.EXAMPLE
CHANGED
@@ -1,7 +1,33 @@
|
|
1
1
|
# Drop this file in $HOME/.pwn/pwn.yaml
|
2
2
|
# Use PWN::Plugins::Vault.create(file: 'pwn.yaml') to encrypt this file
|
3
|
+
|
3
4
|
# ai_engine: 'openai' || 'ollama'
|
4
|
-
|
5
|
+
# WARNING::
|
6
|
+
# If PWN::CONFIG[:ai][:instrospection] = true, the active ai agent will be used
|
7
|
+
# wherever possible throughout pwn. Proceeds with caution, as this may incur additional costs
|
8
|
+
ai:
|
9
|
+
active: 'grok'
|
10
|
+
introspection: false
|
11
|
+
grok:
|
12
|
+
base_uri: 'optional - Base URI for Grok - Use private base OR defaults to https://api.x.ai/v1'
|
13
|
+
key: 'required - OpenAI API Key'
|
14
|
+
model: 'optional - Grok model to use'
|
15
|
+
system_role_content: 'You are an ethically hacking OpenAI agent.'
|
16
|
+
temp: 'optional - OpenAI temperature'
|
17
|
+
|
18
|
+
openai:
|
19
|
+
base_uri: 'optional - Base URI for OpenAI - Use private base OR defaults to https://api.openai.com/v1'
|
20
|
+
key: 'required - OpenAI API Key'
|
21
|
+
model: 'optional - OpenAI model to use'
|
22
|
+
system_role_content: 'You are an ethically hacking OpenAI agent.'
|
23
|
+
temp: 'optional - OpenAI temperature'
|
24
|
+
|
25
|
+
ollama:
|
26
|
+
base_uri: 'required - Base URI for Open WebUI - e.g. https://ollama.local'
|
27
|
+
key: 'required - Open WebUI API Key Under Settings >> Account >> JWT Token'
|
28
|
+
model: 'required - Ollama model to use'
|
29
|
+
system_role_content: 'You are an ethically hacking Ollama agent.'
|
30
|
+
temp: 'optional - Ollama temperature'
|
5
31
|
|
6
32
|
# Use PWN::Plugins::Assembly.list_supported_archs to list supported architectures
|
7
33
|
asm:
|
@@ -28,27 +54,6 @@ irc:
|
|
28
54
|
hunter:
|
29
55
|
api_key: 'hunter.how API Key'
|
30
56
|
|
31
|
-
grok:
|
32
|
-
base_uri: 'optional - Base URI for Grok - Use private base OR defaults to https://api.x.ai/v1'
|
33
|
-
key: 'required - OpenAI API Key'
|
34
|
-
model: 'optional - Grok model to use'
|
35
|
-
system_role_content: 'You are an ethically hacking OpenAI agent.'
|
36
|
-
temp: 'optional - OpenAI temperature'
|
37
|
-
|
38
|
-
openai:
|
39
|
-
base_uri: 'optional - Base URI for OpenAI - Use private base OR defaults to https://api.openai.com/v1'
|
40
|
-
key: 'required - OpenAI API Key'
|
41
|
-
model: 'optional - OpenAI model to use'
|
42
|
-
system_role_content: 'You are an ethically hacking OpenAI agent.'
|
43
|
-
temp: 'optional - OpenAI temperature'
|
44
|
-
|
45
|
-
ollama:
|
46
|
-
base_uri: 'required - Base URI for Open WebUI - e.g. https://ollama.local'
|
47
|
-
key: 'required - Open WebUI API Key Under Settings >> Account >> JWT Token'
|
48
|
-
model: 'required - Ollama model to use'
|
49
|
-
system_role_content: 'You are an ethically hacking Ollama agent.'
|
50
|
-
temp: 'optional - Ollama temperature'
|
51
|
-
|
52
57
|
meshtastic:
|
53
58
|
psks:
|
54
59
|
LongFast: 'required - PSK for LongFast channel'
|
data/lib/pwn/ai/grok.rb
CHANGED
@@ -25,6 +25,13 @@ module PWN
|
|
25
25
|
|
26
26
|
private_class_method def self.grok_rest_call(opts = {})
|
27
27
|
token = opts[:token]
|
28
|
+
if token.nil?
|
29
|
+
PWN::Plugins::AuthenticationHelper.mask_password(
|
30
|
+
prompt: 'Grok Key'
|
31
|
+
)
|
32
|
+
PWN::CONFIG[:ai][:grok][:key] = token
|
33
|
+
end
|
34
|
+
|
28
35
|
http_method = if opts[:http_method].nil?
|
29
36
|
:get
|
30
37
|
else
|
data/lib/pwn/ai/ollama.rb
CHANGED
@@ -27,6 +27,13 @@ module PWN
|
|
27
27
|
private_class_method def self.ollama_rest_call(opts = {})
|
28
28
|
base_uri = opts[:base_uri]
|
29
29
|
token = opts[:token]
|
30
|
+
if token.nil?
|
31
|
+
PWN::Plugins::AuthenticationHelper.mask_password(
|
32
|
+
prompt: 'Ollama Key'
|
33
|
+
)
|
34
|
+
PWN::CONFIG[:ai][:ollama][:key] = token
|
35
|
+
end
|
36
|
+
|
30
37
|
http_method = if opts[:http_method].nil?
|
31
38
|
:get
|
32
39
|
else
|
data/lib/pwn/ai/open_ai.rb
CHANGED
@@ -26,6 +26,13 @@ module PWN
|
|
26
26
|
|
27
27
|
private_class_method def self.open_ai_rest_call(opts = {})
|
28
28
|
token = opts[:token]
|
29
|
+
if token.nil?
|
30
|
+
PWN::Plugins::AuthenticationHelper.mask_password(
|
31
|
+
prompt: 'OpenAI Key'
|
32
|
+
)
|
33
|
+
PWN::CONFIG[:ai][:openai][:key] = token
|
34
|
+
end
|
35
|
+
|
29
36
|
http_method = if opts[:http_method].nil?
|
30
37
|
:get
|
31
38
|
else
|
data/lib/pwn/config.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module PWN
|
7
|
+
# Used to manage PWN configuration settings within PWN drivers.
|
8
|
+
module Config
|
9
|
+
# Supported Method Parameters::
|
10
|
+
# PWN::Config.refresh(
|
11
|
+
# pwn_config_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml',
|
12
|
+
# pwn_decryptor_path: 'optional - Path to pwn.decryptor.yaml file. Defaults to ~/.pwn/pwn.decryptor.yaml'
|
13
|
+
# )
|
14
|
+
|
15
|
+
public_class_method def self.refresh(opts = {})
|
16
|
+
pwn_config_root = "#{Dir.home}/.pwn"
|
17
|
+
FileUtils.mkdir_p(pwn_config_root)
|
18
|
+
|
19
|
+
pwn_config_path = opts[:pwn_config_path] ||= "#{pwn_config_root}/pwn.yaml"
|
20
|
+
raise "PWN Config (#{pwn_config_path}) does not exist!" unless File.exist?(pwn_config_path)
|
21
|
+
|
22
|
+
is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: pwn_config_path)
|
23
|
+
|
24
|
+
if is_encrypted
|
25
|
+
pwn_decryptor_path = opts[:pwn_decryptor_path] ||= "#{pwn_config_root}/pwn.decryptor.yaml"
|
26
|
+
raise "PWN Decryptor (#{pwn_decryptor_path}) does not exist!" unless File.exist?(pwn_decryptor_path)
|
27
|
+
|
28
|
+
pwn_decryptor = YAML.load_file(pwn_decryptor_path, symbolize_names: true)
|
29
|
+
|
30
|
+
key = opts[:key] ||= pwn_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
|
31
|
+
key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
|
32
|
+
|
33
|
+
iv = opts[:iv] ||= pwn_decryptor[:iv] ||= ENV.fetch('PWN_DECRYPTOR_IV')
|
34
|
+
iv = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption IV') if iv.nil?
|
35
|
+
|
36
|
+
config = PWN::Plugins::Vault.dump(
|
37
|
+
file: pwn_config_path,
|
38
|
+
key: key,
|
39
|
+
iv: iv
|
40
|
+
)
|
41
|
+
else
|
42
|
+
config = YAML.load_file(pwn_config_path, symbolize_names: true)
|
43
|
+
end
|
44
|
+
|
45
|
+
valid_ai_engines = %i[
|
46
|
+
grok
|
47
|
+
openai
|
48
|
+
ollama
|
49
|
+
]
|
50
|
+
|
51
|
+
engine = config[:ai][:active].to_s.downcase.to_sym
|
52
|
+
raise "ERROR: Unsupported AI Engine: #{engine} in #{pwn_config_path}. Supported AI Engines:\n#{valid_ai_engines.inspect}" unless valid_ai_engines.include?(engine)
|
53
|
+
|
54
|
+
model = config[:ai][engine][:model]
|
55
|
+
system_role_content = config[:ai][engine][:system_role_content]
|
56
|
+
|
57
|
+
# Reset the ai response history on config refresh
|
58
|
+
config[:ai][engine][:response_history] = {
|
59
|
+
id: '',
|
60
|
+
object: '',
|
61
|
+
model: model,
|
62
|
+
usage: {},
|
63
|
+
choices: [
|
64
|
+
{
|
65
|
+
role: 'system',
|
66
|
+
content: system_role_content
|
67
|
+
}
|
68
|
+
]
|
69
|
+
}
|
70
|
+
|
71
|
+
# These two lines should be immutable for the session
|
72
|
+
config[:pwn_config_path] = pwn_config_path
|
73
|
+
config[:pwn_decryptor_path] = pwn_decryptor_path if is_encrypted
|
74
|
+
|
75
|
+
Pry.config.refresh = false if defined?(Pry)
|
76
|
+
|
77
|
+
PWN.send(:remove_const, :CONFIG) if PWN.const_defined?(:CONFIG)
|
78
|
+
PWN.const_set(:CONFIG, config)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/pwn/plugins/repl.rb
CHANGED
@@ -18,11 +18,7 @@ module PWN
|
|
18
18
|
mode = opts[:mode]
|
19
19
|
|
20
20
|
proc do |_target_self, _nest_level, pi|
|
21
|
-
if Pry.config.refresh
|
22
|
-
# puts "Refreshing PWN env via #{opts[:yaml_config_path]}"
|
23
|
-
opts[:pi] = pi
|
24
|
-
PWN::Plugins::Vault.refresh_config_for_repl(opts)
|
25
|
-
end
|
21
|
+
pi.config.pwn = PWN::Config.refresh(opts) if Pry.config.refresh
|
26
22
|
|
27
23
|
pi.config.pwn_repl_line += 1
|
28
24
|
line_pad = format(
|
@@ -48,13 +44,13 @@ module PWN
|
|
48
44
|
end
|
49
45
|
|
50
46
|
if pi.config.pwn_ai
|
51
|
-
|
52
|
-
model = pi.config.pwn[
|
53
|
-
system_role_content = pi.config.pwn[
|
54
|
-
temp = pi.config.pwn[
|
55
|
-
pname = "pwn.ai:#{
|
56
|
-
pname = "pwn.ai:#{
|
57
|
-
pname = "pwn.ai:#{
|
47
|
+
engine = pi.config.pwn[:ai][:active].to_s.downcase.to_sym
|
48
|
+
model = pi.config.pwn[:ai][engine][:model]
|
49
|
+
system_role_content = pi.config.pwn[:ai][engine][:system_role_content]
|
50
|
+
temp = pi.config.pwn[:ai][engine][:temp]
|
51
|
+
pname = "pwn.ai:#{engine}"
|
52
|
+
pname = "pwn.ai:#{engine}/#{model}" if model
|
53
|
+
pname = "pwn.ai:#{engine}/#{model}.SPEAK" if pi.config.pwn_ai_speak
|
58
54
|
pi.config.prompt_name = pname
|
59
55
|
|
60
56
|
name = "\001\e[1m\002\001\e[33m\002#{pi.config.prompt_name}\001\e[0m\002"
|
@@ -306,12 +302,12 @@ module PWN
|
|
306
302
|
next unless dm_agent == nick
|
307
303
|
|
308
304
|
response_history = ai_agents[dm_agent.to_sym][:response_history]
|
309
|
-
|
310
|
-
base_uri = pi.config.pwn[
|
311
|
-
key = pi.config.pwn[
|
312
|
-
temp = pi.config.pwn[
|
313
|
-
model = pi.config.pwn[
|
314
|
-
system_role_content = pi.config.pwn[
|
305
|
+
engine = pi.config.pwn[:ai][:active].to_s.downcase.to_sym
|
306
|
+
base_uri = pi.config.pwn[:ai][engine][:base_uri]
|
307
|
+
key = pi.config.pwn[:ai][engine][:key] ||= ''
|
308
|
+
temp = pi.config.pwn[:ai][engine][:temp]
|
309
|
+
model = pi.config.pwn[:ai][engine][:model]
|
310
|
+
system_role_content = pi.config.pwn[:ai][engine][:system_role_content]
|
315
311
|
|
316
312
|
users_in_chan = PWN::Plugins::IRC.names(
|
317
313
|
irc_obj: irc_obj,
|
@@ -342,7 +338,7 @@ module PWN
|
|
342
338
|
message.
|
343
339
|
"
|
344
340
|
|
345
|
-
case
|
341
|
+
case engine
|
346
342
|
when :grok
|
347
343
|
response = PWN::AI::Grok.chat(
|
348
344
|
base_uri: base_uri,
|
@@ -459,29 +455,29 @@ module PWN
|
|
459
455
|
end
|
460
456
|
end
|
461
457
|
|
462
|
-
Pry::Commands.create_command 'pwn-vault
|
458
|
+
Pry::Commands.create_command 'pwn-vault' do
|
463
459
|
description 'Edit the pwn.yaml configuration file.'
|
464
460
|
|
465
461
|
def process
|
466
462
|
pi = pry_instance
|
467
|
-
|
468
|
-
unless File.exist?(
|
469
|
-
puts "ERROR: pwn.yaml not found: #{
|
463
|
+
pwn_config_path = pi.config.pwn_config_path ||= "#{Dir.home}/.pwn/pwn.yaml"
|
464
|
+
unless File.exist?(pwn_config_path)
|
465
|
+
puts "ERROR: pwn.yaml not found: #{pwn_config_path}"
|
470
466
|
return
|
471
467
|
end
|
472
468
|
|
473
|
-
|
474
|
-
unless File.exist?(
|
475
|
-
puts "ERROR: pwn.decryptor.yaml not found: #{
|
469
|
+
pwn_decryptor_path = pi.config.pwn_decryptor_path ||= "#{Dir.home}/.pwn/pwn.decryptor.yaml"
|
470
|
+
unless File.exist?(pwn_decryptor_path)
|
471
|
+
puts "ERROR: pwn.decryptor.yaml not found: #{pwn_decryptor_path}"
|
476
472
|
return
|
477
473
|
end
|
478
474
|
|
479
|
-
decryptor = YAML.load_file(
|
475
|
+
decryptor = YAML.load_file(pwn_decryptor_path, symbolize_names: true)
|
480
476
|
key = decryptor[:key]
|
481
477
|
iv = decryptor[:iv]
|
482
478
|
|
483
479
|
PWN::Plugins::Vault.edit(
|
484
|
-
file:
|
480
|
+
file: pwn_config_path,
|
485
481
|
key: key,
|
486
482
|
iv: iv
|
487
483
|
)
|
@@ -539,9 +535,7 @@ module PWN
|
|
539
535
|
|
540
536
|
# Initialize pwn.yaml Configuration using :before_session Hook
|
541
537
|
Pry.config.hooks.add_hook(:before_session, :init_opts) do |_output, _binding, pi|
|
542
|
-
|
543
|
-
opts[:pi] = pi
|
544
|
-
PWN::Plugins::Vault.refresh_config_for_repl(opts)
|
538
|
+
pi.config.pwn = PWN::Config.refresh(opts)
|
545
539
|
end
|
546
540
|
|
547
541
|
Pry.config.hooks.add_hook(:after_read, :pwn_asm_hook) do |request, pi|
|
@@ -585,23 +579,16 @@ module PWN
|
|
585
579
|
if pi.config.pwn_ai && !request.chomp.empty?
|
586
580
|
request = pi.input.line_buffer.to_s
|
587
581
|
debug = pi.config.pwn_ai_debug
|
588
|
-
|
589
|
-
base_uri = pi.config.pwn[
|
590
|
-
key = pi.config.pwn[
|
591
|
-
|
592
|
-
key = PWN::Plugins::AuthenticationHelper.mask_password(
|
593
|
-
prompt: 'pwn-ai Key'
|
594
|
-
)
|
595
|
-
pi.config.pwn[ai_engine][:key] = key
|
596
|
-
end
|
597
|
-
|
598
|
-
response_history = pi.config.pwn_ai_response_history
|
582
|
+
engine = pi.config.pwn[:ai][:active].to_s.downcase.to_sym
|
583
|
+
base_uri = pi.config.pwn[:ai][engine][:base_uri]
|
584
|
+
key = pi.config.pwn[:ai][engine][:key] ||= ''
|
585
|
+
response_history = pi.config.pwn[:ai][engine][:response_history]
|
599
586
|
speak_answer = pi.config.pwn_ai_speak
|
600
|
-
model = pi.config.pwn[
|
601
|
-
system_role_content = pi.config.pwn[
|
602
|
-
temp = pi.config.pwn[
|
587
|
+
model = pi.config.pwn[:ai][engine][:model]
|
588
|
+
system_role_content = pi.config.pwn[:ai][engine][:system_role_content]
|
589
|
+
temp = pi.config.pwn[:ai][engine][:temp]
|
603
590
|
|
604
|
-
case
|
591
|
+
case engine
|
605
592
|
when :grok
|
606
593
|
response = PWN::AI::Grok.chat(
|
607
594
|
base_uri: base_uri,
|
@@ -639,7 +626,7 @@ module PWN
|
|
639
626
|
spinner: true
|
640
627
|
)
|
641
628
|
else
|
642
|
-
raise "ERROR: Unsupported AI Engine: #{
|
629
|
+
raise "ERROR: Unsupported AI Engine: #{engine}"
|
643
630
|
end
|
644
631
|
# puts response.inspect
|
645
632
|
|
@@ -668,7 +655,7 @@ module PWN
|
|
668
655
|
pp response_history
|
669
656
|
puts "\nresponse_history[:choices] Length: #{response_history[:choices].length}\n" unless response_history.nil?
|
670
657
|
end
|
671
|
-
pi.config.
|
658
|
+
pi.config.pwn[:ai][engine][:response_history] = response_history
|
672
659
|
end
|
673
660
|
end
|
674
661
|
rescue StandardError => e
|
@@ -683,13 +670,10 @@ module PWN
|
|
683
670
|
public_class_method def self.start(opts = {})
|
684
671
|
# Monkey Patch Pry, add commands, && hooks
|
685
672
|
PWN::Plugins::MonkeyPatch.pry
|
686
|
-
add_commands
|
687
|
-
|
688
673
|
pwn_config_root = "#{Dir.home}/.pwn"
|
689
|
-
|
690
|
-
opts[:yaml_config_path] ||= "#{pwn_config_root}/pwn.yaml"
|
691
|
-
opts[:yaml_decryptor_path] ||= "#{pwn_config_root}/pwn.decryptor.yaml"
|
674
|
+
Pry.config.history_file = "#{pwn_config_root}/pwn_history"
|
692
675
|
|
676
|
+
add_commands
|
693
677
|
add_hooks(opts)
|
694
678
|
|
695
679
|
# Define PS1 Prompt
|
data/lib/pwn/plugins/vault.rb
CHANGED
@@ -15,7 +15,7 @@ module PWN
|
|
15
15
|
# iv: 'required - iv to decrypt'
|
16
16
|
# )
|
17
17
|
|
18
|
-
def self.refresh_encryption_secrets(opts = {})
|
18
|
+
public_class_method def self.refresh_encryption_secrets(opts = {})
|
19
19
|
file = opts[:file].to_s.scrub if File.exist?(opts[:file].to_s.scrub)
|
20
20
|
key = opts[:key]
|
21
21
|
iv = opts[:iv]
|
@@ -234,84 +234,6 @@ module PWN
|
|
234
234
|
raise e
|
235
235
|
end
|
236
236
|
|
237
|
-
# Supported Method Parameters::
|
238
|
-
# PWN::Plugins::Vault.refresh_config_for_repl(
|
239
|
-
# yaml_config_path: 'required - full path to pwn.yaml file',
|
240
|
-
# pi: 'optional - Pry instance (default: Pry)',
|
241
|
-
# yaml_decryptor_path: 'optional - full path to decryption YAML file'
|
242
|
-
# )
|
243
|
-
public_class_method def self.refresh_config_for_repl(opts = {})
|
244
|
-
yaml_config_path = opts[:yaml_config_path]
|
245
|
-
|
246
|
-
return false unless File.exist?(yaml_config_path)
|
247
|
-
|
248
|
-
pi = opts[:pi]
|
249
|
-
raise 'ERROR: Pry instance is required.' if pi.nil?
|
250
|
-
|
251
|
-
is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: yaml_config_path)
|
252
|
-
|
253
|
-
if is_encrypted
|
254
|
-
# TODO: Implement "something you know, something you have, && something you are?"
|
255
|
-
yaml_decryptor_path = opts[:yaml_decryptor_path] ||= "#{Dir.home}/.pwn/pwn.decryptor.yaml"
|
256
|
-
raise "ERROR: #{yaml_decryptor_path} does not exist." unless File.exist?(yaml_decryptor_path)
|
257
|
-
|
258
|
-
yaml_decryptor = YAML.load_file(yaml_decryptor_path, symbolize_names: true)
|
259
|
-
|
260
|
-
key = opts[:key] ||= yaml_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
|
261
|
-
key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
|
262
|
-
|
263
|
-
iv = opts[:iv] ||= yaml_decryptor[:iv] ||= ENV.fetch('PWN_DECRYPTOR_IV')
|
264
|
-
iv = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption IV') if iv.nil?
|
265
|
-
|
266
|
-
yaml_config = PWN::Plugins::Vault.dump(
|
267
|
-
file: yaml_config_path,
|
268
|
-
key: key,
|
269
|
-
iv: iv
|
270
|
-
)
|
271
|
-
else
|
272
|
-
yaml_config = YAML.load_file(yaml_config_path, symbolize_names: true)
|
273
|
-
end
|
274
|
-
|
275
|
-
valid_ai_engines = %i[
|
276
|
-
grok
|
277
|
-
openai
|
278
|
-
ollama
|
279
|
-
]
|
280
|
-
|
281
|
-
# Convert ai_engine to symbol and downcase to ensure stability
|
282
|
-
yaml_config[:ai_engine] = yaml_config[:ai_engine].to_s.downcase.to_sym
|
283
|
-
pi.config.pwn = yaml_config
|
284
|
-
ai_engine = pi.config.pwn[:ai_engine]
|
285
|
-
raise "ERROR: Unsupported AI Engine: #{ai_engine} in #{yaml_config_path}. Supported AI Engines:\n#{valid_ai_engines.inspect}" unless valid_ai_engines.include?(ai_engine)
|
286
|
-
|
287
|
-
model = pi.config.pwn[ai_engine][:model]
|
288
|
-
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
289
|
-
|
290
|
-
# Reset the ai response history for new configurations
|
291
|
-
pi.config.pwn_ai_response_history = {
|
292
|
-
id: '',
|
293
|
-
object: '',
|
294
|
-
model: model,
|
295
|
-
usage: {},
|
296
|
-
choices: [
|
297
|
-
{
|
298
|
-
role: 'system',
|
299
|
-
content: system_role_content
|
300
|
-
}
|
301
|
-
]
|
302
|
-
}
|
303
|
-
|
304
|
-
# These two lines should be immutable for the session
|
305
|
-
pi.config.pwn[:yaml_config_path] = yaml_config_path
|
306
|
-
pi.config.pwn[:yaml_decryptor_path] = yaml_decryptor_path if is_encrypted
|
307
|
-
|
308
|
-
Pry.config.refresh = false
|
309
|
-
|
310
|
-
true
|
311
|
-
rescue StandardError => e
|
312
|
-
raise e
|
313
|
-
end
|
314
|
-
|
315
237
|
# Author(s):: 0day Inc. <support@0dayinc.com>
|
316
238
|
|
317
239
|
public_class_method def self.authors
|
@@ -364,12 +286,6 @@ module PWN
|
|
364
286
|
file: 'required - file to check if encrypted'
|
365
287
|
)
|
366
288
|
|
367
|
-
#{self}.refresh_config_for_repl(
|
368
|
-
yaml_config_path: 'required - full path to pwn.yaml file',
|
369
|
-
pi: 'optional - Pry instance (default: Pry)',
|
370
|
-
yaml_decryptor_path: 'optional - full path to decryption YAML file'
|
371
|
-
)
|
372
|
-
|
373
289
|
#{self}.authors
|
374
290
|
"
|
375
291
|
end
|
data/lib/pwn/reports/sast.rb
CHANGED
@@ -14,13 +14,7 @@ module PWN
|
|
14
14
|
# PWN::Reports::SAST.generate(
|
15
15
|
# dir_path: 'optional - Directory path to save the report (defaults to .)',
|
16
16
|
# results_hash: 'optional - Hash containing the results of the SAST analysis (defaults to empty hash structure)',
|
17
|
-
# report_name: 'optional - Name of the report file (defaults to current directory name)'
|
18
|
-
# ai_engine: 'optional - AI engine to use for analysis (:grok, :ollama, or :openai)',
|
19
|
-
# ai_model: 'optionnal - AI Model to Use for Respective AI Engine (e.g., grok-4i-0709, chargpt-4o-latest, llama-3.1, etc.)',
|
20
|
-
# ai_key: 'optional - AI Key/Token for Respective AI Engine',
|
21
|
-
# ai_base_uri: 'optional - AI FQDN (Only Required for "ollama" AI Engine)',
|
22
|
-
# ai_system_role_content: 'optional - AI System Role Content (Defaults to "Confidence score of 0-10 this is vulnerable (0 being not vulnerable, moving upwards in confidence of exploitation). Provide additional context to assist penetration tester assessment.")',
|
23
|
-
# ai_temp: 'optional - AI Temperature (Defaults to 0.1)'
|
17
|
+
# report_name: 'optional - Name of the report file (defaults to current directory name)'
|
24
18
|
# )
|
25
19
|
|
26
20
|
public_class_method def self.generate(opts = {})
|
@@ -31,28 +25,21 @@ module PWN
|
|
31
25
|
}
|
32
26
|
report_name = opts[:report_name] ||= File.basename(Dir.pwd)
|
33
27
|
|
34
|
-
|
35
|
-
if
|
36
|
-
|
37
|
-
|
38
|
-
|
28
|
+
ai_instrospection = PWN::CONFIG[:ai][:introspection]
|
29
|
+
if ai_instrospection
|
30
|
+
engine = PWN::CONFIG[:ai][:active].to_s.downcase.to_sym
|
31
|
+
base_uri = PWN::CONFIG[:ai][engine][:base_uri]
|
32
|
+
model = PWN::CONFIG[:ai][engine][:model]
|
33
|
+
key = PWN::CONFIG[:ai][engine][:key]
|
34
|
+
system_role_content = PWN::CONFIG[:ai][engine][:system_role_content]
|
35
|
+
temp = PWN::CONFIG[:ai][engine][:temp]
|
39
36
|
|
40
|
-
|
41
|
-
raise 'ERROR: FQDN for Ollama AI engine is required.' if ai_engine == :ollama && ai_base_uri.nil?
|
42
|
-
|
43
|
-
ai_model = opts[:ai_model]
|
44
|
-
raise 'ERROR: AI Model is required for AI engine ollama.' if ai_engine == :ollama && ai_model.nil?
|
45
|
-
|
46
|
-
ai_key = opts[:ai_key] ||= PWN::Plugins::AuthenticationHelper.mask_password(prompt: "#{ai_engine} Token")
|
47
|
-
ai_system_role_content = opts[:ai_system_role_content] ||= 'Your sole purpose is to analyze source code snippets and generate an Exploit Prediction Scoring System (EPSS) score between 0% - 100%. Just generate a score unless score is higher than 75% in which a code fic should also be included.'
|
48
|
-
ai_temp = opts[:ai_temp] ||= 0.1
|
49
|
-
|
50
|
-
puts "Analyzing source code using AI engine: #{ai_engine}\nModel: #{ai_model}\nSystem Role Content: #{ai_system_role_content}\nTemperature: #{ai_temp}"
|
37
|
+
puts "Analyzing source code using AI engine: #{engine}\nModel: #{model}\nSystem Role Content: #{system_role_content}\nTemperature: #{temp}"
|
51
38
|
end
|
52
39
|
|
53
40
|
# Calculate percentage of AI analysis based on the number of entries
|
54
41
|
total_entries = results_hash[:data].sum { |entry| entry[:line_no_and_contents].size }
|
55
|
-
puts "Total entries to analyze: #{total_entries}" if
|
42
|
+
puts "Total entries to analyze: #{total_entries}" if engine
|
56
43
|
|
57
44
|
percent_complete = 0.0
|
58
45
|
entry_count = 0
|
@@ -79,37 +66,39 @@ module PWN
|
|
79
66
|
response = nil
|
80
67
|
author = src_detail[:author].to_s.scrub.chomp.strip
|
81
68
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
69
|
+
if ai_instrospection
|
70
|
+
case engine
|
71
|
+
when :grok
|
72
|
+
response = PWN::AI::Grok.chat(
|
73
|
+
base_uri: base_uri,
|
74
|
+
token: key,
|
75
|
+
model: model,
|
76
|
+
system_role_content: system_role_content,
|
77
|
+
temp: temp,
|
78
|
+
request: request.chomp,
|
79
|
+
spinner: false
|
80
|
+
)
|
81
|
+
when :ollama
|
82
|
+
response = PWN::AI::Ollama.chat(
|
83
|
+
base_uri: base_uri,
|
84
|
+
token: key,
|
85
|
+
model: model,
|
86
|
+
system_role_content: system_role_content,
|
87
|
+
temp: temp,
|
88
|
+
request: request.chomp,
|
89
|
+
spinner: false
|
90
|
+
)
|
91
|
+
when :openai
|
92
|
+
response = PWN::AI::OpenAI.chat(
|
93
|
+
base_uri: base_uri,
|
94
|
+
token: key,
|
95
|
+
model: model,
|
96
|
+
system_role_content: system_role_content,
|
97
|
+
temp: temp,
|
98
|
+
request: request.chomp,
|
99
|
+
spinner: false
|
100
|
+
)
|
101
|
+
end
|
113
102
|
end
|
114
103
|
|
115
104
|
ai_analysis = nil
|
@@ -118,6 +107,7 @@ module PWN
|
|
118
107
|
ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
|
119
108
|
# puts "AI Analysis Progress: #{percent_complete}% Line: #{line_no} | Author: #{author} | AI Analysis: #{ai_analysis}\n\n\n" if ai_analysis
|
120
109
|
end
|
110
|
+
# TODO: Make results prettier in the HTML report
|
121
111
|
src_detail[:ai_analysis] = ai_analysis.to_s.scrub.chomp.strip
|
122
112
|
|
123
113
|
spin.update(
|
data/lib/pwn/version.rb
CHANGED
data/lib/pwn.rb
CHANGED
@@ -12,19 +12,22 @@ module PWN
|
|
12
12
|
autoload :AWS, 'pwn/aws'
|
13
13
|
autoload :Banner, 'pwn/banner'
|
14
14
|
autoload :Blockchain, 'pwn/blockchain'
|
15
|
+
autoload :Config, 'pwn/config'
|
15
16
|
autoload :FFI, 'pwn/ffi'
|
16
17
|
autoload :Plugins, 'pwn/plugins'
|
17
18
|
autoload :Reports, 'pwn/reports'
|
18
19
|
autoload :SAST, 'pwn/sast'
|
19
20
|
autoload :WWW, 'pwn/www'
|
20
|
-
# TODO: If pwn.yaml is present, attempt to decrypt it, and initialize the YAML config
|
21
|
-
# Do this within PWN::Plugins::AuthenticationHelper?
|
22
21
|
|
23
22
|
# Display a List of Every PWN Module
|
24
23
|
|
25
24
|
public_class_method def self.help
|
26
25
|
constants.sort
|
27
26
|
end
|
27
|
+
|
28
|
+
# Initialize PWN configuration file
|
29
|
+
# PWN::CONFIG is the constant that stores the configuration data
|
30
|
+
PWN::Config.refresh
|
28
31
|
rescue StandardError => e
|
29
32
|
puts e.backtrace
|
30
33
|
raise e
|
data/third_party/pwn_rdoc.jsonl
CHANGED
@@ -438,6 +438,17 @@
|
|
438
438
|
{"messages":[{"role":"user","content":"PWN::Banner::WhiteRabbit.authors Usage"},{"role":"assistant","content":"`PWN::Banner::WhiteRabbit.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
439
439
|
{"messages":[{"role":"user","content":"PWN::Banner::WhiteRabbit.get Usage"},{"role":"assistant","content":"`PWN::Banner::WhiteRabbit.get`: Supported Method Parameters\n\nPWN::Banner::WhiteRabbit.get\n"}]}
|
440
440
|
{"messages":[{"role":"user","content":"PWN::Banner::WhiteRabbit.help Usage"},{"role":"assistant","content":"`PWN::Banner::WhiteRabbit.help`: "}]}
|
441
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain.help Usage"},{"role":"assistant","content":"`PWN::Blockchain.help`: "}]}
|
442
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::BTC.authors Usage"},{"role":"assistant","content":"`PWN::Blockchain::BTC.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
443
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::BTC.btc_rest_call Usage"},{"role":"assistant","content":"`PWN::Blockchain::BTC.btc_rest_call`: Supported Method Parameters\n\nbtc_rest_call(\n\nhttp_method: 'optional HTTP method (defaults to GET)\nrest_call: 'required rest call to make per the schema',\nparams: 'optional params passed in the URI or HTTP Headers',\nhttp_body: 'optional HTTP body sent in HTTP methods that support it e.g. POST',\ntimeout: 'optional timeout in seconds (defaults to 180)',\nspinner: 'optional - display spinner (defaults to false)'\n\n)\n"}]}
|
444
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::BTC.get_block_details Usage"},{"role":"assistant","content":"`PWN::Blockchain::BTC.get_block_details`: Supported Method Parameters\n\nPWN::Blockchain::BTC.get_block_details(\n\nheight: 'required - block height number',\ntoken: 'optional - API token for higher rate limits'\n\n)\n"}]}
|
445
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::BTC.get_latest_block Usage"},{"role":"assistant","content":"`PWN::Blockchain::BTC.get_latest_block`: Supported Method Parameters\n\nlatest_block = PWN::Blockchain::BTC.get_latest_block(\n\ntoken: 'optional - API token for higher rate limits'\n\n)\n"}]}
|
446
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::BTC.help Usage"},{"role":"assistant","content":"`PWN::Blockchain::BTC.help`: "}]}
|
447
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::ETH.authors Usage"},{"role":"assistant","content":"`PWN::Blockchain::ETH.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
448
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::ETH.eth_rest_call Usage"},{"role":"assistant","content":"`PWN::Blockchain::ETH.eth_rest_call`: Supported Method Parameters\n\neth_rest_call(\n\nhttp_method: 'optional HTTP method (defaults to GET)\nrest_call: 'required rest call to make per the schema',\nparams: 'optional params passed in the URI or HTTP Headers',\nhttp_body: 'optional HTTP body sent in HTTP methods that support it e.g. POST',\ntimeout: 'optional timeout in seconds (defaults to 180)',\nspinner: 'optional - display spinner (defaults to false)'\n\n)\n"}]}
|
449
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::ETH.get_block_details Usage"},{"role":"assistant","content":"`PWN::Blockchain::ETH.get_block_details`: Supported Method Parameters\n\nPWN::Blockchain::ETH.get_block_details(\n\nheight: 'required - block height number',\ntoken: 'optional - API token for higher rate limits'\n\n)\n"}]}
|
450
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::ETH.get_latest_block Usage"},{"role":"assistant","content":"`PWN::Blockchain::ETH.get_latest_block`: Supported Method Parameters\n\nlatest_block = PWN::Blockchain::ETH.get_latest_block(\n\ntoken: 'optional - API token for higher rate limits'\n\n)\n"}]}
|
451
|
+
{"messages":[{"role":"user","content":"PWN::Blockchain::ETH.help Usage"},{"role":"assistant","content":"`PWN::Blockchain::ETH.help`: "}]}
|
441
452
|
{"messages":[{"role":"user","content":"PWN::FFI.help Usage"},{"role":"assistant","content":"`PWN::FFI.help`: "}]}
|
442
453
|
{"messages":[{"role":"user","content":"PWN::FFI::Stdio.authors Usage"},{"role":"assistant","content":"`PWN::FFI::Stdio.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
443
454
|
{"messages":[{"role":"user","content":"PWN::FFI::Stdio.help Usage"},{"role":"assistant","content":"`PWN::FFI::Stdio.help`: "}]}
|
@@ -1023,7 +1034,7 @@
|
|
1023
1034
|
{"messages":[{"role":"user","content":"PWN::Plugins::Vault.encrypt Usage"},{"role":"assistant","content":"`PWN::Plugins::Vault.encrypt`: Supported Method Parameters\n\nPWN::Plugins::Vault.encrypt(\n\nfile: 'required - file to encrypt',\nkey: 'required - key to decrypt',\niv: 'required - iv to decrypt'\n\n)\n"}]}
|
1024
1035
|
{"messages":[{"role":"user","content":"PWN::Plugins::Vault.file_encrypted? Usage"},{"role":"assistant","content":"`PWN::Plugins::Vault.file_encrypted?`: Supported Method Parameters\n\nPWN::Plugins::Vault.file_encrypted?(\n\nfile: 'required - file to check if encrypted'\n\n)\n"}]}
|
1025
1036
|
{"messages":[{"role":"user","content":"PWN::Plugins::Vault.help Usage"},{"role":"assistant","content":"`PWN::Plugins::Vault.help`: "}]}
|
1026
|
-
{"messages":[{"role":"user","content":"PWN::Plugins::Vault.refresh_config_for_repl Usage"},{"role":"assistant","content":"`PWN::Plugins::Vault.refresh_config_for_repl`: Supported Method Parameters\n\nPWN::Plugins::Vault.refresh_config_for_repl(\n\n yaml_config_path: 'required - full path to pwn.yaml file',\n pi: 'optional - Pry instance (default: Pry)',\n
|
1037
|
+
{"messages":[{"role":"user","content":"PWN::Plugins::Vault.refresh_config_for_repl Usage"},{"role":"assistant","content":"`PWN::Plugins::Vault.refresh_config_for_repl`: Supported Method Parameters\n\nPWN::Plugins::Vault.refresh_config_for_repl(\n\n yaml_config_path: 'required - full path to pwn.yaml file',\n pi: 'optional - Pry instance (default: Pry)',\n yaml_decryptor_path: 'optional - full path to decryption YAML file'\n)\n"}]}
|
1027
1038
|
{"messages":[{"role":"user","content":"PWN::Plugins::Vault.refresh_encryption_secrets Usage"},{"role":"assistant","content":"`PWN::Plugins::Vault.refresh_encryption_secrets`: Supported Method Parameters\n\nPWN::Plugins::Vault.refresh_encryption_secrets(\n\nfile: 'required - file to encrypt with new key and iv',\nkey: 'required - key to decrypt',\niv: 'required - iv to decrypt'\n\n)\n"}]}
|
1028
1039
|
{"messages":[{"role":"user","content":"PWN::Plugins::Voice.authors Usage"},{"role":"assistant","content":"`PWN::Plugins::Voice.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
1029
1040
|
{"messages":[{"role":"user","content":"PWN::Plugins::Voice.help Usage"},{"role":"assistant","content":"`PWN::Plugins::Voice.help`: "}]}
|
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.
|
4
|
+
version: 0.5.430
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0day Inc.
|
@@ -477,14 +477,14 @@ dependencies:
|
|
477
477
|
requirements:
|
478
478
|
- - '='
|
479
479
|
- !ruby/object:Gem::Version
|
480
|
-
version:
|
480
|
+
version: 2.0.0
|
481
481
|
type: :runtime
|
482
482
|
prerelease: false
|
483
483
|
version_requirements: !ruby/object:Gem::Requirement
|
484
484
|
requirements:
|
485
485
|
- - '='
|
486
486
|
- !ruby/object:Gem::Version
|
487
|
-
version:
|
487
|
+
version: 2.0.0
|
488
488
|
- !ruby/object:Gem::Dependency
|
489
489
|
name: mail
|
490
490
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1832,6 +1832,7 @@ files:
|
|
1832
1832
|
- lib/pwn/blockchain.rb
|
1833
1833
|
- lib/pwn/blockchain/btc.rb
|
1834
1834
|
- lib/pwn/blockchain/eth.rb
|
1835
|
+
- lib/pwn/config.rb
|
1835
1836
|
- lib/pwn/ffi.rb
|
1836
1837
|
- lib/pwn/ffi/stdio.rb
|
1837
1838
|
- lib/pwn/plugins.rb
|
@@ -2180,6 +2181,7 @@ files:
|
|
2180
2181
|
- spec/lib/pwn/blockchain/btc_spec.rb
|
2181
2182
|
- spec/lib/pwn/blockchain/eth_spec.rb
|
2182
2183
|
- spec/lib/pwn/blockchain_spec.rb
|
2184
|
+
- spec/lib/pwn/config_spec.rb
|
2183
2185
|
- spec/lib/pwn/ffi/stdio_spec.rb
|
2184
2186
|
- spec/lib/pwn/ffi_spec.rb
|
2185
2187
|
- spec/lib/pwn/plugins/android_spec.rb
|