pwn 0.5.425 → 0.5.427
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 +2 -10
- data/lib/pwn/ai.rb +1 -1
- data/lib/pwn/blockchain/btc.rb +160 -0
- data/lib/pwn/blockchain/eth.rb +160 -0
- data/lib/pwn/blockchain.rb +17 -0
- data/lib/pwn/plugins/repl.rb +54 -56
- data/lib/pwn/plugins/vault.rb +34 -44
- data/lib/pwn/version.rb +1 -1
- data/lib/pwn.rb +1 -0
- data/spec/lib/pwn/blockchain/btc_spec.rb +15 -0
- data/spec/lib/pwn/blockchain/eth_spec.rb +15 -0
- data/spec/lib/pwn/blockchain_spec.rb +10 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac10751175e251ad205dd5e3c4cc6b1eeb12f45717b7099a018cb71b3628fa7f
|
4
|
+
data.tar.gz: 2535096c15a6baf77f987e7c79b12655a8191b895bc0a1907995fd0cae98159a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d749319613654cbbc475657a6901e4cdad824b72a90889d4612bc89e88df188277941cdb41df44078ef500d549f5bc5de014bdacf141d37c63b82c7c1e14d65
|
7
|
+
data.tar.gz: b7538e5a12b5512f48ebf0976eb2c14009d7c97730eefc8271b77a0b7e53cbbe1b777420318c4bae032d4094e8ff495debc6a00f27ae31799fa966a213737cd3
|
data/Gemfile
CHANGED
@@ -90,7 +90,7 @@ gem 'ruby-nmap', '1.0.3'
|
|
90
90
|
gem 'ruby-saml', '1.18.1'
|
91
91
|
gem 'rvm', '1.11.3.9'
|
92
92
|
gem 'savon', '2.15.1'
|
93
|
-
gem 'selenium-devtools', '0.
|
93
|
+
gem 'selenium-devtools', '0.140.0'
|
94
94
|
# gem 'serialport', '1.3.2'
|
95
95
|
# gem 'sinatra', '4.0.0'
|
96
96
|
gem 'slack-ruby-client', '3.0.0'
|
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.427]: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.427]: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.427]: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
@@ -14,16 +14,8 @@ OptionParser.new do |options|
|
|
14
14
|
opts[:yaml_config_path] = p
|
15
15
|
end
|
16
16
|
|
17
|
-
options.on('-dPATH', '--decryptor=PATH', '<Optional - File
|
18
|
-
opts[:
|
19
|
-
end
|
20
|
-
|
21
|
-
options.on('-kKEY', '--decryption-key=KEY', '<Optional - Decryption Key>') do |k|
|
22
|
-
opts[:key] = k
|
23
|
-
end
|
24
|
-
|
25
|
-
options.on('-iIV', '--decryption-iv=PATH', '<Optional - Decryption IV>') do |i|
|
26
|
-
opts[:iv] = i
|
17
|
+
options.on('-dPATH', '--yaml-decryptor=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
|
18
|
+
opts[:yaml_decryptor_path] = d
|
27
19
|
end
|
28
20
|
end.parse!
|
29
21
|
|
data/lib/pwn/ai.rb
CHANGED
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'tty-spinner'
|
6
|
+
|
7
|
+
module PWN
|
8
|
+
module Blockchain
|
9
|
+
# This plugin interacts with BitCoin's Blockchain API.
|
10
|
+
module BTC
|
11
|
+
# Supported Method Parameters::
|
12
|
+
# btc_rest_call(
|
13
|
+
# http_method: 'optional HTTP method (defaults to GET)
|
14
|
+
# rest_call: 'required rest call to make per the schema',
|
15
|
+
# params: 'optional params passed in the URI or HTTP Headers',
|
16
|
+
# http_body: 'optional HTTP body sent in HTTP methods that support it e.g. POST',
|
17
|
+
# timeout: 'optional timeout in seconds (defaults to 180)',
|
18
|
+
# spinner: 'optional - display spinner (defaults to false)'
|
19
|
+
# )
|
20
|
+
|
21
|
+
private_class_method def self.btc_rest_call(opts = {})
|
22
|
+
http_method = if opts[:http_method].nil?
|
23
|
+
:get
|
24
|
+
else
|
25
|
+
opts[:http_method].to_s.scrub.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
base_uri = 'https://api.blockcypher.com/v1/btc/'
|
29
|
+
rest_call = opts[:rest_call].to_s.scrub
|
30
|
+
params = opts[:params]
|
31
|
+
headers = { content_type: 'application/json; charset=UTF-8' }
|
32
|
+
|
33
|
+
http_body = opts[:http_body]
|
34
|
+
http_body ||= {}
|
35
|
+
|
36
|
+
timeout = opts[:timeout]
|
37
|
+
timeout ||= 180
|
38
|
+
|
39
|
+
spinner = opts[:spinner] || false
|
40
|
+
|
41
|
+
browser_obj = PWN::Plugins::TransparentBrowser.open(browser_type: :rest)
|
42
|
+
rest_client = browser_obj[:browser]::Request
|
43
|
+
|
44
|
+
if spinner
|
45
|
+
spin = TTY::Spinner.new(format: :dots)
|
46
|
+
spin.auto_spin
|
47
|
+
end
|
48
|
+
|
49
|
+
retries = 0
|
50
|
+
case http_method
|
51
|
+
when :delete, :get
|
52
|
+
headers[:params] = params
|
53
|
+
response = rest_client.execute(
|
54
|
+
method: http_method,
|
55
|
+
url: "#{base_uri}#{rest_call}",
|
56
|
+
headers: headers,
|
57
|
+
verify_ssl: false,
|
58
|
+
timeout: timeout
|
59
|
+
)
|
60
|
+
|
61
|
+
when :post
|
62
|
+
if http_body.key?(:multipart)
|
63
|
+
headers[:content_type] = 'multipart/form-data'
|
64
|
+
|
65
|
+
response = rest_client.execute(
|
66
|
+
method: http_method,
|
67
|
+
url: "#{base_uri}#{rest_call}",
|
68
|
+
headers: headers,
|
69
|
+
payload: http_body,
|
70
|
+
verify_ssl: false,
|
71
|
+
timeout: timeout
|
72
|
+
)
|
73
|
+
else
|
74
|
+
response = rest_client.execute(
|
75
|
+
method: http_method,
|
76
|
+
url: "#{base_uri}#{rest_call}",
|
77
|
+
headers: headers,
|
78
|
+
payload: http_body.to_json,
|
79
|
+
verify_ssl: false,
|
80
|
+
timeout: timeout
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
else
|
85
|
+
raise "Unsupported HTTP Method #{http_method} for #{self} Plugin"
|
86
|
+
end
|
87
|
+
|
88
|
+
response
|
89
|
+
rescue RestClient::ExceptionWithResponse => e
|
90
|
+
case e.http_code
|
91
|
+
when 400, 404
|
92
|
+
"#{e.http_code} #{e.message}: #{e.response.body}"
|
93
|
+
else
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
rescue StandardError => e
|
97
|
+
raise e
|
98
|
+
ensure
|
99
|
+
spin.stop if spinner
|
100
|
+
end
|
101
|
+
|
102
|
+
# Supported Method Parameters::
|
103
|
+
# latest_block = PWN::Blockchain::BTC.get_latest_block(
|
104
|
+
# token: 'optional - API token for higher rate limits'
|
105
|
+
# )
|
106
|
+
|
107
|
+
public_class_method def self.get_latest_block(opts = {})
|
108
|
+
params = {}
|
109
|
+
params[:token] = opts[:token] if opts[:token]
|
110
|
+
|
111
|
+
rest_call = 'main'
|
112
|
+
response = btc_rest_call(rest_call: rest_call, params: params)
|
113
|
+
|
114
|
+
JSON.parse(response.body, symbolize_names: true)
|
115
|
+
rescue StandardError => e
|
116
|
+
raise e
|
117
|
+
end
|
118
|
+
|
119
|
+
# Supported Method Parameters::
|
120
|
+
# PWN::Blockchain::BTC.get_block_details(
|
121
|
+
# height: 'required - block height number',
|
122
|
+
# token: 'optional - API token for higher rate limits'
|
123
|
+
# )
|
124
|
+
public_class_method def self.get_block_details(opts = {})
|
125
|
+
height = opts[:height]
|
126
|
+
params = {}
|
127
|
+
params[:token] = opts[:token] if opts[:token]
|
128
|
+
|
129
|
+
rest_call = "main/blocks/#{height}"
|
130
|
+
response = btc_rest_call(rest_call: rest_call, params: params)
|
131
|
+
|
132
|
+
JSON.parse(response.body, symbolize_names: true)
|
133
|
+
rescue StandardError => e
|
134
|
+
raise e
|
135
|
+
end
|
136
|
+
|
137
|
+
# Author(s):: 0day Inc. <support@0dayinc.com>
|
138
|
+
|
139
|
+
public_class_method def self.authors
|
140
|
+
"AUTHOR(S):
|
141
|
+
0day Inc. <support@0dayinc.com>
|
142
|
+
"
|
143
|
+
end
|
144
|
+
|
145
|
+
# Display Usage for this Module
|
146
|
+
|
147
|
+
public_class_method def self.help
|
148
|
+
puts "USAGE:
|
149
|
+
latest_block = #{self}.get_latest_block
|
150
|
+
|
151
|
+
block_details = #{self}.get_block_details(
|
152
|
+
height: 'required - block height number'
|
153
|
+
)
|
154
|
+
|
155
|
+
#{self}.authors
|
156
|
+
"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'tty-spinner'
|
6
|
+
|
7
|
+
module PWN
|
8
|
+
module Blockchain
|
9
|
+
# This plugin interacts with BitCoin's Blockchain API.
|
10
|
+
module ETH
|
11
|
+
# Supported Method Parameters::
|
12
|
+
# eth_rest_call(
|
13
|
+
# http_method: 'optional HTTP method (defaults to GET)
|
14
|
+
# rest_call: 'required rest call to make per the schema',
|
15
|
+
# params: 'optional params passed in the URI or HTTP Headers',
|
16
|
+
# http_body: 'optional HTTP body sent in HTTP methods that support it e.g. POST',
|
17
|
+
# timeout: 'optional timeout in seconds (defaults to 180)',
|
18
|
+
# spinner: 'optional - display spinner (defaults to false)'
|
19
|
+
# )
|
20
|
+
|
21
|
+
private_class_method def self.eth_rest_call(opts = {})
|
22
|
+
http_method = if opts[:http_method].nil?
|
23
|
+
:get
|
24
|
+
else
|
25
|
+
opts[:http_method].to_s.scrub.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
base_uri = 'https://api.blockcypher.com/v1/eth/'
|
29
|
+
rest_call = opts[:rest_call].to_s.scrub
|
30
|
+
params = opts[:params]
|
31
|
+
headers = { content_type: 'application/json; charset=UTF-8' }
|
32
|
+
|
33
|
+
http_body = opts[:http_body]
|
34
|
+
http_body ||= {}
|
35
|
+
|
36
|
+
timeout = opts[:timeout]
|
37
|
+
timeout ||= 180
|
38
|
+
|
39
|
+
spinner = opts[:spinner] || false
|
40
|
+
|
41
|
+
browser_obj = PWN::Plugins::TransparentBrowser.open(browser_type: :rest)
|
42
|
+
rest_client = browser_obj[:browser]::Request
|
43
|
+
|
44
|
+
if spinner
|
45
|
+
spin = TTY::Spinner.new(format: :dots)
|
46
|
+
spin.auto_spin
|
47
|
+
end
|
48
|
+
|
49
|
+
retries = 0
|
50
|
+
case http_method
|
51
|
+
when :delete, :get
|
52
|
+
headers[:params] = params
|
53
|
+
response = rest_client.execute(
|
54
|
+
method: http_method,
|
55
|
+
url: "#{base_uri}#{rest_call}",
|
56
|
+
headers: headers,
|
57
|
+
verify_ssl: false,
|
58
|
+
timeout: timeout
|
59
|
+
)
|
60
|
+
|
61
|
+
when :post
|
62
|
+
if http_body.key?(:multipart)
|
63
|
+
headers[:content_type] = 'multipart/form-data'
|
64
|
+
|
65
|
+
response = rest_client.execute(
|
66
|
+
method: http_method,
|
67
|
+
url: "#{base_uri}#{rest_call}",
|
68
|
+
headers: headers,
|
69
|
+
payload: http_body,
|
70
|
+
verify_ssl: false,
|
71
|
+
timeout: timeout
|
72
|
+
)
|
73
|
+
else
|
74
|
+
response = rest_client.execute(
|
75
|
+
method: http_method,
|
76
|
+
url: "#{base_uri}#{rest_call}",
|
77
|
+
headers: headers,
|
78
|
+
payload: http_body.to_json,
|
79
|
+
verify_ssl: false,
|
80
|
+
timeout: timeout
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
else
|
85
|
+
raise "Unsupported HTTP Method #{http_method} for #{self} Plugin"
|
86
|
+
end
|
87
|
+
|
88
|
+
response
|
89
|
+
rescue RestClient::ExceptionWithResponse => e
|
90
|
+
case e.http_code
|
91
|
+
when 400, 404
|
92
|
+
"#{e.http_code} #{e.message}: #{e.response.body}"
|
93
|
+
else
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
rescue StandardError => e
|
97
|
+
raise e
|
98
|
+
ensure
|
99
|
+
spin.stop if spinner
|
100
|
+
end
|
101
|
+
|
102
|
+
# Supported Method Parameters::
|
103
|
+
# latest_block = PWN::Blockchain::ETH.get_latest_block(
|
104
|
+
# token: 'optional - API token for higher rate limits'
|
105
|
+
# )
|
106
|
+
|
107
|
+
public_class_method def self.get_latest_block(opts = {})
|
108
|
+
params = {}
|
109
|
+
params[:token] = opts[:token] if opts[:token]
|
110
|
+
|
111
|
+
rest_call = 'main'
|
112
|
+
response = eth_rest_call(rest_call: rest_call, params: params)
|
113
|
+
|
114
|
+
JSON.parse(response.body, symbolize_names: true)
|
115
|
+
rescue StandardError => e
|
116
|
+
raise e
|
117
|
+
end
|
118
|
+
|
119
|
+
# Supported Method Parameters::
|
120
|
+
# PWN::Blockchain::ETH.get_block_details(
|
121
|
+
# height: 'required - block height number',
|
122
|
+
# token: 'optional - API token for higher rate limits'
|
123
|
+
# )
|
124
|
+
public_class_method def self.get_block_details(opts = {})
|
125
|
+
height = opts[:height]
|
126
|
+
params = {}
|
127
|
+
params[:token] = opts[:token] if opts[:token]
|
128
|
+
|
129
|
+
rest_call = "main/blocks/#{height}"
|
130
|
+
response = eth_rest_call(rest_call: rest_call, params: params)
|
131
|
+
|
132
|
+
JSON.parse(response.body, symbolize_names: true)
|
133
|
+
rescue StandardError => e
|
134
|
+
raise e
|
135
|
+
end
|
136
|
+
|
137
|
+
# Author(s):: 0day Inc. <support@0dayinc.com>
|
138
|
+
|
139
|
+
public_class_method def self.authors
|
140
|
+
"AUTHOR(S):
|
141
|
+
0day Inc. <support@0dayinc.com>
|
142
|
+
"
|
143
|
+
end
|
144
|
+
|
145
|
+
# Display Usage for this Module
|
146
|
+
|
147
|
+
public_class_method def self.help
|
148
|
+
puts "USAGE:
|
149
|
+
latest_block = #{self}.get_latest_block
|
150
|
+
|
151
|
+
block_details = #{self}.get_block_details(
|
152
|
+
height: 'required - block height number'
|
153
|
+
)
|
154
|
+
|
155
|
+
#{self}.authors
|
156
|
+
"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PWN
|
4
|
+
# This file, using the autoload directive loads SP plugins
|
5
|
+
# into memory only when they're needed. For more information, see:
|
6
|
+
# http://www.rubyinside.com/ruby-techniques-revealed-autoload-1652.html
|
7
|
+
module Blockchain
|
8
|
+
autoload :BTC, 'pwn/blockchain/btc'
|
9
|
+
autoload :ETH, 'pwn/blockchain/eth'
|
10
|
+
|
11
|
+
# Display a List of Every PWN::Blockchain Module
|
12
|
+
|
13
|
+
public_class_method def self.help
|
14
|
+
constants.sort
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/pwn/plugins/repl.rb
CHANGED
@@ -18,7 +18,11 @@ module PWN
|
|
18
18
|
mode = opts[:mode]
|
19
19
|
|
20
20
|
proc do |_target_self, _nest_level, pi|
|
21
|
-
|
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
|
22
26
|
|
23
27
|
pi.config.pwn_repl_line += 1
|
24
28
|
line_pad = format(
|
@@ -34,8 +38,8 @@ module PWN
|
|
34
38
|
dchars = "\001\e[33m\002***\001\e[0m\002" if mode == :splat
|
35
39
|
|
36
40
|
if pi.config.pwn_asm
|
37
|
-
arch = pi.config.
|
38
|
-
endian = pi.config.
|
41
|
+
arch = pi.config.pwn[:asm][:arch] ||= PWN::Plugins::DetectOS.arch
|
42
|
+
endian = pi.config.pwn[:asm][:endian] ||= PWN::Plugins::DetectOS.endian
|
39
43
|
|
40
44
|
pi.config.prompt_name = "pwn.asm:#{arch}/#{endian}"
|
41
45
|
name = "\001\e[1m\002\001\e[37m\002#{pi.config.prompt_name}\001\e[0m\002"
|
@@ -44,10 +48,10 @@ module PWN
|
|
44
48
|
end
|
45
49
|
|
46
50
|
if pi.config.pwn_ai
|
47
|
-
ai_engine = pi.config.
|
48
|
-
model = pi.config.
|
49
|
-
system_role_content = pi.config.
|
50
|
-
temp = pi.config.
|
51
|
+
ai_engine = pi.config.pwn[:ai_engine]
|
52
|
+
model = pi.config.pwn[ai_engine][:model]
|
53
|
+
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
54
|
+
temp = pi.config.pwn[ai_engine][:temp]
|
51
55
|
pname = "pwn.ai:#{ai_engine}"
|
52
56
|
pname = "pwn.ai:#{ai_engine}/#{model}" if model
|
53
57
|
pname = "pwn.ai:#{ai_engine}/#{model}.SPEAK" if pi.config.pwn_ai_speak
|
@@ -173,10 +177,10 @@ module PWN
|
|
173
177
|
|
174
178
|
reply = nil
|
175
179
|
response_history = nil
|
176
|
-
shared_chan = pi.config.
|
180
|
+
shared_chan = pi.config.pwn[:irc][:shared_chan]
|
177
181
|
mem_chan = '#mem'
|
178
|
-
ai_agents = pi.config.
|
179
|
-
ai_agents_arr = pi.config.
|
182
|
+
ai_agents = pi.config.pwn[:irc][:ai_agent_nicks]
|
183
|
+
ai_agents_arr = pi.config.pwn[:irc][:ai_agent_nicks].keys
|
180
184
|
total_ai_agents = ai_agents_arr.length
|
181
185
|
mutex = Mutex.new
|
182
186
|
PWN::Plugins::ThreadPool.fill(
|
@@ -302,15 +306,12 @@ module PWN
|
|
302
306
|
next unless dm_agent == nick
|
303
307
|
|
304
308
|
response_history = ai_agents[dm_agent.to_sym][:response_history]
|
305
|
-
ai_engine = pi.config.
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
model = pi.config.pwn_ai_model
|
312
|
-
system_role_content = pi.config.pwn_ai_system_role_content
|
313
|
-
temp = pi.config.pwn_ai_temp
|
309
|
+
ai_engine = pi.config.pwn[:ai_engine]
|
310
|
+
base_uri = pi.config.pwn[ai_engine][:base_uri]
|
311
|
+
key = pi.config.pwn[ai_engine][:key] ||= ''
|
312
|
+
temp = pi.config.pwn[ai_engine][:temp]
|
313
|
+
model = pi.config.pwn[ai_engine][:model]
|
314
|
+
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
314
315
|
|
315
316
|
users_in_chan = PWN::Plugins::IRC.names(
|
316
317
|
irc_obj: irc_obj,
|
@@ -344,10 +345,10 @@ module PWN
|
|
344
345
|
case ai_engine
|
345
346
|
when :grok
|
346
347
|
response = PWN::AI::Grok.chat(
|
347
|
-
base_uri:
|
348
|
-
token:
|
348
|
+
base_uri: base_uri,
|
349
|
+
token: key,
|
349
350
|
model: model,
|
350
|
-
temp:
|
351
|
+
temp: temp,
|
351
352
|
system_role_content: system_role_content,
|
352
353
|
request: request,
|
353
354
|
response_history: response_history,
|
@@ -355,10 +356,10 @@ module PWN
|
|
355
356
|
)
|
356
357
|
when :ollama
|
357
358
|
response = PWN::AI::Ollama.chat(
|
358
|
-
base_uri:
|
359
|
-
token:
|
359
|
+
base_uri: base_uri,
|
360
|
+
token: key,
|
360
361
|
model: model,
|
361
|
-
temp:
|
362
|
+
temp: temp,
|
362
363
|
system_role_content: system_role_content,
|
363
364
|
request: request,
|
364
365
|
response_history: response_history,
|
@@ -366,10 +367,10 @@ module PWN
|
|
366
367
|
)
|
367
368
|
when :openai
|
368
369
|
response = PWN::AI::OpenAI.chat(
|
369
|
-
base_uri:
|
370
|
-
token:
|
370
|
+
base_uri: base_uri,
|
371
|
+
token: key,
|
371
372
|
model: model,
|
372
|
-
temp:
|
373
|
+
temp: temp,
|
373
374
|
system_role_content: system_role_content,
|
374
375
|
request: request,
|
375
376
|
response_history: response_history,
|
@@ -434,7 +435,7 @@ module PWN
|
|
434
435
|
|
435
436
|
# TODO: Use TLS for IRC Connections
|
436
437
|
# Use an IRC nCurses CLI Client
|
437
|
-
ui_nick = pi.config.
|
438
|
+
ui_nick = pi.config.pwn[:irc][:ui_nick]
|
438
439
|
join_channels = ai_agents_arr.map { |ai_chan| "##{ai_chan}" }.join(',')
|
439
440
|
|
440
441
|
cmd0 = "/server add pwn #{host}/#{port} -notls"
|
@@ -469,12 +470,13 @@ module PWN
|
|
469
470
|
return
|
470
471
|
end
|
471
472
|
|
472
|
-
|
473
|
-
unless File.exist?(
|
474
|
-
puts "ERROR: pwn.decryptor.yaml not found: #{
|
473
|
+
yaml_decryptor_path = pi.config.yaml_decryptor_path ||= "#{Dir.home}/.pwn/pwn.decryptor.yaml"
|
474
|
+
unless File.exist?(yaml_decryptor_path)
|
475
|
+
puts "ERROR: pwn.decryptor.yaml not found: #{yaml_decryptor_path}"
|
475
476
|
return
|
476
477
|
end
|
477
|
-
|
478
|
+
|
479
|
+
decryptor = YAML.load_file(yaml_decryptor_path, symbolize_names: true)
|
478
480
|
key = decryptor[:key]
|
479
481
|
iv = decryptor[:iv]
|
480
482
|
|
@@ -537,10 +539,8 @@ module PWN
|
|
537
539
|
|
538
540
|
# Initialize pwn.yaml Configuration using :before_session Hook
|
539
541
|
Pry.config.hooks.add_hook(:before_session, :init_opts) do |_output, _binding, pi|
|
542
|
+
# puts "Refreshing PWN env via #{opts[:yaml_config_path]}"
|
540
543
|
opts[:pi] = pi
|
541
|
-
Pry.config.yaml_config_path = opts[:yaml_config_path]
|
542
|
-
Pry.config.decryption_file = opts[:decryption_file]
|
543
|
-
|
544
544
|
PWN::Plugins::Vault.refresh_config_for_repl(opts)
|
545
545
|
end
|
546
546
|
|
@@ -548,8 +548,8 @@ module PWN
|
|
548
548
|
if pi.config.pwn_asm && !request.chomp.empty?
|
549
549
|
request = pi.input.line_buffer
|
550
550
|
|
551
|
-
arch = pi.config.
|
552
|
-
endian = pi.config.
|
551
|
+
arch = pi.config.pwn[:asm][:arch]
|
552
|
+
endian = pi.config.pwn[:asm][:endian]
|
553
553
|
|
554
554
|
# Analyze request to determine if it should be processed as opcodes or asm.
|
555
555
|
straight_hex = /^[a-fA-F0-9\s]+$/
|
@@ -585,29 +585,27 @@ module PWN
|
|
585
585
|
if pi.config.pwn_ai && !request.chomp.empty?
|
586
586
|
request = pi.input.line_buffer.to_s
|
587
587
|
debug = pi.config.pwn_ai_debug
|
588
|
-
ai_engine = pi.config.
|
589
|
-
|
590
|
-
|
591
|
-
if
|
592
|
-
|
588
|
+
ai_engine = pi.config.pwn[:ai_engine]
|
589
|
+
base_uri = pi.config.pwn[ai_engine][:base_uri]
|
590
|
+
key = pi.config.pwn[ai_engine][:key] ||= ''
|
591
|
+
if key.empty?
|
592
|
+
key = PWN::Plugins::AuthenticationHelper.mask_password(
|
593
593
|
prompt: 'pwn-ai Key'
|
594
594
|
)
|
595
|
-
pi.config.
|
595
|
+
pi.config.pwn[ai_engine][:key] = key
|
596
596
|
end
|
597
597
|
|
598
598
|
response_history = pi.config.pwn_ai_response_history
|
599
599
|
speak_answer = pi.config.pwn_ai_speak
|
600
|
-
model = pi.config.
|
601
|
-
system_role_content = pi.config.
|
602
|
-
temp = pi.config.
|
603
|
-
|
604
|
-
ai_base_uri = pi.config.pwn_ai_base_uri
|
600
|
+
model = pi.config.pwn[ai_engine][:model]
|
601
|
+
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
602
|
+
temp = pi.config.pwn[ai_engine][:temp]
|
605
603
|
|
606
604
|
case ai_engine
|
607
605
|
when :grok
|
608
606
|
response = PWN::AI::Grok.chat(
|
609
|
-
base_uri:
|
610
|
-
token:
|
607
|
+
base_uri: base_uri,
|
608
|
+
token: key,
|
611
609
|
model: model,
|
612
610
|
system_role_content: system_role_content,
|
613
611
|
temp: temp,
|
@@ -618,8 +616,8 @@ module PWN
|
|
618
616
|
)
|
619
617
|
when :ollama
|
620
618
|
response = PWN::AI::Ollama.chat(
|
621
|
-
base_uri:
|
622
|
-
token:
|
619
|
+
base_uri: base_uri,
|
620
|
+
token: key,
|
623
621
|
model: model,
|
624
622
|
system_role_content: system_role_content,
|
625
623
|
temp: temp,
|
@@ -630,8 +628,8 @@ module PWN
|
|
630
628
|
)
|
631
629
|
when :openai
|
632
630
|
response = PWN::AI::OpenAI.chat(
|
633
|
-
base_uri:
|
634
|
-
token:
|
631
|
+
base_uri: base_uri,
|
632
|
+
token: key,
|
635
633
|
model: model,
|
636
634
|
system_role_content: system_role_content,
|
637
635
|
temp: temp,
|
@@ -690,7 +688,7 @@ module PWN
|
|
690
688
|
pwn_config_root = "#{Dir.home}/.pwn"
|
691
689
|
FileUtils.mkdir_p(pwn_config_root)
|
692
690
|
opts[:yaml_config_path] ||= "#{pwn_config_root}/pwn.yaml"
|
693
|
-
opts[:
|
691
|
+
opts[:yaml_decryptor_path] ||= "#{pwn_config_root}/pwn.decryptor.yaml"
|
694
692
|
|
695
693
|
add_hooks(opts)
|
696
694
|
|
data/lib/pwn/plugins/vault.rb
CHANGED
@@ -173,7 +173,7 @@ module PWN
|
|
173
173
|
system(relative_editor, file)
|
174
174
|
|
175
175
|
# If the Pry object exists, set refresh_config to true
|
176
|
-
Pry.config.
|
176
|
+
Pry.config.refresh = true if defined?(Pry)
|
177
177
|
|
178
178
|
encrypt(
|
179
179
|
file: file,
|
@@ -238,23 +238,24 @@ module PWN
|
|
238
238
|
# PWN::Plugins::Vault.refresh_config_for_repl(
|
239
239
|
# yaml_config_path: 'required - full path to pwn.yaml file',
|
240
240
|
# pi: 'optional - Pry instance (default: Pry)',
|
241
|
-
#
|
241
|
+
# yaml_decryptor_path: 'optional - full path to decryption YAML file'
|
242
242
|
# )
|
243
243
|
public_class_method def self.refresh_config_for_repl(opts = {})
|
244
244
|
yaml_config_path = opts[:yaml_config_path]
|
245
245
|
|
246
246
|
return false unless File.exist?(yaml_config_path)
|
247
247
|
|
248
|
-
pi = opts[:pi]
|
248
|
+
pi = opts[:pi]
|
249
|
+
raise 'ERROR: Pry instance is required.' if pi.nil?
|
249
250
|
|
250
251
|
is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: yaml_config_path)
|
251
252
|
|
252
253
|
if is_encrypted
|
253
254
|
# TODO: Implement "something you know, something you have, && something you are?"
|
254
|
-
|
255
|
-
raise "ERROR: #{
|
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)
|
256
257
|
|
257
|
-
yaml_decryptor = YAML.load_file(
|
258
|
+
yaml_decryptor = YAML.load_file(yaml_decryptor_path, symbolize_names: true)
|
258
259
|
|
259
260
|
key = opts[:key] ||= yaml_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
|
260
261
|
key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
|
@@ -270,52 +271,41 @@ module PWN
|
|
270
271
|
else
|
271
272
|
yaml_config = YAML.load_file(yaml_config_path, symbolize_names: true)
|
272
273
|
end
|
273
|
-
pi.config.p = yaml_config
|
274
|
-
Pry.config.p = yaml_config
|
275
274
|
|
276
275
|
valid_ai_engines = %i[
|
277
276
|
grok
|
278
277
|
openai
|
279
278
|
ollama
|
280
279
|
]
|
281
|
-
ai_engine = yaml_config[:ai_engine].to_s.downcase.to_sym
|
282
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]
|
283
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)
|
284
286
|
|
285
|
-
pi.config.
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
pi.config.
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
Pry.config.pwn_asm_endian = pi.config.pwn_asm_endian
|
308
|
-
|
309
|
-
pi.config.pwn_irc = pi.config.p[:irc]
|
310
|
-
Pry.config.pwn_irc = pi.config.pwn_irc
|
311
|
-
|
312
|
-
pi.config.pwn_hunter = pi.config.p[:hunter][:api_key]
|
313
|
-
Pry.config.pwn_hunter = pi.config.pwn_hunter
|
314
|
-
|
315
|
-
pi.config.pwn_shodan = pi.config.p[:shodan][:api_key]
|
316
|
-
Pry.config.pwn_shodan = pi.config.pwn_shodan
|
317
|
-
|
318
|
-
Pry.config.refresh_config = false
|
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
|
319
309
|
|
320
310
|
true
|
321
311
|
rescue StandardError => e
|
@@ -377,7 +367,7 @@ module PWN
|
|
377
367
|
#{self}.refresh_config_for_repl(
|
378
368
|
yaml_config_path: 'required - full path to pwn.yaml file',
|
379
369
|
pi: 'optional - Pry instance (default: Pry)',
|
380
|
-
|
370
|
+
yaml_decryptor_path: 'optional - full path to decryption YAML file'
|
381
371
|
)
|
382
372
|
|
383
373
|
#{self}.authors
|
data/lib/pwn/version.rb
CHANGED
data/lib/pwn.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe PWN::Blockchain::BTC do
|
6
|
+
it 'should display information for authors' do
|
7
|
+
authors_response = PWN::Blockchain::BTC
|
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::Blockchain::BTC
|
13
|
+
expect(help_response).to respond_to :help
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe PWN::Blockchain::ETH do
|
6
|
+
it 'should display information for authors' do
|
7
|
+
authors_response = PWN::Blockchain::ETH
|
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::Blockchain::ETH
|
13
|
+
expect(help_response).to respond_to :help
|
14
|
+
end
|
15
|
+
end
|
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.427
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0day Inc.
|
@@ -1051,14 +1051,14 @@ dependencies:
|
|
1051
1051
|
requirements:
|
1052
1052
|
- - '='
|
1053
1053
|
- !ruby/object:Gem::Version
|
1054
|
-
version: 0.
|
1054
|
+
version: 0.140.0
|
1055
1055
|
type: :runtime
|
1056
1056
|
prerelease: false
|
1057
1057
|
version_requirements: !ruby/object:Gem::Requirement
|
1058
1058
|
requirements:
|
1059
1059
|
- - '='
|
1060
1060
|
- !ruby/object:Gem::Version
|
1061
|
-
version: 0.
|
1061
|
+
version: 0.140.0
|
1062
1062
|
- !ruby/object:Gem::Dependency
|
1063
1063
|
name: slack-ruby-client
|
1064
1064
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1829,6 +1829,9 @@ files:
|
|
1829
1829
|
- lib/pwn/banner/radare2.rb
|
1830
1830
|
- lib/pwn/banner/radare2_ai.rb
|
1831
1831
|
- lib/pwn/banner/white_rabbit.rb
|
1832
|
+
- lib/pwn/blockchain.rb
|
1833
|
+
- lib/pwn/blockchain/btc.rb
|
1834
|
+
- lib/pwn/blockchain/eth.rb
|
1832
1835
|
- lib/pwn/ffi.rb
|
1833
1836
|
- lib/pwn/ffi/stdio.rb
|
1834
1837
|
- lib/pwn/plugins.rb
|
@@ -2174,6 +2177,9 @@ files:
|
|
2174
2177
|
- spec/lib/pwn/banner/radare2_spec.rb
|
2175
2178
|
- spec/lib/pwn/banner/white_rabbit_spec.rb
|
2176
2179
|
- spec/lib/pwn/banner_spec.rb
|
2180
|
+
- spec/lib/pwn/blockchain/btc_spec.rb
|
2181
|
+
- spec/lib/pwn/blockchain/eth_spec.rb
|
2182
|
+
- spec/lib/pwn/blockchain_spec.rb
|
2177
2183
|
- spec/lib/pwn/ffi/stdio_spec.rb
|
2178
2184
|
- spec/lib/pwn/ffi_spec.rb
|
2179
2185
|
- spec/lib/pwn/plugins/android_spec.rb
|