1
1
# -*- coding: binary -*-
2
- require 'msf/base'
3
- require 'msf/base/sessions/scriptable'
4
- require 'shellwords'
2
+ require 'msf/base/sessions/command_shell'
5
3
6
- module Msf
7
- module Sessions
8
-
9
- ###
10
- #
11
- # This class provides basic interaction with a command shell on the remote
12
- # endpoint. This session is initialized with a stream that will be used
13
- # as the pipe for reading and writing the command shell.
14
- #
15
- ###
16
- class PowerShell
17
-
18
- #
19
- # This interface supports basic interaction.
20
- #
21
- include Msf ::Session ::Basic
22
-
23
- #
24
- # This interface supports interacting with a single command shell.
25
- #
26
- include Msf ::Session ::Provider ::SingleCommandShell
27
-
28
- include Msf ::Session ::Scriptable
29
-
30
-
31
- ##
32
- # :category: Msf::Session::Scriptable implementors
33
- #
34
- # Executes the supplied script, must be specified as full path.
35
- #
36
- # Msf::Session::Scriptable implementor
37
- #
38
- def execute_file ( full_path , args )
39
- o = Rex ::Script ::Shell . new ( self , full_path )
40
- o . run ( args )
41
- end
4
+ class Msf ::Sessions ::PowerShell < Msf ::Sessions ::CommandShell
42
5
43
6
#
44
7
# Returns the type of session.
@@ -47,273 +10,10 @@ def self.type
47
10
"powershell"
48
11
end
49
12
50
- def initialize ( *args )
51
- self . platform ||= ""
52
- self . arch ||= ""
53
- super
54
- end
55
-
56
13
#
57
14
# Returns the session description.
58
15
#
59
16
def desc
60
17
"Powershell session"
61
18
end
62
-
63
- #
64
- # Explicitly runs a command.
65
- #
66
- def run_cmd ( cmd )
67
- shell_command ( cmd )
68
- end
69
-
70
- #
71
- # Calls the class method.
72
- #
73
- def type
74
- self . class . type
75
- end
76
-
77
- ##
78
- # :category: Msf::Session::Provider::SingleCommandShell implementors
79
- #
80
- # The shell will have been initialized by default.
81
- #
82
- def shell_init
83
- return true
84
- end
85
-
86
- ##
87
- # :category: Msf::Session::Provider::SingleCommandShell implementors
88
- #
89
- # Explicitly run a single command, return the output.
90
- #
91
- def shell_command ( cmd )
92
- # Send the command to the session's stdin.
93
- shell_write ( cmd + "\n " )
94
-
95
- timeo = 5
96
- etime = ::Time . now . to_f + timeo
97
- buff = ""
98
-
99
- # Keep reading data until no more data is available or the timeout is
100
- # reached.
101
- while ( ::Time . now . to_f < etime and ( self . respond_to? ( :ring ) or ::IO . select ( [ rstream ] , nil , nil , timeo ) ) )
102
- res = shell_read ( -1 , 0.01 )
103
- buff << res if res
104
- timeo = etime - ::Time . now . to_f
105
- end
106
-
107
- buff
108
- end
109
-
110
- ##
111
- # :category: Msf::Session::Provider::SingleCommandShell implementors
112
- #
113
- # Read from the command shell.
114
- #
115
- def shell_read ( length = -1 , timeout = 1 )
116
- return shell_read_ring ( length , timeout ) if self . respond_to? ( :ring )
117
-
118
- begin
119
- rv = rstream . get_once ( length , timeout )
120
- framework . events . on_session_output ( self , rv ) if rv
121
- return rv
122
- rescue ::Rex ::SocketError , ::EOFError , ::IOError , ::Errno ::EPIPE => e
123
- #print_error("Socket error: #{e.class}: #{e}")
124
- shell_close
125
- raise e
126
- end
127
- end
128
-
129
- #
130
- # Read from the command shell.
131
- #
132
- def shell_read_ring ( length = -1 , timeout = 1 )
133
- self . ring_buff ||= ""
134
-
135
- # Short-circuit bad length values
136
- return "" if length == 0
137
-
138
- # Return data from the stored buffer if available
139
- if self . ring_buff . length >= length and length > 0
140
- buff = self . ring_buff . slice! ( 0 , length )
141
- return buff
142
- end
143
-
144
- buff = self . ring_buff
145
- self . ring_buff = ""
146
-
147
- begin
148
- ::Timeout . timeout ( timeout ) do
149
- while ( ( length > 0 and buff . length < length ) or ( length == -1 and buff . length == 0 ) )
150
- ring . select
151
- nseq , data = ring . read_data ( self . ring_seq )
152
- if data
153
- self . ring_seq = nseq
154
- buff << data
155
- end
156
- end
157
- end
158
- rescue ::Timeout ::Error
159
- rescue ::Rex ::SocketError , ::EOFError , ::IOError , ::Errno ::EPIPE => e
160
- shell_close
161
- raise e
162
- end
163
-
164
- # Store any leftovers in the ring buffer backlog
165
- if length > 0 and buff . length > length
166
- self . ring_buff = buff [ length , buff . length - length ]
167
- buff = buff [ 0 , length ]
168
- end
169
-
170
- buff
171
- end
172
-
173
- ##
174
- # :category: Msf::Session::Provider::SingleCommandShell implementors
175
- #
176
- # Writes to the command shell.
177
- #
178
- def shell_write ( buf )
179
- return if not buf
180
-
181
- begin
182
- framework . events . on_session_command ( self , buf . strip )
183
- rstream . write ( buf )
184
- rescue ::Rex ::SocketError , ::EOFError , ::IOError , ::Errno ::EPIPE => e
185
- #print_error("Socket error: #{e.class}: #{e}")
186
- shell_close
187
- raise e
188
- end
189
- end
190
-
191
- ##
192
- # :category: Msf::Session::Provider::SingleCommandShell implementors
193
- #
194
- # Closes the shell.
195
- #
196
- def shell_close ( )
197
- rstream . close rescue nil
198
- self . kill
199
- end
200
-
201
- #
202
- # Execute any specified auto-run scripts for this session
203
- #
204
- def process_autoruns ( datastore )
205
- # Read the initial output and mash it into a single line
206
- if ( not self . info or self . info . empty? )
207
- initial_output = shell_read ( -1 , 0.01 )
208
- if ( initial_output )
209
- initial_output . force_encoding ( "ASCII-8BIT" ) if initial_output . respond_to? ( :force_encoding )
210
- initial_output . gsub! ( /[\x00 -\x08 \x0b \x0c \x0e -\x19 \x7f -\xff ]+/n , "_" )
211
- initial_output . gsub! ( /[\r \n \t ]+/ , ' ' )
212
- initial_output . strip!
213
-
214
- # Set the inital output to .info
215
- self . info = initial_output
216
- end
217
- end
218
-
219
- if ( datastore [ 'InitialAutoRunScript' ] && datastore [ 'InitialAutoRunScript' ] . empty? == false )
220
- args = Shellwords . shellwords ( datastore [ 'InitialAutoRunScript' ] )
221
- print_status ( "Session ID #{ sid } (#{ tunnel_to_s } ) processing InitialAutoRunScript '#{ datastore [ 'InitialAutoRunScript' ] } '" )
222
- execute_script ( args . shift , *args )
223
- end
224
-
225
- if ( datastore [ 'AutoRunScript' ] && datastore [ 'AutoRunScript' ] . empty? == false )
226
- args = Shellwords . shellwords ( datastore [ 'AutoRunScript' ] )
227
- print_status ( "Session ID #{ sid } (#{ tunnel_to_s } ) processing AutoRunScript '#{ datastore [ 'AutoRunScript' ] } '" )
228
- execute_script ( args . shift , *args )
229
- end
230
- end
231
-
232
- def reset_ring_sequence
233
- self . ring_seq = 0
234
- end
235
-
236
- attr_accessor :arch
237
- attr_accessor :platform
238
-
239
- protected
240
-
241
- ##
242
- # :category: Msf::Session::Interactive implementors
243
- #
244
- # Override the basic session interaction to use shell_read and
245
- # shell_write instead of operating on rstream directly.
246
- def _interact
247
- framework . events . on_session_interact ( self )
248
- if self . respond_to? ( :ring )
249
- _interact_ring
250
- else
251
- _interact_stream
252
- end
253
- end
254
-
255
- ##
256
- # :category: Msf::Session::Interactive implementors
257
- #
258
- def _interact_stream
259
- fds = [ rstream . fd , user_input . fd ]
260
- while self . interacting
261
- sd = Rex ::ThreadSafe . select ( fds , nil , fds , 0.5 )
262
- next if not sd
263
-
264
- if sd [ 0 ] . include? rstream . fd
265
- user_output . print ( shell_read )
266
- end
267
- if sd [ 0 ] . include? user_input . fd
268
- shell_write ( user_input . gets )
269
- end
270
- Thread . pass
271
- end
272
- end
273
-
274
- def _interact_ring
275
-
276
- begin
277
-
278
- rdr = framework . threads . spawn ( "RingMonitor" , false ) do
279
- seq = nil
280
- while self . interacting
281
-
282
- # Look for any pending data from the remote ring
283
- nseq , data = ring . read_data ( seq )
284
-
285
- # Update the sequence number if necessary
286
- seq = nseq || seq
287
-
288
- # Write output to the local stream if successful
289
- user_output . print ( data ) if data
290
-
291
- begin
292
- # Wait for new data to arrive on this session
293
- ring . wait ( seq )
294
- rescue EOFError => e
295
- break
296
- end
297
- end
298
- end
299
-
300
- while self . interacting
301
- # Look for any pending input or errors from the local stream
302
- sd = Rex ::ThreadSafe . select ( [ _local_fd ] , nil , [ _local_fd ] , 5.0 )
303
-
304
- # Write input to the ring's input mechanism
305
- shell_write ( user_input . gets ) if sd
306
- end
307
-
308
- ensure
309
- rdr . kill
310
- end
311
- end
312
-
313
- attr_accessor :ring_seq # This tracks the last seen ring buffer sequence (for shell_read)
314
- attr_accessor :ring_buff # This tracks left over read data to maintain a compatible API
315
- end
316
-
317
19
end
318
- end
319
-
0 commit comments