Refactor cmd_shell and add cmd_shell_{help,tabs}
parent
cfbd259e80
commit
4a759fd048
|
@ -22,7 +22,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
#
|
||||
@@execute_opts = Rex::Parser::Arguments.new(
|
||||
"-a" => [ true, "The arguments to pass to the command." ],
|
||||
"-c" => [ false, "Channelized I/O (required for interaction)." ],
|
||||
"-c" => [ false, "Channelized I/O (required for interaction)." ], # -i sets -c
|
||||
"-f" => [ true, "The executable command to run." ],
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-H" => [ false, "Create the process hidden from view." ],
|
||||
|
@ -33,6 +33,14 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"-k" => [ false, "Execute process on the meterpreters current desktop" ],
|
||||
"-s" => [ true, "Execute process in a given session as the session user" ])
|
||||
|
||||
#
|
||||
# Options used by the 'shell' command.
|
||||
#
|
||||
@@shell_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-l" => [ false, "List available shells (/etc/shells)." ],
|
||||
"-t" => [ true, "Spawn a PTY shell (/bin/bash if no argument given)." ]) # ssh(1) -t
|
||||
|
||||
#
|
||||
# Options used by the 'reboot' command.
|
||||
#
|
||||
|
@ -40,15 +48,6 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"-h" => [ false, "Help menu." ],
|
||||
"-f" => [ true, "Force a reboot, valid values [1|2]" ])
|
||||
|
||||
#
|
||||
# Options used by the 'shell' command.
|
||||
#
|
||||
@@shell_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-b" => [ false, "Spawn bash PTY shell. (/bin/bash)" ],
|
||||
"-l" => [ false, "List available shells. (Linux, OSX, BSD)" ],
|
||||
"-s" => [ true, "Spawn alternative PTY shell. (E.g. /bin/zsh)" ])
|
||||
|
||||
#
|
||||
# Options used by the 'shutdown' command.
|
||||
#
|
||||
|
@ -258,111 +257,148 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
[]
|
||||
end
|
||||
|
||||
def cmd_shell_help
|
||||
print_line 'Usage: shell [options]'
|
||||
print_line
|
||||
print_line 'Opens an interactive native shell.'
|
||||
print_line @@shell_opts.usage
|
||||
end
|
||||
|
||||
def cmd_shell_tabs(str, words)
|
||||
return @@shell_opts.fmt.keys if words.length == 1
|
||||
[]
|
||||
end
|
||||
|
||||
#
|
||||
# Drop into a system shell as specified by %COMSPEC% or
|
||||
# as appropriate for the host.
|
||||
#
|
||||
def cmd_shell(*args)
|
||||
use_alt = false
|
||||
alt_path = ""
|
||||
use_pty = false
|
||||
sh_path = '/bin/bash'
|
||||
|
||||
@@shell_opts.parse(args) { |opt, idx, val|
|
||||
@@shell_opts.parse(args) do |opt, idx, val|
|
||||
case opt
|
||||
when "-h"
|
||||
print(
|
||||
"Usage: shell [options]\n\n" +
|
||||
"Opens an interactive native shell.\n" +
|
||||
@@shell_opts.usage)
|
||||
return true
|
||||
when "-b"
|
||||
use_alt = true
|
||||
alt_path = "/bin/bash"
|
||||
when "-s"
|
||||
use_alt = true
|
||||
alt_path = val
|
||||
if (alt_path == "")
|
||||
print_error("You must specify a shell path with -s")
|
||||
return true
|
||||
when '-h'
|
||||
cmd_shell_help
|
||||
return true
|
||||
when '-l'
|
||||
return false unless client.fs.file.exist?('/etc/shells')
|
||||
|
||||
begin
|
||||
client.fs.file.open('/etc/shells') do |f|
|
||||
print(f.read) until f.eof
|
||||
end
|
||||
when "-l"
|
||||
if client.fs.file.exist?('/etc/shells')
|
||||
fd = client.fs.file.new("/etc/shells", "rb")
|
||||
begin
|
||||
until fd.eof?
|
||||
print(fd.read)
|
||||
end
|
||||
rescue EOFError
|
||||
end
|
||||
fd.close
|
||||
end
|
||||
return true
|
||||
rescue
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
when '-t'
|
||||
use_pty = true
|
||||
# XXX: No other options must follow
|
||||
sh_path = val if val
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
case client.platform
|
||||
when 'windows'
|
||||
path = client.fs.file.expand_path("%COMSPEC%")
|
||||
path = (path and not path.empty?) ? path : "cmd.exe"
|
||||
path = client.fs.file.expand_path('%COMSPEC%')
|
||||
path = (path && !path.empty?) ? path : 'cmd.exe'
|
||||
|
||||
# attempt the shell with thread impersonation
|
||||
begin
|
||||
cmd_execute("-f", path, "-c", "-H", "-i", "-t")
|
||||
cmd_execute('-f', path, '-c', '-i', '-H', '-t')
|
||||
rescue
|
||||
# if this fails, then we attempt without impersonation
|
||||
print_error( "Failed to spawn shell with thread impersonation. Retrying without it." )
|
||||
cmd_execute("-f", path, "-c", "-H", "-i")
|
||||
print_error('Failed to spawn shell with thread impersonation. Retrying without it.')
|
||||
cmd_execute('-f', path, '-c', '-i', '-H')
|
||||
end
|
||||
when 'linux', 'osx'
|
||||
if use_pty && pty_shell(sh_path)
|
||||
return true
|
||||
end
|
||||
|
||||
# Don't expand_path() this because it's literal anyway
|
||||
if use_alt
|
||||
return true if alt_shell(alt_path)
|
||||
end
|
||||
path = "/bin/sh"
|
||||
cmd_execute("-f", path, "-c", "-i")
|
||||
cmd_execute('-f', '/bin/sh', '-c', '-i')
|
||||
else
|
||||
# Then this is a multi-platform meterpreter (php or java), which
|
||||
# Then this is a multi-platform meterpreter (e.g., php or java), which
|
||||
# must special-case COMSPEC to return the system-specific shell.
|
||||
path = client.fs.file.expand_path("%COMSPEC%")
|
||||
path = client.fs.file.expand_path('%COMSPEC%')
|
||||
|
||||
# If that failed for whatever reason, guess it's unix
|
||||
path = (path and not path.empty?) ? path : "/bin/sh"
|
||||
if use_alt && path == "/bin/sh"
|
||||
return true if alt_shell(alt_path)
|
||||
path = (path && !path.empty?) ? path : '/bin/sh'
|
||||
|
||||
if use_pty && path == '/bin/sh' && pty_shell(sh_path)
|
||||
return true
|
||||
end
|
||||
cmd_execute("-f", path, "-c", "-i")
|
||||
|
||||
cmd_execute('-f', comspec, '-c', '-i')
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Spawn an alternative shell
|
||||
# Spawn a PTY shell
|
||||
#
|
||||
def alt_shell(sh_path)
|
||||
def pty_shell(sh_path)
|
||||
sh_path = client.fs.file.exist?(sh_path) ? sh_path : '/bin/sh'
|
||||
|
||||
# Python Meterpreter calls pty.openpty() - No need for other methods
|
||||
if client.session_type =~ /python/
|
||||
cmd_execute('-if', sh_path)
|
||||
if client.arch == 'python'
|
||||
cmd_execute('-f', sh_path, '-c', '-i')
|
||||
return true
|
||||
end
|
||||
|
||||
# Check for the following in /usr{,/local}/bin:
|
||||
# script
|
||||
# python{,2,3}
|
||||
# socat
|
||||
# expect
|
||||
paths = %w[
|
||||
/usr/bin/script
|
||||
/usr/bin/python
|
||||
/usr/local/bin/python
|
||||
/usr/bin/python2
|
||||
/usr/local/bin/python2
|
||||
/usr/bin/python3
|
||||
/usr/local/bin/python3
|
||||
/usr/bin/socat
|
||||
/usr/local/bin/socat
|
||||
/usr/bin/expect
|
||||
/usr/local/bin/expect
|
||||
]
|
||||
|
||||
# Select method for spawning PTY Shell based on availability on the target.
|
||||
path = nil
|
||||
path = '/usr/bin/socat' if client.fs.file.exist?('/usr/bin/socat')
|
||||
path = '/usr/bin/script' if client.fs.file.exist?('/usr/bin/script') && !path
|
||||
path = '/usr/bin/python' if client.fs.file.exist?('/usr/bin/python') && !path
|
||||
path = '/usr/bin/python2' if client.fs.file.exist?('/usr/bin/python2') && !path
|
||||
path = '/usr/bin/python3' if client.fs.file.exist?('/usr/bin/python3') && !path
|
||||
path = '/usr/bin/expect' if client.fs.file.exist?('/usr/bin/expect') && !path
|
||||
path = paths.find { |p| client.fs.file.exist?(p) }
|
||||
|
||||
return false unless path
|
||||
|
||||
# Commands for methods - "env TERM=xterm" provides colors, "clear" command, etc. as available on the target.
|
||||
cmd = "env TERM=xterm #{path} - exec:'#{sh_path} -li',pty,stderr,setsid,sigint,sane" if path =~ /socat/
|
||||
cmd = "env TERM=xterm #{path} -qc #{sh_path} /dev/null || #{path} -q /dev/null #{sh_path}" if path =~ /script/
|
||||
cmd = "env TERM=xterm #{path} -c \'import pty;pty.spawn(\"#{sh_path}\")\'" if path =~ /python/
|
||||
cmd = "env TERM=xterm #{path} -c 'spawn #{sh_path}; interact'" if path =~ /expect/
|
||||
cmd_execute('-if', cmd)
|
||||
# Commands for methods
|
||||
cmd =
|
||||
case path
|
||||
when /script/
|
||||
if client.platform == 'linux'
|
||||
"#{path} -qc #{sh_path} /dev/null"
|
||||
else
|
||||
# script(1) invocation for BSD, OS X, etc.
|
||||
"#{path} -q /dev/null #{sh_path}"
|
||||
end
|
||||
when /python/
|
||||
"#{path} -c 'import pty; pty.spawn(\"#{sh_path}\")'"
|
||||
when /socat/
|
||||
# sigint isn't passed through yet
|
||||
"#{path} - exec:#{sh_path},pty,sane,setsid,sigint,stderr"
|
||||
when /expect/
|
||||
"#{path} -c 'spawn #{sh_path}; interact'"
|
||||
end
|
||||
|
||||
# "env TERM=xterm" provides colors, "clear" command, etc. as available on the target.
|
||||
cmd.prepend('env TERM=xterm HISTFILE= ')
|
||||
|
||||
print_status(cmd)
|
||||
cmd_execute('-f', cmd, '-c', '-i')
|
||||
|
||||
true
|
||||
rescue
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue