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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8fd794ce6149bca1bcacf6eb83e4116d26dddad3f7007829cec0ff4520eb9f59
4
- data.tar.gz: 056c7e6727ec6afb5ec98563b912ab65fdca366067296f0aa12501d5d7ae63d1
3
+ metadata.gz: 7e2be578588aa0e4172ddafce691a25711ad3afd796c293cf96df508d3c7fc84
4
+ data.tar.gz: c72375b8d8c69ceb9fd3909d33187f595f3f11c41918cc1dd2fe0ae8a44ed25e
5
5
  SHA512:
6
- metadata.gz: 0764f4c9956e10475675ed33769d07b94ba19090c2db59937ff45ed1f110dad1860a6c02b8eaca71d7e5269dacb4c460472777dfb3285d2ec963c4a0c59975e2
7
- data.tar.gz: 651a021f5476d9e6735c08f126411c23c6cfba3b0d9455ad1561b0fa9a46793f1c1b4bf6025a49f1d0c50f557ed9e150cd339aefed44003298a5f3100fa85e94
6
+ metadata.gz: 47b720e8b8e98b3adf7c04c5e5af2fda98d614c70e29c43b1a5e781b0bf6bf960c60134496f245586656aeebc6349b8a3d8260af12632d1814a0a5dbbc74675e
7
+ data.tar.gz: 3db9a37a60de63e47a700bb0fdd8385a68c2314015ddd8818fe218372a07dda3cb5dfa47126974d7783fffa1c0166cd55d0da235cdaa4bb1508065398bbec623
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2024-03-25 22:25:57 UTC using RuboCop version 1.62.1.
3
+ # on 2024-03-26 16:48:38 UTC using RuboCop version 1.62.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -35,6 +35,12 @@ Layout/LineLength:
35
35
  - 'lib/pwn/reports/uri_buster.rb'
36
36
  - 'lib/pwn/sast/banned_function_calls_c.rb'
37
37
 
38
+ # Offense count: 7
39
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
40
+ Lint/NestedMethodDefinition:
41
+ Exclude:
42
+ - 'lib/pwn/plugins/repl.rb'
43
+
38
44
  # Offense count: 311
39
45
  # This cop supports unsafe autocorrection (--autocorrect-all).
40
46
  # Configuration parameters: AutoCorrect.
@@ -88,6 +94,14 @@ Metrics/ModuleLength:
88
94
  - 'lib/pwn/plugins/open_ai.rb'
89
95
  - 'lib/pwn/plugins/packet.rb'
90
96
 
97
+ # Offense count: 1
98
+ # This cop supports safe autocorrection (--autocorrect).
99
+ # Configuration parameters: EnforcedStyle.
100
+ # SupportedStyles: prefer_alias, prefer_alias_method
101
+ Style/Alias:
102
+ Exclude:
103
+ - 'lib/pwn/plugins/monkey_patch.rb'
104
+
91
105
  # Offense count: 160
92
106
  Style/ClassVars:
93
107
  Enabled: false
@@ -105,11 +119,10 @@ Style/ExplicitBlockArgument:
105
119
  Exclude:
106
120
  - 'lib/pwn/plugins/nmap_it.rb'
107
121
 
108
- # Offense count: 3
122
+ # Offense count: 2
109
123
  # This cop supports safe autocorrection (--autocorrect).
110
124
  Style/IfUnlessModifier:
111
125
  Exclude:
112
- - 'bin/pwn'
113
126
  - 'lib/pwn/plugins/baresip.rb'
114
127
  - 'lib/pwn/plugins/mail_agent.rb'
115
128
 
@@ -133,18 +146,3 @@ Style/RedundantStringEscape:
133
146
  # This cop supports unsafe autocorrection (--autocorrect-all).
134
147
  Style/SlicingWithRange:
135
148
  Enabled: false
