pwn 0.5.431 → 0.5.433
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 +9 -9
- data/lib/pwn/ai/grok.rb +0 -7
- data/lib/pwn/ai/introspection.rb +80 -0
- data/lib/pwn/ai/ollama.rb +0 -7
- data/lib/pwn/ai/open_ai.rb +0 -7
- data/lib/pwn/ai.rb +1 -0
- data/lib/pwn/config.rb +56 -25
- data/lib/pwn/plugins/repl.rb +38 -42
- data/lib/pwn/reports/sast.rb +5 -47
- data/lib/pwn/version.rb +1 -1
- data/lib/pwn.rb +2 -2
- data/spec/lib/pwn/ai/introspection_spec.rb +15 -0
- data/spec/lib/pwn/config_spec.rb +10 -0
- data/third_party/pwn_rdoc.jsonl +2 -2
- 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: 387bbe4af26b617f25c04626d47edc3a6a939e7c377352a9e03e4036e61ff9b6
|
4
|
+
data.tar.gz: a498482eacaaf46d73f8af584fbfeda222f46089db1360f4dbb28fe83d4a198c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f656eb703bea4dc1bb679451d0b755c81007eddeda0c2a951f21a8f0bd093bad4edff86ebf17ccde1ec468f3f983c38aecbe6232ffc91448a28e8fa07b46d9b6
|
7
|
+
data.tar.gz: 5a70e26ea3e2c273e5d4a2edd62868799c9aa7dcfa4c8fb8e2f2cc43525234756ae020d63328fde508bf73940712eb828672d7f86bd29c46b3e2a809ce070527
|
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.433]: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.433]: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.433]: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('-YPATH', '--pwn-
|
14
|
-
opts[:
|
13
|
+
options.on('-YPATH', '--pwn-env=PATH', '<Optional - PWN YAML File>') do |p|
|
14
|
+
opts[:pwn_env_path] = p
|
15
15
|
end
|
16
16
|
|
17
|
-
options.on('-ZPATH', '--pwn-
|
18
|
-
opts[:
|
17
|
+
options.on('-ZPATH', '--pwn-dec=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
|
18
|
+
opts[:pwn_dec_path] = d
|
19
19
|
end
|
20
20
|
end.parse!
|
21
21
|
|
data/bin/pwn_sast
CHANGED
@@ -12,12 +12,12 @@ OptionParser.new do |options|
|
|
12
12
|
"
|
13
13
|
|
14
14
|
# TODO: HOW TO LOAD THE pwn.yaml CONFIGURATION FILE FOR EVERYTHING UNLESS OVERRIDDEN???
|
15
|
-
options.on('-YPATH', '--pwn-
|
16
|
-
opts[:
|
15
|
+
options.on('-YPATH', '--pwn-env=PATH', '<Optional - PWN YAML File>') do |p|
|
16
|
+
opts[:pwn_env_path] = p
|
17
17
|
end
|
18
18
|
|
19
|
-
options.on('-ZPATH', '--pwn-
|
20
|
-
opts[:
|
19
|
+
options.on('-ZPATH', '--pwn-dec=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
|
20
|
+
opts[:pwn_dec_path] = d
|
21
21
|
end
|
22
22
|
|
23
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|
|
@@ -57,12 +57,12 @@ end
|
|
57
57
|
begin
|
58
58
|
timestamp = Time.now.strftime('%Y-%m-%d_%H:%M:%S%z')
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
if
|
60
|
+
pwn_env_path = opts[:pwn_env_path]
|
61
|
+
pwn_dec_path = opts[:pwn_dec_path]
|
62
|
+
if pwn_env_path
|
63
63
|
PWN::Config.refresh(
|
64
|
-
|
65
|
-
|
64
|
+
pwn_env_path: pwn_env_path,
|
65
|
+
pwn_dec_path: pwn_dec_path
|
66
66
|
)
|
67
67
|
end
|
68
68
|
|
data/lib/pwn/ai/grok.rb
CHANGED
@@ -25,13 +25,6 @@ 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
|
-
|
35
28
|
http_method = if opts[:http_method].nil?
|
36
29
|
:get
|
37
30
|
else
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'tty-spinner'
|
6
|
+
|
7
|
+
module PWN
|
8
|
+
module AI
|
9
|
+
# This plugin interacts with PWN::Env's `ai` data structure
|
10
|
+
# when `PWN::Env[:ai][:introspection]` is set to `true`.
|
11
|
+
module Introspection
|
12
|
+
# Supported Method Parameters::
|
13
|
+
# response = PWN::AI::Introspection.reflect
|
14
|
+
|
15
|
+
public_class_method def self.reflect
|
16
|
+
engine = PWN::Env[:ai][:active].to_s.downcase.to_sym
|
17
|
+
base_uri = PWN::Env[:ai][engine][:base_uri]
|
18
|
+
model = PWN::Env[:ai][engine][:model]
|
19
|
+
key = PWN::Env[:ai][engine][:key]
|
20
|
+
system_role_content = PWN::Env[:ai][engine][:system_role_content]
|
21
|
+
temp = PWN::Env[:ai][engine][:temp]
|
22
|
+
|
23
|
+
case engine
|
24
|
+
when :grok
|
25
|
+
response = PWN::AI::Grok.chat(
|
26
|
+
base_uri: base_uri,
|
27
|
+
token: key,
|
28
|
+
model: model,
|
29
|
+
system_role_content: system_role_content,
|
30
|
+
temp: temp,
|
31
|
+
request: request.chomp,
|
32
|
+
spinner: false
|
33
|
+
)
|
34
|
+
when :ollama
|
35
|
+
response = PWN::AI::Ollama.chat(
|
36
|
+
base_uri: base_uri,
|
37
|
+
token: key,
|
38
|
+
model: model,
|
39
|
+
system_role_content: system_role_content,
|
40
|
+
temp: temp,
|
41
|
+
request: request.chomp,
|
42
|
+
spinner: false
|
43
|
+
)
|
44
|
+
when :openai
|
45
|
+
response = PWN::AI::OpenAI.chat(
|
46
|
+
base_uri: base_uri,
|
47
|
+
token: key,
|
48
|
+
model: model,
|
49
|
+
system_role_content: system_role_content,
|
50
|
+
temp: temp,
|
51
|
+
request: request.chomp,
|
52
|
+
spinner: false
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
response
|
57
|
+
rescue StandardError => e
|
58
|
+
raise e
|
59
|
+
end
|
60
|
+
|
61
|
+
# Author(s):: 0day Inc. <support@0dayinc.com>
|
62
|
+
|
63
|
+
public_class_method def self.authors
|
64
|
+
"AUTHOR(S):
|
65
|
+
0day Inc. <support@0dayinc.com>
|
66
|
+
"
|
67
|
+
end
|
68
|
+
|
69
|
+
# Display Usage for this Module
|
70
|
+
|
71
|
+
public_class_method def self.help
|
72
|
+
puts "USAGE:
|
73
|
+
#{self}.reflect
|
74
|
+
|
75
|
+
#{self}.authors
|
76
|
+
"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/pwn/ai/ollama.rb
CHANGED
@@ -27,13 +27,6 @@ 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
|
-
|
37
30
|
http_method = if opts[:http_method].nil?
|
38
31
|
:get
|
39
32
|
else
|
data/lib/pwn/ai/open_ai.rb
CHANGED
@@ -26,13 +26,6 @@ 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
|
-
|
36
29
|
http_method = if opts[:http_method].nil?
|
37
30
|
:get
|
38
31
|
else
|
data/lib/pwn/ai.rb
CHANGED
data/lib/pwn/config.rb
CHANGED
@@ -7,25 +7,25 @@ module PWN
|
|
7
7
|
# Used to manage PWN configuration settings within PWN drivers.
|
8
8
|
module Config
|
9
9
|
# Supported Method Parameters::
|
10
|
-
# PWN::Config.
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# PWN::Config.refresh_env(
|
11
|
+
# pwn_env_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml',
|
12
|
+
# pwn_dec_path: 'optional - Path to pwn.decryptor.yaml file. Defaults to ~/.pwn/pwn.decryptor.yaml'
|
13
13
|
# )
|
14
14
|
|
15
|
-
public_class_method def self.
|
16
|
-
|
17
|
-
FileUtils.mkdir_p(
|
15
|
+
public_class_method def self.refresh_env(opts = {})
|
16
|
+
pwn_env_root = "#{Dir.home}/.pwn"
|
17
|
+
FileUtils.mkdir_p(pwn_env_root)
|
18
18
|
|
19
|
-
|
20
|
-
return unless File.exist?(
|
19
|
+
pwn_env_path = opts[:pwn_env_path] ||= "#{pwn_env_root}/pwn.yaml"
|
20
|
+
return {} unless File.exist?(pwn_env_path)
|
21
21
|
|
22
|
-
is_encrypted = PWN::Plugins::Vault.file_encrypted?(file:
|
22
|
+
is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: pwn_env_path)
|
23
23
|
|
24
24
|
if is_encrypted
|
25
|
-
|
26
|
-
raise "PWN Decryptor (#{
|
25
|
+
pwn_dec_path = opts[:pwn_dec_path] ||= "#{pwn_env_root}/pwn.decryptor.yaml"
|
26
|
+
raise "PWN Decryptor (#{pwn_dec_path}) does not exist!" unless File.exist?(pwn_dec_path)
|
27
27
|
|
28
|
-
pwn_decryptor = YAML.load_file(
|
28
|
+
pwn_decryptor = YAML.load_file(pwn_dec_path, symbolize_names: true)
|
29
29
|
|
30
30
|
key = opts[:key] ||= pwn_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
|
31
31
|
key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
|
@@ -33,13 +33,13 @@ module PWN
|
|
33
33
|
iv = opts[:iv] ||= pwn_decryptor[:iv] ||= ENV.fetch('PWN_DECRYPTOR_IV')
|
34
34
|
iv = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption IV') if iv.nil?
|
35
35
|
|
36
|
-
|
37
|
-
file:
|
36
|
+
env = PWN::Plugins::Vault.dump(
|
37
|
+
file: pwn_env_path,
|
38
38
|
key: key,
|
39
39
|
iv: iv
|
40
40
|
)
|
41
41
|
else
|
42
|
-
|
42
|
+
env = YAML.load_file(pwn_env_path, symbolize_names: true)
|
43
43
|
end
|
44
44
|
|
45
45
|
valid_ai_engines = %i[
|
@@ -48,14 +48,22 @@ module PWN
|
|
48
48
|
ollama
|
49
49
|
]
|
50
50
|
|
51
|
-
engine =
|
52
|
-
raise "ERROR: Unsupported AI Engine: #{engine} in #{
|
51
|
+
engine = env[:ai][:active].to_s.downcase.to_sym
|
52
|
+
raise "ERROR: Unsupported AI Engine: #{engine} in #{pwn_env_path}. Supported AI Engines:\n#{valid_ai_engines.inspect}" unless valid_ai_engines.include?(engine)
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
key = env[:ai][engine][:key]
|
55
|
+
if key.nil?
|
56
|
+
key = PWN::Plugins::AuthenticationHelper.mask_password(
|
57
|
+
prompt: "#{engine} API Key"
|
58
|
+
)
|
59
|
+
env[:ai][engine][:key] = key
|
60
|
+
end
|
61
|
+
|
62
|
+
model = env[:ai][engine][:model]
|
63
|
+
system_role_content = env[:ai][engine][:system_role_content]
|
56
64
|
|
57
|
-
# Reset the ai response history on
|
58
|
-
|
65
|
+
# Reset the ai response history on env refresh
|
66
|
+
env[:ai][engine][:response_history] = {
|
59
67
|
id: '',
|
60
68
|
object: '',
|
61
69
|
model: model,
|
@@ -69,13 +77,36 @@ module PWN
|
|
69
77
|
}
|
70
78
|
|
71
79
|
# These two lines should be immutable for the session
|
72
|
-
|
73
|
-
|
80
|
+
env[:pwn_env_path] = pwn_env_path
|
81
|
+
env[:pwn_dec_path] = pwn_dec_path if is_encrypted
|
74
82
|
|
75
83
|
Pry.config.refresh = false if defined?(Pry)
|
76
84
|
|
77
|
-
PWN.send(:remove_const, :
|
78
|
-
PWN.const_set(:
|
85
|
+
PWN.send(:remove_const, :Env) if PWN.const_defined?(:Env)
|
86
|
+
PWN.const_set(:Env, env.freeze)
|
87
|
+
rescue StandardError => e
|
88
|
+
raise e
|
89
|
+
end
|
90
|
+
|
91
|
+
# Author(s):: 0day Inc. <support@0dayinc.com>
|
92
|
+
|
93
|
+
public_class_method def self.authors
|
94
|
+
"AUTHOR(S):
|
95
|
+
0day Inc. <support@0dayinc.com>
|
96
|
+
"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Display Usage for this Module
|
100
|
+
|
101
|
+
public_class_method def self.help
|
102
|
+
puts "USAGE:
|
103
|
+
#{self}.refresh_env(
|
104
|
+
pwn_env_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml',
|
105
|
+
pwn_dec_path: 'optional - Path to pwn.decryptor.yaml file. Defaults to ~/.pwn/pwn.decryptor.yaml'
|
106
|
+
)
|
107
|
+
|
108
|
+
#{self}.authors
|
109
|
+
"
|
79
110
|
end
|
80
111
|
end
|
81
112
|
end
|
data/lib/pwn/plugins/repl.rb
CHANGED
@@ -18,7 +18,7 @@ module PWN
|
|
18
18
|
mode = opts[:mode]
|
19
19
|
|
20
20
|
proc do |_target_self, _nest_level, pi|
|
21
|
-
|
21
|
+
PWN::Config.refresh_env(opts) if Pry.config.refresh
|
22
22
|
|
23
23
|
pi.config.pwn_repl_line += 1
|
24
24
|
line_pad = format(
|
@@ -34,8 +34,8 @@ module PWN
|
|
34
34
|
dchars = "\001\e[33m\002***\001\e[0m\002" if mode == :splat
|
35
35
|
|
36
36
|
if pi.config.pwn_asm
|
37
|
-
arch =
|
38
|
-
endian =
|
37
|
+
arch = PWN::Env[:asm][:arch] ||= PWN::Plugins::DetectOS.arch
|
38
|
+
endian = PWN::Env[:asm][:endian] ||= PWN::Plugins::DetectOS.endian
|
39
39
|
|
40
40
|
pi.config.prompt_name = "pwn.asm:#{arch}/#{endian}"
|
41
41
|
name = "\001\e[1m\002\001\e[37m\002#{pi.config.prompt_name}\001\e[0m\002"
|
@@ -44,10 +44,10 @@ module PWN
|
|
44
44
|
end
|
45
45
|
|
46
46
|
if pi.config.pwn_ai
|
47
|
-
engine =
|
48
|
-
model =
|
49
|
-
system_role_content =
|
50
|
-
temp =
|
47
|
+
engine = PWN::Env[:ai][:active].to_s.downcase.to_sym
|
48
|
+
model = PWN::Env[:ai][engine][:model]
|
49
|
+
system_role_content = PWN::Env[:ai][engine][:system_role_content]
|
50
|
+
temp = PWN::Env[:ai][engine][:temp]
|
51
51
|
pname = "pwn.ai:#{engine}"
|
52
52
|
pname = "pwn.ai:#{engine}/#{model}" if model
|
53
53
|
pname = "pwn.ai:#{engine}/#{model}.SPEAK" if pi.config.pwn_ai_speak
|
@@ -173,10 +173,10 @@ module PWN
|
|
173
173
|
|
174
174
|
reply = nil
|
175
175
|
response_history = nil
|
176
|
-
shared_chan =
|
176
|
+
shared_chan = PWN::Env[:irc][:shared_chan]
|
177
177
|
mem_chan = '#mem'
|
178
|
-
ai_agents =
|
179
|
-
ai_agents_arr =
|
178
|
+
ai_agents = PWN::Env[:irc][:ai_agent_nicks]
|
179
|
+
ai_agents_arr = PWN::Env[:irc][:ai_agent_nicks].keys
|
180
180
|
total_ai_agents = ai_agents_arr.length
|
181
181
|
mutex = Mutex.new
|
182
182
|
PWN::Plugins::ThreadPool.fill(
|
@@ -302,12 +302,12 @@ module PWN
|
|
302
302
|
next unless dm_agent == nick
|
303
303
|
|
304
304
|
response_history = ai_agents[dm_agent.to_sym][:response_history]
|
305
|
-
engine =
|
306
|
-
base_uri =
|
307
|
-
key =
|
308
|
-
temp =
|
309
|
-
model =
|
310
|
-
system_role_content =
|
305
|
+
engine = PWN::Env[:ai][:active].to_s.downcase.to_sym
|
306
|
+
base_uri = PWN::Env[:ai][engine][:base_uri]
|
307
|
+
key = PWN::Env[:ai][engine][:key] ||= ''
|
308
|
+
temp = PWN::Env[:ai][engine][:temp]
|
309
|
+
model = PWN::Env[:ai][engine][:model]
|
310
|
+
system_role_content = PWN::Env[:ai][engine][:system_role_content]
|
311
311
|
|
312
312
|
users_in_chan = PWN::Plugins::IRC.names(
|
313
313
|
irc_obj: irc_obj,
|
@@ -431,7 +431,7 @@ module PWN
|
|
431
431
|
|
432
432
|
# TODO: Use TLS for IRC Connections
|
433
433
|
# Use an IRC nCurses CLI Client
|
434
|
-
ui_nick =
|
434
|
+
ui_nick = PWN::Env[:irc][:ui_nick]
|
435
435
|
join_channels = ai_agents_arr.map { |ai_chan| "##{ai_chan}" }.join(',')
|
436
436
|
|
437
437
|
cmd0 = "/server add pwn #{host}/#{port} -notls"
|
@@ -460,24 +460,24 @@ module PWN
|
|
460
460
|
|
461
461
|
def process
|
462
462
|
pi = pry_instance
|
463
|
-
|
464
|
-
unless File.exist?(
|
465
|
-
puts "ERROR: pwn
|
463
|
+
pwn_env_path = PWN::Env[:pwn_env_path] ||= "#{Dir.home}/.pwn/pwn.yaml"
|
464
|
+
unless File.exist?(pwn_env_path)
|
465
|
+
puts "ERROR: pwn environment file not found: #{pwn_env_path}"
|
466
466
|
return
|
467
467
|
end
|
468
468
|
|
469
|
-
|
470
|
-
unless File.exist?(
|
471
|
-
puts "ERROR: pwn
|
469
|
+
pwn_dec_path = PWN::Env[:pwn_dec_path] ||= "#{Dir.home}/.pwn/pwn.decryptor.yaml"
|
470
|
+
unless File.exist?(pwn_dec_path)
|
471
|
+
puts "ERROR: pwn decryptor file not found: #{pwn_dec_path}"
|
472
472
|
return
|
473
473
|
end
|
474
474
|
|
475
|
-
decryptor = YAML.load_file(
|
475
|
+
decryptor = YAML.load_file(pwn_dec_path, symbolize_names: true)
|
476
476
|
key = decryptor[:key]
|
477
477
|
iv = decryptor[:iv]
|
478
478
|
|
479
479
|
PWN::Plugins::Vault.edit(
|
480
|
-
file:
|
480
|
+
file: pwn_env_path,
|
481
481
|
key: key,
|
482
482
|
iv: iv
|
483
483
|
)
|
@@ -530,20 +530,16 @@ module PWN
|
|
530
530
|
# Define REPL Hooks
|
531
531
|
# Welcome Banner Hook
|
532
532
|
Pry.config.hooks.add_hook(:before_session, :welcome) do |output, _binding, _pi|
|
533
|
+
PWN::Config.refresh_env(opts)
|
533
534
|
output.puts PWN::Banner.welcome
|
534
535
|
end
|
535
536
|
|
536
|
-
# Initialize pwn.yaml Configuration using :before_session Hook
|
537
|
-
Pry.config.hooks.add_hook(:before_session, :init_opts) do |_output, _binding, pi|
|
538
|
-
pi.config.pwn = PWN::Config.refresh(opts)
|
539
|
-
end
|
540
|
-
|
541
537
|
Pry.config.hooks.add_hook(:after_read, :pwn_asm_hook) do |request, pi|
|
542
538
|
if pi.config.pwn_asm && !request.chomp.empty?
|
543
539
|
request = pi.input.line_buffer
|
544
540
|
|
545
|
-
arch =
|
546
|
-
endian =
|
541
|
+
arch = PWN::Env[:asm][:arch]
|
542
|
+
endian = PWN::Env[:asm][:endian]
|
547
543
|
|
548
544
|
# Analyze request to determine if it should be processed as opcodes or asm.
|
549
545
|
straight_hex = /^[a-fA-F0-9\s]+$/
|
@@ -579,14 +575,14 @@ module PWN
|
|
579
575
|
if pi.config.pwn_ai && !request.chomp.empty?
|
580
576
|
request = pi.input.line_buffer.to_s
|
581
577
|
debug = pi.config.pwn_ai_debug
|
582
|
-
engine =
|
583
|
-
base_uri =
|
584
|
-
key =
|
585
|
-
response_history =
|
578
|
+
engine = PWN::Env[:ai][:active].to_s.downcase.to_sym
|
579
|
+
base_uri = PWN::Env[:ai][engine][:base_uri]
|
580
|
+
key = PWN::Env[:ai][engine][:key] ||= ''
|
581
|
+
response_history = PWN::Env[:ai][engine][:response_history]
|
586
582
|
speak_answer = pi.config.pwn_ai_speak
|
587
|
-
model =
|
588
|
-
system_role_content =
|
589
|
-
temp =
|
583
|
+
model = PWN::Env[:ai][engine][:model]
|
584
|
+
system_role_content = PWN::Env[:ai][engine][:system_role_content]
|
585
|
+
temp = PWN::Env[:ai][engine][:temp]
|
590
586
|
|
591
587
|
case engine
|
592
588
|
when :grok
|
@@ -655,7 +651,7 @@ module PWN
|
|
655
651
|
pp response_history
|
656
652
|
puts "\nresponse_history[:choices] Length: #{response_history[:choices].length}\n" unless response_history.nil?
|
657
653
|
end
|
658
|
-
|
654
|
+
PWN::Env[:ai][engine][:response_history] = response_history
|
659
655
|
end
|
660
656
|
end
|
661
657
|
rescue StandardError => e
|
@@ -670,8 +666,8 @@ module PWN
|
|
670
666
|
public_class_method def self.start(opts = {})
|
671
667
|
# Monkey Patch Pry, add commands, && hooks
|
672
668
|
PWN::Plugins::MonkeyPatch.pry
|
673
|
-
|
674
|
-
Pry.config.history_file = "#{
|
669
|
+
pwn_env_root = "#{Dir.home}/.pwn"
|
670
|
+
Pry.config.history_file = "#{pwn_env_root}/pwn_history"
|
675
671
|
|
676
672
|
add_commands
|
677
673
|
add_hooks(opts)
|
data/lib/pwn/reports/sast.rb
CHANGED
@@ -25,17 +25,8 @@ module PWN
|
|
25
25
|
}
|
26
26
|
report_name = opts[:report_name] ||= File.basename(Dir.pwd)
|
27
27
|
|
28
|
-
ai_instrospection = PWN::
|
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]
|
36
|
-
|
37
|
-
puts "Analyzing source code using AI engine: #{engine}\nModel: #{model}\nSystem Role Content: #{system_role_content}\nTemperature: #{temp}"
|
38
|
-
end
|
28
|
+
ai_instrospection = PWN::Env[:ai][:introspection]
|
29
|
+
puts "Analyzing source code using AI engine: #{engine}\nModel: #{model}\nSystem Role Content: #{system_role_content}\nTemperature: #{temp}" if ai_instrospection
|
39
30
|
|
40
31
|
# Calculate percentage of AI analysis based on the number of entries
|
41
32
|
total_entries = results_hash[:data].sum { |entry| entry[:line_no_and_contents].size }
|
@@ -63,44 +54,11 @@ module PWN
|
|
63
54
|
line: line_no,
|
64
55
|
source_code_snippet: source_code_snippet
|
65
56
|
}.to_json
|
66
|
-
response = nil
|
67
57
|
author = src_detail[:author].to_s.scrub.chomp.strip
|
68
58
|
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
102
|
-
end
|
103
|
-
|
59
|
+
# TODO: move PWN::AI::Introspection.reflect into each PWN::SAST::* module
|
60
|
+
# This will drastically speed up the overall SAST analysis process
|
61
|
+
response = PWN::AI::Introspection.reflect if ai_instrospection
|
104
62
|
ai_analysis = nil
|
105
63
|
if response.is_a?(Hash)
|
106
64
|
ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
|
data/lib/pwn/version.rb
CHANGED
data/lib/pwn.rb
CHANGED
@@ -26,8 +26,8 @@ module PWN
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# Initialize PWN configuration file
|
29
|
-
# PWN::
|
30
|
-
PWN::Config.
|
29
|
+
# PWN::Env is the constant that stores the configuration data
|
30
|
+
PWN::Config.refresh_env
|
31
31
|
rescue StandardError => e
|
32
32
|
puts e.backtrace
|
33
33
|
raise e
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe PWN::AI::Introspection do
|
6
|
+
it 'should display information for authors' do
|
7
|
+
authors_response = PWN::AI::Introspection
|
8
|
+
expect(authors_response).to respond_to :authors
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should display information for existing help method' do
|
12
|
+
help_response = PWN::AI::Introspection
|
13
|
+
expect(help_response).to respond_to :help
|
14
|
+
end
|
15
|
+
end
|
data/spec/lib/pwn/config_spec.rb
CHANGED
@@ -7,4 +7,14 @@ describe PWN::Config do
|
|
7
7
|
config_response = PWN::Config.refresh
|
8
8
|
expect(config_response).not_to be_nil
|
9
9
|
end
|
10
|
+
|
11
|
+
it 'should display information for authors' do
|
12
|
+
authors_response = PWN::Config
|
13
|
+
expect(authors_response).to respond_to :authors
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should display information for existing help method' do
|
17
|
+
help_response = PWN::Config
|
18
|
+
expect(help_response).to respond_to :help
|
19
|
+
end
|
10
20
|
end
|
data/third_party/pwn_rdoc.jsonl
CHANGED
@@ -449,6 +449,7 @@
|
|
449
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
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
451
|
{"messages":[{"role":"user","content":"PWN::Blockchain::ETH.help Usage"},{"role":"assistant","content":"`PWN::Blockchain::ETH.help`: "}]}
|
452
|
+
{"messages":[{"role":"user","content":"PWN::Config.refresh Usage"},{"role":"assistant","content":"`PWN::Config.refresh`: Supported Method Parameters\n\nPWN::Config.refresh(\n\npwn_config_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml',\npwn_decryptor_path: 'optional - Path to pwn.decryptor.yaml file. Defaults to ~/.pwn/pwn.decryptor.yaml'\n\n)\n"}]}
|
452
453
|
{"messages":[{"role":"user","content":"PWN::FFI.help Usage"},{"role":"assistant","content":"`PWN::FFI.help`: "}]}
|
453
454
|
{"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"}]}
|
454
455
|
{"messages":[{"role":"user","content":"PWN::FFI::Stdio.help Usage"},{"role":"assistant","content":"`PWN::FFI::Stdio.help`: "}]}
|
@@ -1034,7 +1035,6 @@
|
|
1034
1035
|
{"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"}]}
|
1035
1036
|
{"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"}]}
|
1036
1037
|
{"messages":[{"role":"user","content":"PWN::Plugins::Vault.help Usage"},{"role":"assistant","content":"`PWN::Plugins::Vault.help`: "}]}
|
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"}]}
|
1038
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"}]}
|
1039
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"}]}
|
1040
1040
|
{"messages":[{"role":"user","content":"PWN::Plugins::Voice.help Usage"},{"role":"assistant","content":"`PWN::Plugins::Voice.help`: "}]}
|
@@ -1081,7 +1081,7 @@
|
|
1081
1081
|
{"messages":[{"role":"user","content":"PWN::Reports::Phone.generate Usage"},{"role":"assistant","content":"`PWN::Reports::Phone.generate`: Supported Method Parameters\n\nPWN::Reports::Phone.generate(\n\ndir_path: dir_path,\nresults_hash: results_hash\n\n)\n"}]}
|
1082
1082
|
{"messages":[{"role":"user","content":"PWN::Reports::Phone.help Usage"},{"role":"assistant","content":"`PWN::Reports::Phone.help`: "}]}
|
1083
1083
|
{"messages":[{"role":"user","content":"PWN::Reports::SAST.authors Usage"},{"role":"assistant","content":"`PWN::Reports::SAST.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
1084
|
-
{"messages":[{"role":"user","content":"PWN::Reports::SAST.generate Usage"},{"role":"assistant","content":"`PWN::Reports::SAST.generate`: Supported Method Parameters\n\nPWN::Reports::SAST.generate(\n\ndir_path: 'optional - Directory path to save the report (defaults to .)',\nresults_hash: 'optional - Hash containing the results of the SAST analysis (defaults to empty hash structure)',\nreport_name: 'optional - Name of the report file (defaults to current directory name)'
|
1084
|
+
{"messages":[{"role":"user","content":"PWN::Reports::SAST.generate Usage"},{"role":"assistant","content":"`PWN::Reports::SAST.generate`: Supported Method Parameters\n\nPWN::Reports::SAST.generate(\n\ndir_path: 'optional - Directory path to save the report (defaults to .)',\nresults_hash: 'optional - Hash containing the results of the SAST analysis (defaults to empty hash structure)',\nreport_name: 'optional - Name of the report file (defaults to current directory name)'\n\n)\n"}]}
|
1085
1085
|
{"messages":[{"role":"user","content":"PWN::Reports::SAST.help Usage"},{"role":"assistant","content":"`PWN::Reports::SAST.help`: "}]}
|
1086
1086
|
{"messages":[{"role":"user","content":"PWN::Reports::URIBuster.authors Usage"},{"role":"assistant","content":"`PWN::Reports::URIBuster.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
1087
1087
|
{"messages":[{"role":"user","content":"PWN::Reports::URIBuster.generate Usage"},{"role":"assistant","content":"`PWN::Reports::URIBuster.generate`: Supported Method Parameters\n\nPWN::Reports::URIBuster.generate(\n\ndir_path: dir_path,\nresults_hash: results_hash\n\n)\n"}]}
|
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.433
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0day Inc.
|
@@ -841,14 +841,14 @@ dependencies:
|
|
841
841
|
requirements:
|
842
842
|
- - '='
|
843
843
|
- !ruby/object:Gem::Version
|
844
|
-
version: 6.
|
844
|
+
version: 6.15.0
|
845
845
|
type: :development
|
846
846
|
prerelease: false
|
847
847
|
version_requirements: !ruby/object:Gem::Requirement
|
848
848
|
requirements:
|
849
849
|
- - '='
|
850
850
|
- !ruby/object:Gem::Version
|
851
|
-
version: 6.
|
851
|
+
version: 6.15.0
|
852
852
|
- !ruby/object:Gem::Dependency
|
853
853
|
name: rest-client
|
854
854
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1720,6 +1720,7 @@ files:
|
|
1720
1720
|
- lib/pwn.rb
|
1721
1721
|
- lib/pwn/ai.rb
|
1722
1722
|
- lib/pwn/ai/grok.rb
|
1723
|
+
- lib/pwn/ai/introspection.rb
|
1723
1724
|
- lib/pwn/ai/ollama.rb
|
1724
1725
|
- lib/pwn/ai/open_ai.rb
|
1725
1726
|
- lib/pwn/aws.rb
|
@@ -2068,6 +2069,7 @@ files:
|
|
2068
2069
|
- pwn.gemspec
|
2069
2070
|
- reinstall_pwn_gemset.sh
|
2070
2071
|
- spec/lib/pwn/ai/grok_spec.rb
|
2072
|
+
- spec/lib/pwn/ai/introspection_spec.rb
|
2071
2073
|
- spec/lib/pwn/ai/ollama_spec.rb
|
2072
2074
|
- spec/lib/pwn/ai/open_ai_spec.rb
|
2073
2075
|
- spec/lib/pwn/ai_spec.rb
|