pwn 0.5.434 → 0.5.436
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/README.md +3 -3
- data/lib/pwn/ai/introspection.rb +15 -3
- data/lib/pwn/config.rb +102 -8
- data/lib/pwn/plugins/repl.rb +2 -2
- data/lib/pwn/plugins/vault.rb +15 -6
- data/lib/pwn/reports/sast.rb +14 -8
- data/lib/pwn/version.rb +1 -1
- data/lib/pwn.rb +3 -1
- data/spec/lib/pwn/config_spec.rb +0 -5
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b0b70877101aefea31cdfd2b5eeb0ad3828273814199faf10e2c52fe35a6455
|
4
|
+
data.tar.gz: ad68a9d8e4a114096a062812cedf20813d34d6bc91f210884b54ac838ed6219b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b4721af1d836061595b1c295100927d2824c19e68ce0f17edec6dd07e707cbf5f01dcc7ca0d697803547b2ecc64a2b527936a7e5f86d7d4ba2f3d44e6ada0e3
|
7
|
+
data.tar.gz: f0eea79fb719f06556c8b6260181c5dd25067cba7c4e8d800bc3c543b61e05a45907a22add4e73d6b63b3db04771c31e90793344e8d9f3d1da49f0ce2bbd4ac8
|
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.436]: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.436]: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.436]: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/lib/pwn/ai/introspection.rb
CHANGED
@@ -10,10 +10,20 @@ module PWN
|
|
10
10
|
# when `PWN::Env[:ai][:introspection]` is set to `true`.
|
11
11
|
module Introspection
|
12
12
|
# Supported Method Parameters::
|
13
|
-
# response = PWN::AI::Introspection.reflect
|
13
|
+
# response = PWN::AI::Introspection.reflect(
|
14
|
+
# request: 'required - String - What you want the AI to reflect on'
|
15
|
+
# )
|
14
16
|
|
15
|
-
public_class_method def self.reflect
|
17
|
+
public_class_method def self.reflect(opts = {})
|
18
|
+
request = opts[:request]
|
19
|
+
raise 'ERROR: request must be provided' if request.nil?
|
20
|
+
|
21
|
+
response = nil
|
22
|
+
|
23
|
+
valid_ai_engines = PWN::AI.help.reject { |e| e.downcase == :introspection }.map(&:downcase)
|
16
24
|
engine = PWN::Env[:ai][:active].to_s.downcase.to_sym
|
25
|
+
raise "ERROR: Unsupported AI engine. Supported engines are: #{valid_ai_engines}" unless valid_ai_engines.include?(engine)
|
26
|
+
|
17
27
|
base_uri = PWN::Env[:ai][engine][:base_uri]
|
18
28
|
model = PWN::Env[:ai][engine][:model]
|
19
29
|
key = PWN::Env[:ai][engine][:key]
|
@@ -70,7 +80,9 @@ module PWN
|
|
70
80
|
|
71
81
|
public_class_method def self.help
|
72
82
|
puts "USAGE:
|
73
|
-
#{self}.reflect
|
83
|
+
#{self}.reflect(
|
84
|
+
request: 'required - String - What you want the AI to reflect on'
|
85
|
+
)
|
74
86
|
|
75
87
|
#{self}.authors
|
76
88
|
"
|
data/lib/pwn/config.rb
CHANGED
@@ -6,6 +6,101 @@ require 'yaml'
|
|
6
6
|
module PWN
|
7
7
|
# Used to manage PWN configuration settings within PWN drivers.
|
8
8
|
module Config
|
9
|
+
# Supported Method Parameters::
|
10
|
+
# env = PWN::Config.minimal_env
|
11
|
+
public_class_method def self.minimal_env(opts = {})
|
12
|
+
pwn_env_path = opts[:pwn_env_path]
|
13
|
+
pwn_dec_path = "#{File.dirname(pwn_env_path)}/pwn.decryptor.yaml"
|
14
|
+
|
15
|
+
puts "
|
16
|
+
[*] NOTICE:
|
17
|
+
1. Writing minimal PWN::Env to:
|
18
|
+
#{pwn_env_path}
|
19
|
+
2. Your decryptor file will be written to:
|
20
|
+
#{pwn_dec_path}
|
21
|
+
3. Use the pwn-vault command in the pwn prototyping driver to update:
|
22
|
+
#{pwn_env_path}
|
23
|
+
4. For optimal security, it's recommended to move:
|
24
|
+
#{pwn_dec_path}
|
25
|
+
to a secure location and use the --pwn-dec parameter for PWN drivers.
|
26
|
+
"
|
27
|
+
env = {
|
28
|
+
ai: {
|
29
|
+
active: 'grok',
|
30
|
+
introspection: false,
|
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
|
+
},
|
53
|
+
asm: { arch: PWN::Plugins::DetectOS.arch, endian: PWN::Plugins::DetectOS.endian },
|
54
|
+
irc: {
|
55
|
+
ui_nick: '_human_',
|
56
|
+
shared_chan: '#pwn',
|
57
|
+
ai_agent_nicks: {
|
58
|
+
browser: {
|
59
|
+
pwn_rb: '/opt/pwn/lib/pwn/plugins/transparent_browser.rb',
|
60
|
+
system_role_content: 'You are a browser. You are a web browser that can be controlled by a human or AI agent'
|
61
|
+
},
|
62
|
+
nimjeh: {
|
63
|
+
pwn_rb: '',
|
64
|
+
system_role_content: 'You are a sarcastic hacker. You find software zero day vulnerabilities. This involves analyzing source code, race conditions, application binaries, and network protocols from an offensive security perspective.'
|
65
|
+
},
|
66
|
+
nmap: {
|
67
|
+
pwn_rb: '/opt/pwn/lib/pwn/plugins/nmap_it.rb',
|
68
|
+
system_role_content: 'You are a network scanner. You are a network scanner that can be controlled by a human or AI agent'
|
69
|
+
},
|
70
|
+
shodan: {
|
71
|
+
pwn_rb: '/opt/pwn/lib/pwn/plugins/shodan.rb',
|
72
|
+
system_role_content: 'You are a passive reconnaissance agent. You are a passive reconnaissance agent that can be controlled by a human or AI agent'
|
73
|
+
}
|
74
|
+
}
|
75
|
+
},
|
76
|
+
hunter: { api_key: 'hunter.how API Key' },
|
77
|
+
meshtastic: {
|
78
|
+
psks: {
|
79
|
+
LongFast: 'AQ==',
|
80
|
+
PWN: 'required - PSK for pwn channel'
|
81
|
+
}
|
82
|
+
},
|
83
|
+
shodan: { api_key: 'SHODAN API Key' }
|
84
|
+
}
|
85
|
+
# Remove beginning colon from key names
|
86
|
+
yaml_env = YAML.dump(env).gsub(/^(\s*):/, '\1')
|
87
|
+
File.write(pwn_env_path, yaml_env)
|
88
|
+
|
89
|
+
env[:pwn_env_path] = pwn_env_path
|
90
|
+
env[:pwn_dec_path] = pwn_dec_path
|
91
|
+
|
92
|
+
PWN::Plugins::Vault.create(
|
93
|
+
file: pwn_env_path,
|
94
|
+
decryptor_file: pwn_dec_path
|
95
|
+
)
|
96
|
+
|
97
|
+
Pry.config.refresh_pwn_env = false if defined?(Pry)
|
98
|
+
PWN.send(:remove_const, :Env) if PWN.const_defined?(:Env)
|
99
|
+
PWN.const_set(:Env, env.freeze)
|
100
|
+
rescue StandardError => e
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
|
9
104
|
# Supported Method Parameters::
|
10
105
|
# PWN::Config.refresh_env(
|
11
106
|
# pwn_env_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml',
|
@@ -17,7 +112,7 @@ module PWN
|
|
17
112
|
FileUtils.mkdir_p(pwn_env_root)
|
18
113
|
|
19
114
|
pwn_env_path = opts[:pwn_env_path] ||= "#{pwn_env_root}/pwn.yaml"
|
20
|
-
return
|
115
|
+
return minimal_env(pwn_env_path: pwn_env_path) unless File.exist?(pwn_env_path)
|
21
116
|
|
22
117
|
is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: pwn_env_path)
|
23
118
|
|
@@ -42,11 +137,7 @@ module PWN
|
|
42
137
|
env = YAML.load_file(pwn_env_path, symbolize_names: true)
|
43
138
|
end
|
44
139
|
|
45
|
-
valid_ai_engines =
|
46
|
-
grok
|
47
|
-
openai
|
48
|
-
ollama
|
49
|
-
]
|
140
|
+
valid_ai_engines = PWN::AI.help.reject { |e| e.downcase == :introspection }.map(&:downcase)
|
50
141
|
|
51
142
|
engine = env[:ai][:active].to_s.downcase.to_sym
|
52
143
|
raise "ERROR: Unsupported AI Engine: #{engine} in #{pwn_env_path}. Supported AI Engines:\n#{valid_ai_engines.inspect}" unless valid_ai_engines.include?(engine)
|
@@ -80,8 +171,7 @@ module PWN
|
|
80
171
|
env[:pwn_env_path] = pwn_env_path
|
81
172
|
env[:pwn_dec_path] = pwn_dec_path if is_encrypted
|
82
173
|
|
83
|
-
Pry.config.
|
84
|
-
|
174
|
+
Pry.config.refresh_pwn_env = false if defined?(Pry)
|
85
175
|
PWN.send(:remove_const, :Env) if PWN.const_defined?(:Env)
|
86
176
|
PWN.const_set(:Env, env.freeze)
|
87
177
|
rescue StandardError => e
|
@@ -100,6 +190,10 @@ module PWN
|
|
100
190
|
|
101
191
|
public_class_method def self.help
|
102
192
|
puts "USAGE:
|
193
|
+
#{self}.minimal_env(
|
194
|
+
pwn_env_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml'
|
195
|
+
)
|
196
|
+
|
103
197
|
#{self}.refresh_env(
|
104
198
|
pwn_env_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml',
|
105
199
|
pwn_dec_path: 'optional - Path to pwn.decryptor.yaml file. Defaults to ~/.pwn/pwn.decryptor.yaml'
|
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
|
-
PWN::Config.refresh_env(opts) if Pry.config.
|
21
|
+
PWN::Config.refresh_env(opts) if Pry.config.refresh_pwn_env
|
22
22
|
|
23
23
|
pi.config.pwn_repl_line += 1
|
24
24
|
line_pad = format(
|
@@ -530,8 +530,8 @@ 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)
|
534
533
|
output.puts PWN::Banner.welcome
|
534
|
+
PWN::Config.refresh_env(opts)
|
535
535
|
end
|
536
536
|
|
537
537
|
Pry.config.hooks.add_hook(:after_read, :pwn_asm_hook) do |request, pi|
|
data/lib/pwn/plugins/vault.rb
CHANGED
@@ -37,19 +37,27 @@ module PWN
|
|
37
37
|
|
38
38
|
# Supported Method Parameters::
|
39
39
|
# PWN::Plugins::Vault.create(
|
40
|
-
# file: 'required - encrypted file to create'
|
40
|
+
# file: 'required - encrypted file to create',
|
41
|
+
# decryptor_file: 'optional - file to save the key && iv values'
|
41
42
|
# )
|
42
43
|
|
43
44
|
public_class_method def self.create(opts = {})
|
44
45
|
file = opts[:file].to_s.scrub if File.exist?(opts[:file].to_s.scrub)
|
46
|
+
decryptor_file = opts[:decryptor_file]
|
45
47
|
|
46
48
|
cipher = OpenSSL::Cipher.new('aes-256-cbc')
|
47
49
|
key = Base64.strict_encode64(cipher.random_key)
|
48
50
|
iv = Base64.strict_encode64(cipher.random_iv)
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
if decryptor_file
|
53
|
+
decryptor_hash = { key: key, iv: iv }
|
54
|
+
yaml_decryptor = YAML.dump(decryptor_hash).gsub(/^(\s*):/, '\1')
|
55
|
+
File.write(decryptor_file, yaml_decryptor)
|
56
|
+
else
|
57
|
+
puts 'Please store the Key && IV in a secure location as they are required for decryption.'
|
58
|
+
puts "Key: #{key}"
|
59
|
+
puts "IV: #{iv}"
|
60
|
+
end
|
53
61
|
|
54
62
|
encrypt(
|
55
63
|
file: file,
|
@@ -173,7 +181,7 @@ module PWN
|
|
173
181
|
system(relative_editor, file)
|
174
182
|
|
175
183
|
# If the Pry object exists, set refresh_config to true
|
176
|
-
Pry.config.
|
184
|
+
Pry.config.refresh_pwn_env = true if defined?(Pry)
|
177
185
|
|
178
186
|
encrypt(
|
179
187
|
file: file,
|
@@ -253,7 +261,8 @@ module PWN
|
|
253
261
|
)
|
254
262
|
|
255
263
|
#{self}.create(
|
256
|
-
file: 'required - file to encrypt'
|
264
|
+
file: 'required - file to encrypt',
|
265
|
+
decryptor_file: 'optional - file to save the key && iv values'
|
257
266
|
)
|
258
267
|
|
259
268
|
#{self}.decrypt(
|
data/lib/pwn/reports/sast.rb
CHANGED
@@ -49,16 +49,22 @@ module PWN
|
|
49
49
|
percent_complete = (entry_count.to_f / total_entries * 100).round(2)
|
50
50
|
line_no = src_detail[:line_no]
|
51
51
|
source_code_snippet = src_detail[:contents]
|
52
|
-
request = {
|
53
|
-
scm_uri: "#{git_repo_root_uri}/#{filename}",
|
54
|
-
line: line_no,
|
55
|
-
source_code_snippet: source_code_snippet
|
56
|
-
}.to_json
|
57
52
|
author = src_detail[:author].to_s.scrub.chomp.strip
|
58
53
|
|
59
|
-
# TODO:
|
60
|
-
#
|
61
|
-
|
54
|
+
# TODO: >>>
|
55
|
+
# 1. Move PWN::AI::Introspection.reflect into each PWN::SAST::* module
|
56
|
+
# This will drastically speed up the overall SAST analysis process
|
57
|
+
# 2. Have PWN::AI::Introspection.reflect assess test case effectiveness
|
58
|
+
response = nil
|
59
|
+
if ai_instrospection
|
60
|
+
request = {
|
61
|
+
scm_uri: "#{git_repo_root_uri}/#{filename}",
|
62
|
+
line: line_no,
|
63
|
+
source_code_snippet: source_code_snippet
|
64
|
+
}.to_json
|
65
|
+
response = PWN::AI::Introspection.reflect(request: request)
|
66
|
+
end
|
67
|
+
|
62
68
|
ai_analysis = nil
|
63
69
|
if response.is_a?(Hash)
|
64
70
|
ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
|
data/lib/pwn/version.rb
CHANGED
data/lib/pwn.rb
CHANGED
@@ -27,7 +27,9 @@ module PWN
|
|
27
27
|
|
28
28
|
# Initialize PWN configuration file
|
29
29
|
# PWN::Env is the constant that stores the configuration data
|
30
|
-
|
30
|
+
# Only call this if the program name is not pwn
|
31
|
+
driver = File.basename($PROGRAM_NAME)
|
32
|
+
PWN::Config.refresh_env unless driver == 'pwn'
|
31
33
|
rescue StandardError => e
|
32
34
|
puts e.backtrace
|
33
35
|
raise e
|
data/spec/lib/pwn/config_spec.rb
CHANGED
@@ -3,11 +3,6 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe PWN::Config do
|
6
|
-
it 'should return data for refresh method' do
|
7
|
-
config_response = PWN::Config.refresh_env
|
8
|
-
expect(config_response).not_to be_nil
|
9
|
-
end
|
10
|
-
|
11
6
|
it 'should display information for authors' do
|
12
7
|
authors_response = PWN::Config
|
13
8
|
expect(authors_response).to respond_to :authors
|