136
-
137
- # Offense count: 1
138
- # This cop supports safe autocorrection (--autocorrect).
139
- # Configuration parameters: AllowModifier.
140
- Style/SoleNestedConditional:
141
- Exclude:
142
- - 'bin/pwn'
143
-
144
- # Offense count: 1
145
- # This cop supports safe autocorrection (--autocorrect).
146
- # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
147
- # SupportedStyles: single_quotes, double_quotes
148
- Style/StringLiterals:
149
- Exclude:
150
- - 'bin/pwn'
data/Gemfile CHANGED
@@ -50,7 +50,7 @@ gem 'msfrpc-client', '1.1.2'
50
50
  gem 'netaddr', '2.0.6'
51
51
  gem 'net-ldap', '0.19.0'
52
52
  gem 'net-openvpn', '0.8.7'
53
- gem 'net-smtp', '0.4.0.1'
53
+ gem 'net-smtp', '0.5.0'
54
54
  gem 'nexpose', '7.3.0'
55
55
  gem 'nokogiri', '1.16.3'
56
56
  gem 'nokogiri-diff', '0.3.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.67]:001 >>> PWN.help
40
+ pwn[v0.5.69]:001 >>> PWN.help
41
41
  ```
42
42
 
43
43
  [![Installing the pwn Security Automation Framework](https://raw.githubusercontent.com/0dayInc/pwn/master/documentation/pwn_install.png)](https://youtu.be/G7iLUY4FzsI)
@@ -52,7 +52,7 @@ $ rvm use ruby-3.3.0@pwn
52
52
  $ gem uninstall --all --executables pwn
53
53
  $ gem install --verbose pwn
54
54
  $ pwn
55
- pwn[v0.5.67]:001 >>> PWN.help
55
+ pwn[v0.5.69]: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.3.0@pwn
62
62
  $ rvmsudo gem uninstall --all --executables pwn
63
63
  $ rvmsudo gem install --verbose pwn
64
64
  $ pwn
65
- pwn[v0.5.67]:001 >>> PWN.help
65
+ pwn[v0.5.69]: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
@@ -3,9 +3,6 @@
3
3
 
4
4
  require 'optparse'
5
5
  require 'pwn'
6
- require 'pry'
7
- require 'tty-prompt'
8
- require 'yaml'
9
6
 
10
7
  opts = {}
11
8
  OptionParser.new do |options|
@@ -31,391 +28,19 @@ OptionParser.new do |options|
31
28
  end.parse!
32
29
 
33
30
  begin
34
- def refresh_ps1_proc(opts = {})
35
- mode = opts[:mode]
36
-
37
- proc do |_target_self, _nest_level, pi|
38
- pi.config.pwn_repl_line += 1
39
- line_pad = format(
40
- '%0.3d',
41
- pi.config.pwn_repl_line
42
- )
43
-
44
- pi.config.prompt_name = :pwn
45
- name = "\001\e[1m\002\001\e[31m\002#{pi.config.prompt_name}\001\e[0m\002"
46
- version = "\001\e[36m\002v#{PWN::VERSION}\001\e[0m\002"
47
- line_count = "\001\e[34m\002#{line_pad}\001\e[0m\002"
48
- dchars = "\001\e[32m\002>>>\001\e[0m\002"
49
- dchars = "\001\e[33m\002***\001\e[0m\002" if mode == :splat
50
-
51
- if pi.config.pwn_asm
52
- pi.config.prompt_name = 'pwn.asm'
53
- name = "\001\e[1m\002\001\e[37m\002#{pi.config.prompt_name}\001\e[0m\002"
54
- dchars = "\001\e[32m\002>>>\001\e[33m\002"
55
- dchars = "\001\e[33m\002***\001\e[33m\002" if mode == :splat
56
- end
57
-
58
- if pi.config.pwn_ai
59
- pi.config.prompt_name = 'pwn.ai'
60
- pi.config.prompt_name = 'pwn.ai.SPEAKING' if pi.config.pwn_ai_speak
61
- name = "\001\e[1m\002\001\e[33m\002#{pi.config.prompt_name}\001\e[0m\002"
62
- dchars = "\001\e[32m\002>>>\001\e[33m\002"
63
- dchars = "\001\e[33m\002***\001\e[33m\002" if mode == :splat
64
- if pi.config.pwn_ai_debug
65
- dchars = "\001\e[32m\002(DEBUG) >>>\001\e[33m\002"
66
- dchars = "\001\e[33m\002(DEBUG) ***\001\e[33m\002" if mode == :splat
67
- end
68
- end
69
-
70
- "#{name}[#{version}]:#{line_count} #{dchars} ".to_s.scrub
71
- end
72
- end
73
-
74
- # Pry Monkey Patches \_(--)_/
75
- class Pry
76
- # Overwrite Pry::History.push method in History class to get duplicate history entries
77
- # in order to properly replay automation in this prototyping driver
78
- class History
79
- def push(line)
80
- return line if line.empty? || invalid_readline_line?(line)
81
-
82
- begin
83
- last_line = @history[-1]
84
- rescue IndexError
85
- last_line = nil
86
- end
87
-
88
- @history << line
89
- @history_line_count += 1
90
- @saver.call(line) if !should_ignore?(line) &&
91
- Pry.config.history_save
92
-
93
- line
94
- end
95
- alias << push
96
- end
97
-
98
- def handle_line(line, options)
99
- if line.nil?
100
- config.control_d_handler.call(self)
101
- return
102
- end
103
-
104
- ensure_correct_encoding!(line)
105
- Pry.history << line unless options[:generated]
106
-
107
- @suppress_output = false
108
- inject_sticky_locals!
109
- begin
110
- unless process_command_safely(line)
111
- @eval_string += "#{line.chomp}\n" if !line.empty? || !@eval_string.empty?
112
- end
113
- rescue RescuableException => e
114
- self.last_exception = e
115
- result = e
116
-
117
- Pry.critical_section do
118
- show_result(result)
119
- end
120
- return
121
- end
122
-
123
- # This hook is supposed to be executed after each line of ruby code
124
- # has been read (regardless of whether eval_string is yet a complete expression)
125
- exec_hook :after_read, eval_string, self
126
-
127
- begin
128
- complete_expr = true if config.pwn_ai || config.pwn_asm
129
- complete_expr = Pry::Code.complete_expression?(@eval_string) unless config.pwn_ai || config.pwn_asm
130
- rescue SyntaxError => e
131
- output.puts e.message.gsub(/^.*syntax error, */, "SyntaxError: ")
132
- reset_eval_string
133
- end
134
-
135
- if complete_expr
136
- @suppress_output = true if @eval_string =~ /;\Z/ ||
137
- @eval_string.empty? ||
138
- @eval_string =~ /\A *#.*\n\z/ ||
139
- config.pwn_ai ||
140
- config.pwn_asm
141
-
142
- # A bug in jruby makes java.lang.Exception not rescued by
143
- # `rescue Pry::RescuableException` clause.
144
- #
145
- # * https://github.com/pry/pry/issues/854
146
- # * https://jira.codehaus.org/browse/JRUBY-7100
147
- #
148
- # Until that gets fixed upstream, treat java.lang.Exception
149
- # as an additional exception to be rescued explicitly.
150
- #
151
- # This workaround has a side effect: java exceptions specified
152
- # in `Pry.config.unrescued_exceptions` are ignored.
153
- jruby_exceptions = []
154
- jruby_exceptions << Java::JavaLang::Exception if Helpers::Platform.jruby?
155
-
156
- begin
157
- # Reset eval string, in case we're evaluating Ruby that does something
158
- # like open a nested REPL on this instance.
159
- eval_string = @eval_string
160
- reset_eval_string
161
-
162
- result = evaluate_ruby(eval_string) unless config.pwn_ai ||
163
- config.pwn_asm
164
-
165
- result = eval_string if config.pwn_ai ||
166
- config.pwn_asm
167
- rescue RescuableException, *jruby_exceptions => e
168
- # Eliminate following warning:
169
- # warning: singleton on non-persistent Java type X
170
- # (http://wiki.jruby.org/Persistence)
171
- if Helpers::Platform.jruby? && e.class.respond_to?('__persistent__')
172
- e.class.__persistent__ = true
173
- end
174
- self.last_exception = e
175
- result = e
176
- end
177
-
178
- Pry.critical_section do
179
- show_result(result)
180
- end
181
- end
182
-
183
- throw(:breakout) if current_binding.nil?
184
- end
185
-
186
- # Ensure the return value in pwn_ai mode reflects the input
187
- def evaluate_ruby(code)
188
- # if config.pwn_ai || config.pwn_asm
189
- # result = message = code.to_s
190
- # return
191
- # end
192
- inject_sticky_locals!
193
- exec_hook :before_eval, code, self
194
-
195
- result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
196
- set_last_result(result, code)
197
- ensure
198
- update_input_history(code)
199
- exec_hook :after_eval, result, self
200
- end
201
- end
202
-
203
- # Define Custom REPL Commands
204
- Pry::Commands.create_command 'welcome-banner' do
205
- description 'Display the random welcome banner, including basic usage.'
206
-
207
- def process
208
- puts PWN::Banner.welcome
209
- end
210
- end
211
-
212
- Pry::Commands.create_command 'toggle-pager' do
213
- description 'Toggle less on returned objects surpassing the terminal.'
214
-
215
- def process
216
- pi = pry_instance
217
- pi.config.pager ? pi.config.pager = false : pi.config.pager = true
218
- end
219
- end
220
-
221
- # class PWNCompleter < Pry::InputCompleter
222
- # def call(input)
223
- # end
224
- # end
225
-
226
- Pry::Commands.create_command 'pwn-asm' do
227
- description 'Initiate pwn.asm shell.'
228
-
229
- def process
230
- pi = pry_instance
231
- pi.config.pwn_asm = true
232
- pi.custom_completions = proc do
233
- prompt = TTY::Prompt.new
234
- [pi.input.line_buffer]
235
- # prompt.select(pi.input.line_buffer)
236
- end
237
- end
238
- end
239
-
240
- Pry::Commands.create_command 'pwn-ai' do
241
- description 'Initiate pwn.ai chat interface.'
242
-
243
- def process
244
- pi = pry_instance
245
- pi.config.pwn_ai = true
246
- pi.config.color = false if pi.config.pwn_ai
247
- pi.config.color = true unless pi.config.pwn_ai
248
- end
249
- end
250
-
251
- Pry::Commands.create_command 'toggle-pwn-ai-debug' do
252
- description 'Display the response_history object while using pwn.ai'
253
-
254
- def process
255
- pi = pry_instance
256
- pi.config.pwn_ai_debug ? pi.config.pwn_ai_debug = false : pi.config.pwn_ai_debug = true
257
- end
258
- end
259
-
260
- Pry::Commands.create_command 'toggle-pwn-ai-speaks' do
261
- description 'Use speech capabilities within pwn.ai to speak answers.'
262
-
263
- def process
264
- pi = pry_instance
265
- pi.config.pwn_ai_speak ? pi.config.pwn_ai_speak = false : pi.config.pwn_ai_speak = true
266
- end
267
- end
268
-
269
- Pry::Commands.create_command 'back' do
270
- description 'Jump back to pwn REPL when in pwn-asm || pwn-ai.'
271
-
272
- def process
273
- pi = pry_instance
274
- pi.config.pwn_asm = false if pi.config.pwn_asm
275
- pi.config.pwn_ai = false if pi.config.pwn_ai
276
- pi.config.pwn_ai_debug = false if pi.config.pwn_ai_debug
277
- pi.config.pwn_ai_speak = false if pi.config.pwn_ai_speak
278
- pi.config.completer = Pry::InputCompleter
279
- end
280
- end
281
-
282
- # Define REPL Hooks
283
- # Welcome Banner Hook
284
- Pry.config.hooks.add_hook(:before_session, :welcome) do |output, _binding, _pi|
285
- output.puts PWN::Banner.welcome
286
- end
287
-
288
- # pwn.ai Hooks
289
- Pry.config.hooks.add_hook(:before_session, :init_opts) do |_output, _binding, pi|
290
- if opts[:yaml_config_path] && File.exist?(opts[:yaml_config_path])
291
- yaml_config_path = opts[:yaml_config_path]
292
- is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: yaml_config_path)
293
-
294
- if is_encrypted
295
- # TODO: Implement "something you know, something you have, && something you are?"
296
- decryption_file = opts[:decryption_file] ||= "#{Dir.home}/pwn.decryptor.yaml"
297
- yaml_decryptor = YAML.load_file(decryption_file, symbolize_names: true) if File.exist?(decryption_file)
298
-
299
- key = opts[:key] ||= yaml_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
300
- key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
301
-
302
- iv = opts[:iv] ||= yaml_decryptor[:iv] ||= ENV.fetch('PWN_DECRYPTOR_IV')
303
- iv = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption IV') if iv.nil?
304
-
305
- decrypted_yaml_config = PWN::Plugins::Vault.dump(
306
- file: yaml_config_path,
307
- key: key,
308
- iv: iv
309
- )
310
- yaml_config = YAML.load(decrypted_yaml_config, symbolize_names: true)
311
- else
312
- yaml_config = YAML.load_file(yaml_config_path, symbolize_names: true)
313
- end
314
-
315
- pi.config.pwn_ai_key = yaml_config[:ai_key]
316
- Pry.config.pwn_ai_key = pi.config.pwn_ai_key
317
- end
318
- end
319
-
320
- Pry.config.hooks.add_hook(:after_read, :pwn_asm_hook) do |request, pi|
321
- if pi.config.pwn_asm && !request.chomp.empty?
322
- request = pi.input.line_buffer
323
-
324
- # Analyze request to determine if it should be processed as opcodes or asm.
325
- straight_hex = /^[a-fA-F0-9\s]+$/
326
- hex_esc_strings = /\\x[\da-fA-F]{2}/
327
- hex_comma_delim_w_dbl_qt = /"(?:[0-9a-fA-F]{2})",?/
328
- hex_comma_delim_w_sng_qt = /'(?:[0-9a-fA-F]{2})',?/
329
- hex_byte_array_as_str = /^\[\s*(?:"[0-9a-fA-F]{2}",\s*)*"[0-9a-fA-F]{2}"\s*\]$/
330
-
331
- if request.match?(straight_hex) ||
332
- request.match?(hex_esc_strings) ||
333
- request.match?(hex_comma_delim_w_dbl_qt) ||
334
- request.match?(hex_comma_delim_w_sng_qt) ||
335
- request.match?(hex_byte_array_as_str)
336
-
337
- response = PWN::Plugins::Assembly.opcodes_to_asm(
338
- opcodes: request,
339
- opcodes_always_strings_obj: true
340
- )
341
- else
342
- response = PWN::Plugins::Assembly.asm_to_opcodes(asm: request)
343
- end
344
- puts "\001\e[31m\002#{response}\001\e[0m\002"
345
- end
346
- end
347
-
348
- Pry.config.hooks.add_hook(:after_read, :pwn_ai_hook) do |request, pi|
349
- if pi.config.pwn_ai && !request.chomp.empty?
350
- request = pi.input.line_buffer.to_s
351
- debug = pi.config.pwn_ai_debug
352
- ai_key = pi.config.pwn_ai_key
353
- ai_key ||= ''
354
- if ai_key.empty?
355
- ai_key = PWN::Plugins::AuthenticationHelper.mask_password(
356
- prompt: 'OpenAI API Key'
357
- )
358
- pi.config.pwn_ai_key = ai_key
359
- end
360
-
361
- response_history = pi.config.pwn_ai_response_history
362
- speak_answer = pi.config.pwn_ai_speak
363
- response = PWN::Plugins::OpenAI.chat(
364
- token: ai_key,
365
- request: request.chomp,
366
- temp: 1,
367
- response_history: response_history,
368
- speak_answer: speak_answer
369
- )
370
- last_response = response[:choices].last[:content]
371
- puts "\n\001\e[32m\002#{last_response}\001\e[0m\002\n\n"
372
-
373
- response_history = {
374
- id: response[:id],
375
- object: response[:object],
376
- model: response[:model],
377
- usage: response[:usage]
378
- }
379
- response_history[:choices] ||= response[:choices]
380
-
381
- if debug
382
- puts 'DEBUG: response_history => '
383
- pp response_history
384
- puts "\nresponse_history[:choices] Length: #{response_history[:choices].length}\n" unless response_history.nil?
385
- end
386
- pi.config.pwn_ai_response_history = response_history
387
- end
388
- end
389
-
390
- # Define PS1 Prompt
391
- Pry.config.pwn_repl_line = 0
392
- Pry.config.prompt_name = :pwn
393
- arrow_ps1_proc = refresh_ps1_proc
394
- splat_ps1_proc = refresh_ps1_proc(mode: :splat)
395
- prompt_ps1 = [arrow_ps1_proc, splat_ps1_proc]
396
- prompt = Pry::Prompt.new(
397
- :pwn,
398
- 'PWN Prototyping REPL',
399
- prompt_ps1
400
- )
401
-
402
- # Start PWN REPL
403
31
  pwn_pid = Process.pid
404
- Pry.start(
405
- self,
406
- prompt: prompt
407
- )
32
+ PWN::Plugins::REPL.start(opts)
408
33
  rescue StandardError => e
409
34
  raise e
410
35
  ensure
411
- proc_list_arr = PWN::Plugins::PS.list
36
+ ps_list_arr = PWN::Plugins::PS.list
412
37
 
413
- kid_pids_arr = proc_list_arr.select { |proc_line| proc_line[3] == pwn_pid.to_s }
38
+ kid_pids_arr = ps_list_arr.select { |ps_line| ps_line[3] == pwn_pid.to_s }
414
39
  # pp kid_pids_arr
415
40
 
416
41
  grandkid_pids_arr = []
417
42
  kid_pids_arr.each do |kid_pid|
418
- gk_arr = proc_list_arr.select { |proc_line| proc_line[3] == kid_pid[2] }
43
+ gk_arr = ps_list_arr.select { |ps_line| ps_line[3] == kid_pid[2] }
419
44
  gk_arr.each { |gk| grandkid_pids_arr.push(gk) }
420
45
  end
421
46
  # pp grandkid_pids_arr
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PWN
4
+ module Plugins
5
+ # This module provides the abilty to centralize monkey patches used in PWN
6
+ module MonkeyPatch
7
+ # Supported Method Parameters::
8
+ # PWN::Plugins::MonkeyPatch.pry
9
+
10
+ public_class_method def self.pry
11
+ # Overwrite Pry::History.push method in History class
12
+ # to get duplicate history entries in order to properly
13
+ # replay automation in this prototyping driver
14
+ Pry::History.class_eval do
15
+ def push(line)
16
+ return line if line.empty? || invalid_readline_line?(line)
17
+
18
+ begin
19
+ last_line = @history[-1]
20
+ rescue IndexError
21
+ last_line = nil
22
+ end
23
+
24
+ @history << line
25
+ @history_line_count += 1
26
+ @saver.call(line) if !should_ignore?(line) &&
27
+ Pry.config.history_save
28
+
29
+ line
30
+ end
31
+ alias << push
32
+ end
33
+
34
+ Pry.class_eval do
35
+ def handle_line(line, options)
36
+ if line.nil?
37
+ config.control_d_handler.call(self)
38
+ return
39
+ end
40
+
41
+ ensure_correct_encoding!(line)
42
+ Pry.history << line unless options[:generated]
43
+
44
+ @suppress_output = false
45
+ inject_sticky_locals!
46
+ begin
47
+ # unless process_command_safely(line)
48
+ unless process_command_safely(line) && (
49
+ line.empty? || @eval_string.empty?
50
+ )
51
+ # @eval_string += "#{line.chomp}\n" if !line.empty? || !@eval_string.empty?
52
+ @eval_string += "#{line.chomp}\n"
53
+ end
54
+ rescue Pry::RescuableException => e
55
+ self.last_exception = e
56
+ result = e
57
+
58
+ Pry.critical_section do
59
+ show_result(result)
60
+ end
61
+ return
62
+ end
63
+
64
+ # This hook is supposed to be executed after each line of ruby code
65
+ # has been read (regardless of whether eval_string is yet a complete expression)
66
+ exec_hook :after_read, eval_string, self
67
+
68
+ begin
69
+ complete_expr = true if config.pwn_ai || config.pwn_asm
70
+ complete_expr = Pry::Code.complete_expression?(@eval_string) unless config.pwn_ai || config.pwn_asm
71
+ rescue SyntaxError => e
72
+ output.puts e.message.gsub(/^.*syntax error, */, 'SyntaxError: ')
73
+ reset_eval_string
74
+ end
75
+
76
+ if complete_expr
77
+ @suppress_output = true if @eval_string =~ /;\Z/ ||
78
+ @eval_string.empty? ||
79
+ @eval_string =~ /\A *#.*\n\z/ ||
80
+ config.pwn_ai ||
81
+ config.pwn_asm
82
+
83
+ # A bug in jruby makes java.lang.Exception not rescued by
84
+ # `rescue Pry::RescuableException` clause.
85
+ #
86
+ # * https://github.com/pry/pry/issues/854
87
+ # * https://jira.codehaus.org/browse/JRUBY-7100
88
+ #
89
+ # Until that gets fixed upstream, treat java.lang.Exception
90
+ # as an additional exception to be rescued explicitly.
91
+ #
92
+ # This workaround has a side effect: java exceptions specified
93
+ # in `Pry.config.unrescued_exceptions` are ignored.
94
+ jruby_exceptions = []
95
+ jruby_exceptions << Java::JavaLang::Exception if Pry::Helpers::Platform.jruby?
96
+
97
+ begin
98
+ # Reset eval string, in case we're evaluating Ruby that does something
99
+ # like open a nested REPL on this instance.
100
+ eval_string = @eval_string
101
+ reset_eval_string
102
+
103
+ result = evaluate_ruby(eval_string) unless config.pwn_ai ||
104
+ config.pwn_asm
105
+
106
+ result = eval_string if config.pwn_ai ||
107
+ config.pwn_asm
108
+ rescue Pry::RescuableException, *jruby_exceptions => e
109
+ # Eliminate following warning:
110
+ # warning: singleton on non-persistent Java type X
111
+ # (http://wiki.jruby.org/Persistence)
112
+ e.class.__persistent__ = true if Pry::Helpers::Platform.jruby? && e.class.respond_to?('__persistent__')
113
+ self.last_exception = e
114
+ result = e
115
+ end
116
+
117
+ Pry.critical_section do
118
+ show_result(result)
119
+ end
120
+ end
121
+
122
+ throw(:breakout) if current_binding.nil?
123
+ end
124
+
125
+ # Ensure the return value in pwn_ai mode reflects the input
126
+ def evaluate_ruby(code)
127
+ # if config.pwn_ai || config.pwn_asm
128
+ # result = message = code.to_s
129
+ # return
130
+ # end
131
+ inject_sticky_locals!
132
+ exec_hook :before_eval, code, self
133
+
134
+ result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
135
+ set_last_result(result, code)
136
+ ensure
137
+ update_input_history(code)
138
+ exec_hook :after_eval, result, self
139
+ end
140
+ end
141
+ rescue StandardError => e
142
+ raise e
143
+ end
144
+
145
+ # Author(s):: 0day Inc. <request.pentest@0dayinc.com>
146
+
147
+ public_class_method def self.authors
148
+ "AUTHOR(S):
149
+ 0day Inc. <request.pentest@0dayinc.com>
150
+ "
151
+ end
152
+
153
+ # Display Usage for this Module
154
+
155
+ public_class_method def self.help
156
+ puts "USAGE:
157
+ #{self}.pry
158
+
159
+ #{self}.authors
160
+ "
161
+ end
162
+ end
163
+ end
164
+ end