pwn 0.5.67 → 0.5.69

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.
@@ -0,0 +1,317 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pry'
4
+ require 'tty-prompt'
5
+ require 'yaml'
6
+
7
+ module PWN
8
+ module Plugins
9
+ # This module contains methods related to the pwn REPL Driver.
10
+ module REPL
11
+ # Supported Method Parameters::
12
+ # PWN::Plugins::REPL.refresh_ps1_proc(
13
+ # mode: 'required - :splat or nil'
14
+ # )
15
+
16
+ public_class_method def self.refresh_ps1_proc(opts = {})
17
+ mode = opts[:mode]
18
+
19
+ proc do |_target_self, _nest_level, pi|
20
+ pi.config.pwn_repl_line += 1
21
+ line_pad = format(
22
+ '%0.3d',
23
+ pi.config.pwn_repl_line
24
+ )
25
+
26
+ pi.config.prompt_name = :pwn
27
+ name = "\001\e[1m\002\001\e[31m\002#{pi.config.prompt_name}\001\e[0m\002"
28
+ version = "\001\e[36m\002v#{PWN::VERSION}\001\e[0m\002"
29
+ line_count = "\001\e[34m\002#{line_pad}\001\e[0m\002"
30
+ dchars = "\001\e[32m\002>>>\001\e[0m\002"
31
+ dchars = "\001\e[33m\002***\001\e[0m\002" if mode == :splat
32
+
33
+ if pi.config.pwn_asm
34
+ pi.config.prompt_name = 'pwn.asm'
35
+ name = "\001\e[1m\002\001\e[37m\002#{pi.config.prompt_name}\001\e[0m\002"
36
+ dchars = "\001\e[32m\002>>>\001\e[33m\002"
37
+ dchars = "\001\e[33m\002***\001\e[33m\002" if mode == :splat
38
+ end
39
+
40
+ if pi.config.pwn_ai
41
+ pi.config.prompt_name = 'pwn.ai'
42
+ pi.config.prompt_name = 'pwn.ai.SPEAKING' if pi.config.pwn_ai_speak
43
+ name = "\001\e[1m\002\001\e[33m\002#{pi.config.prompt_name}\001\e[0m\002"
44
+ dchars = "\001\e[32m\002>>>\001\e[33m\002"
45
+ dchars = "\001\e[33m\002***\001\e[33m\002" if mode == :splat
46
+ if pi.config.pwn_ai_debug
47
+ dchars = "\001\e[32m\002(DEBUG) >>>\001\e[33m\002"
48
+ dchars = "\001\e[33m\002(DEBUG) ***\001\e[33m\002" if mode == :splat
49
+ end
50
+ end
51
+
52
+ "#{name}[#{version}]:#{line_count} #{dchars} ".to_s.scrub
53
+ end
54
+ rescue StandardError => e
55
+ raise e
56
+ end
57
+
58
+ # Supported Method Parameters::
59
+ # PWN::Plugins::REPL.add_commands
60
+
61
+ public_class_method def self.add_commands
62
+ # Define Custom REPL Commands
63
+ Pry::Commands.create_command 'welcome-banner' do
64
+ description 'Display the random welcome banner, including basic usage.'
65
+
66
+ def process
67
+ puts PWN::Banner.welcome
68
+ end
69
+ end
70
+
71
+ Pry::Commands.create_command 'toggle-pager' do
72
+ description 'Toggle less on returned objects surpassing the terminal.'
73
+
74
+ def process
75
+ pi = pry_instance
76
+ pi.config.pager ? pi.config.pager = false : pi.config.pager = true
77
+ end
78
+ end
79
+
80
+ # class PWNCompleter < Pry::InputCompleter
81
+ # def call(input)
82
+ # end
83
+ # end
84
+
85
+ Pry::Commands.create_command 'pwn-asm' do
86
+ description 'Initiate pwn.asm shell.'
87
+
88
+ def process
89
+ pi = pry_instance
90
+ pi.config.pwn_asm = true
91
+ pi.custom_completions = proc do
92
+ prompt = TTY::Prompt.new
93
+ [pi.input.line_buffer]
94
+ # prompt.select(pi.input.line_buffer)
95
+ end
96
+ end
97
+ end
98
+
99
+ Pry::Commands.create_command 'pwn-ai' do
100
+ description 'Initiate pwn.ai chat interface.'
101
+
102
+ def process
103
+ pi = pry_instance
104
+ pi.config.pwn_ai = true
105
+ pi.config.color = false if pi.config.pwn_ai
106
+ pi.config.color = true unless pi.config.pwn_ai
107
+ end
108
+ end
109
+
110
+ Pry::Commands.create_command 'toggle-pwn-ai-debug' do
111
+ description 'Display the response_history object while using pwn.ai'
112
+
113
+ def process
114
+ pi = pry_instance
115
+ pi.config.pwn_ai_debug ? pi.config.pwn_ai_debug = false : pi.config.pwn_ai_debug = true
116
+ end
117
+ end
118
+
119
+ Pry::Commands.create_command 'toggle-pwn-ai-speaks' do
120
+ description 'Use speech capabilities within pwn.ai to speak answers.'
121
+
122
+ def process
123
+ pi = pry_instance
124
+ pi.config.pwn_ai_speak ? pi.config.pwn_ai_speak = false : pi.config.pwn_ai_speak = true
125
+ end
126
+ end
127
+
128
+ Pry::Commands.create_command 'back' do
129
+ description 'Jump back to pwn REPL when in pwn-asm || pwn-ai.'
130
+
131
+ def process
132
+ pi = pry_instance
133
+ pi.config.pwn_asm = false if pi.config.pwn_asm
134
+ pi.config.pwn_ai = false if pi.config.pwn_ai
135
+ pi.config.pwn_ai_debug = false if pi.config.pwn_ai_debug
136
+ pi.config.pwn_ai_speak = false if pi.config.pwn_ai_speak
137
+ pi.config.completer = Pry::InputCompleter
138
+ end
139
+ end
140
+ rescue StandardError => e
141
+ raise e
142
+ end
143
+
144
+ # Supported Method Parameters::
145
+ # PWN::Plugins::REPL.add_hooks(
146
+ # opts: 'required - Hash object passed in via pwn OptParser'
147
+ # )
148
+
149
+ public_class_method def self.add_hooks(opts = {})
150
+ # Define REPL Hooks
151
+ # Welcome Banner Hook
152
+ Pry.config.hooks.add_hook(:before_session, :welcome) do |output, _binding, _pi|
153
+ output.puts PWN::Banner.welcome
154
+ end
155
+
156
+ # pwn.ai Hooks
157
+ Pry.config.hooks.add_hook(:before_session, :init_opts) do |_output, _binding, pi|
158
+ if opts[:yaml_config_path] && File.exist?(opts[:yaml_config_path])
159
+ yaml_config_path = opts[:yaml_config_path]
160
+ is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: yaml_config_path)
161
+
162
+ if is_encrypted
163
+ # TODO: Implement "something you know, something you have, && something you are?"
164
+ decryption_file = opts[:decryption_file] ||= "#{Dir.home}/pwn.decryptor.yaml"
165
+ yaml_decryptor = YAML.load_file(decryption_file, symbolize_names: true) if File.exist?(decryption_file)
166
+
167
+ key = opts[:key] ||= yaml_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
168
+ key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
169
+
170
+ iv = opts[:iv] ||= yaml_decryptor[:iv] ||= ENV.fetch('PWN_DECRYPTOR_IV')
171
+ iv = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption IV') if iv.nil?
172
+
173
+ decrypted_yaml_config = PWN::Plugins::Vault.dump(
174
+ file: yaml_config_path,
175
+ key: key,
176
+ iv: iv
177
+ )
178
+ yaml_config = YAML.load(decrypted_yaml_config, symbolize_names: true)
179
+ else
180
+ yaml_config = YAML.load_file(yaml_config_path, symbolize_names: true)
181
+ end
182
+
183
+ pi.config.pwn_ai_key = yaml_config[:ai_key]
184
+ Pry.config.pwn_ai_key = pi.config.pwn_ai_key
185
+ end
186
+ end
187
+
188
+ Pry.config.hooks.add_hook(:after_read, :pwn_asm_hook) do |request, pi|
189
+ if pi.config.pwn_asm && !request.chomp.empty?
190
+ request = pi.input.line_buffer
191
+
192
+ # Analyze request to determine if it should be processed as opcodes or asm.
193
+ straight_hex = /^[a-fA-F0-9\s]+$/
194
+ hex_esc_strings = /\\x[\da-fA-F]{2}/
195
+ hex_comma_delim_w_dbl_qt = /"(?:[0-9a-fA-F]{2})",?/
196
+ hex_comma_delim_w_sng_qt = /'(?:[0-9a-fA-F]{2})',?/
197
+ hex_byte_array_as_str = /^\[\s*(?:"[0-9a-fA-F]{2}",\s*)*"[0-9a-fA-F]{2}"\s*\]$/
198
+
199
+ if request.match?(straight_hex) ||
200
+ request.match?(hex_esc_strings) ||
201
+ request.match?(hex_comma_delim_w_dbl_qt) ||
202
+ request.match?(hex_comma_delim_w_sng_qt) ||
203
+ request.match?(hex_byte_array_as_str)
204
+
205
+ response = PWN::Plugins::Assembly.opcodes_to_asm(
206
+ opcodes: request,
207
+ opcodes_always_strings_obj: true
208
+ )
209
+ else
210
+ response = PWN::Plugins::Assembly.asm_to_opcodes(asm: request)
211
+ end
212
+ puts "\001\e[31m\002#{response}\001\e[0m\002"
213
+ end
214
+ end
215
+
216
+ Pry.config.hooks.add_hook(:after_read, :pwn_ai_hook) do |request, pi|
217
+ if pi.config.pwn_ai && !request.chomp.empty?
218
+ request = pi.input.line_buffer.to_s
219
+ debug = pi.config.pwn_ai_debug
220
+ ai_key = pi.config.pwn_ai_key
221
+ ai_key ||= ''
222
+ if ai_key.empty?
223
+ ai_key = PWN::Plugins::AuthenticationHelper.mask_password(
224
+ prompt: 'OpenAI API Key'
225
+ )
226
+ pi.config.pwn_ai_key = ai_key
227
+ end
228
+
229
+ response_history = pi.config.pwn_ai_response_history
230
+ speak_answer = pi.config.pwn_ai_speak
231
+ response = PWN::Plugins::OpenAI.chat(
232
+ token: ai_key,
233
+ request: request.chomp,
234
+ temp: 1,
235
+ response_history: response_history,
236
+ speak_answer: speak_answer
237
+ )
238
+ last_response = response[:choices].last[:content]
239
+ puts "\n\001\e[32m\002#{last_response}\001\e[0m\002\n\n"
240
+
241
+ response_history = {
242
+ id: response[:id],
243
+ object: response[:object],
244
+ model: response[:model],
245
+ usage: response[:usage]
246
+ }
247
+ response_history[:choices] ||= response[:choices]
248
+
249
+ if debug
250
+ puts 'DEBUG: response_history => '
251
+ pp response_history
252
+ puts "\nresponse_history[:choices] Length: #{response_history[:choices].length}\n" unless response_history.nil?
253
+ end
254
+ pi.config.pwn_ai_response_history = response_history
255
+ end
256
+ end
257
+ rescue StandardError => e
258
+ raise e
259
+ end
260
+
261
+ # Supported Method Parameters::
262
+ # PWN::Plugins::REPL.start(
263
+ # opts: 'required - Hash object passed in via pwn OptParser'
264
+ # )
265
+
266
+ public_class_method def self.start(opts = {})
267
+ # Monkey Patch Pry, add commands, && hooks
268
+ PWN::Plugins::MonkeyPatch.pry
269
+ add_commands
270
+ add_hooks(opts)
271
+
272
+ # Define PS1 Prompt
273
+ Pry.config.pwn_repl_line = 0
274
+ Pry.config.prompt_name = :pwn
275
+ arrow_ps1_proc = refresh_ps1_proc
276
+ splat_ps1_proc = refresh_ps1_proc(mode: :splat)
277
+ ps1 = [arrow_ps1_proc, splat_ps1_proc]
278
+ prompt = Pry::Prompt.new(:pwn, 'PWN Prototyping REPL', ps1)
279
+
280
+ # Start PWN REPL
281
+ Pry.start(self, prompt: prompt)
282
+ rescue StandardError => e
283
+ raise e
284
+ end
285
+
286
+ # Author(s):: 0day Inc. <request.pentest@0dayinc.com>
287
+
288
+ public_class_method def self.authors
289
+ "AUTHOR(S):
290
+ 0day Inc. <request.pentest@0dayinc.com>
291
+ "
292
+ end
293
+
294
+ # Display Usage for this Module
295
+
296
+ public_class_method def self.help
297
+ puts "USAGE:
298
+ #{self}.refresh_ps1_proc(
299
+ mode: 'required - :splat or nil'
300
+ )
301
+
302
+ #{self}.add_commands
303
+
304
+ #{self}.add_hooks(
305
+ opts: 'required - Hash object passed in via pwn OptParser'
306
+ )
307
+
308
+ #{self}.start(
309
+ opts: 'required - Hash object passed in via pwn OptParser'
310
+ )
311
+
312
+ #{self}.authors
313
+ "
314
+ end
315
+ end
316
+ end
317
+ end
@@ -72,6 +72,9 @@ module PWN
72
72
 
