Skip to content

Commit 1cc167a

Browse files
committed
Inserted ARCH_X86 payloads, removed interactive_powershell and updated base powershell session
1 parent 4cb1a6c commit 1cc167a

File tree

6 files changed

+190
-383
lines changed

6 files changed

+190
-383
lines changed

lib/msf/base/sessions/powershell.rb

Lines changed: 2 additions & 302 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,7 @@
11
# -*- coding: binary -*-
2-
require 'msf/base'
3-
require 'msf/base/sessions/scriptable'
4-
require 'shellwords'
2+
require 'msf/base/sessions/command_shell'
53

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
425

436
#
447
# Returns the type of session.
@@ -47,273 +10,10 @@ def self.type
4710
"powershell"
4811
end
4912

50-
def initialize(*args)
51-
self.platform ||= ""
52-
self.arch ||= ""
53-
super
54-
end
55-
5613
#
5714
# Returns the session description.
5815
#
5916
def desc
6017
"Powershell session"
6118
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-
31719
end
318-
end
319-

lib/msf/ui/console/command_dispatcher/core.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,10 +1915,6 @@ def cmd_sessions(*args)
19151915
session.init_ui(driver.input, driver.output)
19161916
session.execute_script('post/multi/manage/shell_to_meterpreter')
19171917
session.reset_ui
1918-
elsif session.type == 'powershell'
1919-
session.init_ui(driver.input, driver.output)
1920-
session.execute_script('post/multi/manage/shell_to_meterpreter')
1921-
session.reset_ui
19221918
else
19231919
print_error("Session #{sess_id} is not a command shell session, skipping...")
19241920
next

0 commit comments

Comments
 (0)