73
73
  raise 'ERROR: key and iv parameters are required.' if key.nil? || iv.nil?
74
74
 
75
+ is_encrypted = file_encrypted?(file: file)
76
+ raise 'ERROR: File is not encrypted.' unless is_encrypted
77
+
75
78
  cipher = OpenSSL::Cipher.new('aes-256-cbc')
76
79
  cipher.decrypt
77
80
  cipher.key = Base64.strict_decode64(key)
@@ -195,6 +198,8 @@ module PWN
195
198
 
196
199
  file_contents = File.read(file)
197
200
  file_contents.is_a?(String) && Base64.strict_encode64(Base64.strict_decode64(file_contents)) == file_contents
201
+ rescue ArgumentError
202
+ false
198
203
  rescue StandardError => e
199
204
  raise e
200
205
  end
data/lib/pwn/plugins.rb CHANGED
@@ -37,6 +37,7 @@ module PWN
37
37
  autoload :Log, 'pwn/plugins/log'
38
38
  autoload :MailAgent, 'pwn/plugins/mail_agent'
39
39
  autoload :Metasploit, 'pwn/plugins/metasploit'
40
+ autoload :MonkeyPatch, 'pwn/plugins/monkey_patch'
40
41
  autoload :MSR206, 'pwn/plugins/msr206'
41
42
  autoload :NessusCloud, 'pwn/plugins/nessus_cloud'
42
43
  autoload :NexposeVulnScan, 'pwn/plugins/nexpose_vuln_scan'
@@ -52,6 +53,7 @@ module PWN
52
53
  autoload :Pony, 'pwn/plugins/pony'
53
54
  autoload :PS, 'pwn/plugins/ps'
54
55
  autoload :RabbitMQ, 'pwn/plugins/rabbit_mq'
56
+ autoload :REPL, 'pwn/plugins/repl'
55
57
  autoload :RFIDler, 'pwn/plugins/rfidler'
56
58
  autoload :ScannableCodes, 'pwn/plugins/scannable_codes'
57
59
  autoload :Serial, 'pwn/plugins/serial'
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.67'
4
+ VERSION = '0.5.69'
5
5
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PWN::Plugins::MonkeyPatch do
6
+ it 'should display information for authors' do
7
+ authors_response = PWN::Plugins::MonkeyPatch
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::Plugins::MonkeyPatch
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::Plugins::REPL do
6
+ it 'should display information for authors' do
7
+ authors_response = PWN::Plugins::REPL
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::Plugins::REPL
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.67
4
+ version: 0.5.69
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
@@ -534,14 +534,14 @@ dependencies:
534
534
  requirements:
535
535
  - - '='
536
536
  - !ruby/object:Gem::Version
537
- version: 0.4.0.1
537
+ version: 0.5.0
538
538
  type: :runtime
539
539
  prerelease: false
540
540
  version_requirements: !ruby/object:Gem::Requirement
541
541
  requirements:
542
542
  - - '='
543
543
  - !ruby/object:Gem::Version
544
- version: 0.4.0.1
544
+ version: 0.5.0
545
545
  - !ruby/object:Gem::Dependency
546
546
  name: nexpose
547
547
  requirement: !ruby/object:Gem::Requirement
@@ -1767,6 +1767,7 @@ files:
1767
1767
  - lib/pwn/plugins/log.rb
1768
1768
  - lib/pwn/plugins/mail_agent.rb
1769
1769
  - lib/pwn/plugins/metasploit.rb
1770
+ - lib/pwn/plugins/monkey_patch.rb
1770
1771
  - lib/pwn/plugins/msr206.rb
1771
1772
  - lib/pwn/plugins/nessus_cloud.rb
1772
1773
  - lib/pwn/plugins/nexpose_vuln_scan.rb
@@ -1783,6 +1784,7 @@ files:
1783
1784
  - lib/pwn/plugins/ps.rb
1784
1785
  - lib/pwn/plugins/pwn_logger.rb
1785
1786
  - lib/pwn/plugins/rabbit_mq.rb
1787
+ - lib/pwn/plugins/repl.rb
1786
1788
  - lib/pwn/plugins/rfidler.rb
1787
1789
  - lib/pwn/plugins/scannable_codes.rb
1788
1790
  - lib/pwn/plugins/serial.rb
@@ -2094,6 +2096,7 @@ files:
2094
2096
  - spec/lib/pwn/plugins/log_spec.rb
2095
2097
  - spec/lib/pwn/plugins/mail_agent_spec.rb
2096
2098
  - spec/lib/pwn/plugins/metasploit_spec.rb
2099
+ - spec/lib/pwn/plugins/monkey_patch_spec.rb
2097
2100
  - spec/lib/pwn/plugins/msr206_spec.rb
2098
2101
  - spec/lib/pwn/plugins/nessus_cloud_spec.rb
2099
2102
  - spec/lib/pwn/plugins/nexpose_vuln_scan_spec.rb
@@ -2110,6 +2113,7 @@ files:
2110
2113
  - spec/lib/pwn/plugins/ps_spec.rb
2111
2114
  - spec/lib/pwn/plugins/pwn_logger_spec.rb
2112
2115
  - spec/lib/pwn/plugins/rabbit_mq_spec.rb
2116
+ - spec/lib/pwn/plugins/repl_spec.rb
2113
2117
  - spec/lib/pwn/plugins/rfidler_spec.rb
2114
2118
  - spec/lib/pwn/plugins/scannable_codes_spec.rb
2115
2119
  - spec/lib/pwn/plugins/serial_spec.rb