Files
metasploit-gs/lib/msf/base/sessions/ssh_command_shell.rb
T
RageLtMan c339662fed SshCommandSession and Ruby Payloads
Implement a command-only session type over the HrrRbSsh client
Connection Channels' file descriptors, adjust from base command
session to deal with the separate reader/writer IOs. Technically,
a TTY session works out of the box here as well.

Implement a pair of showcase Ruby payloads using net/ssh to call
back to the handler, create a shell channel, and loop piping I/O
between framework session and client via the Ruby backtick exec.

Next Steps:
  Command payloads need to be written for every major interpreted
language as well as some sort of bashism a la openssl_double if
it comes to that, but preferably single socket implementation.

Testing:
  Very minimal, needs a good run through by the community and R7
2019-06-23 05:20:04 -04:00

77 lines
1.5 KiB
Ruby

# -*- coding: binary -*-
require 'msf/base/sessions/command_shell'
module Msf::Sessions
###
#
# This class provides basic interaction with a ChannelFD
# abstraction provided by the Rex::Proto::Ssh wrapper
# around HrrRbSsh.
#
# Date: June 22, 2019
# Author: RageLtMan
#
###
class SshCommandShell < Msf::Sessions::CommandShell
#
# This interface supports basic interaction.
#
include Msf::Session::Basic
#
# This interface supports interacting with a single command shell.
#
include Msf::Session::Provider::SingleCommandShell
##
#
# Returns the session description.
#
def desc
"SSH command shell"
end
def shell_command(cmd)
# Send the command to the session's stdin.
shell_write(cmd + "\n")
timeo = 0.5
etime = ::Time.now.to_f + timeo
buff = ""
# Keep reading data until no more data is available or the timeout is
# reached.
while (::Time.now.to_f < etime and ::IO.select([rstream.fd_rd], nil, nil, timeo))
res = shell_read(-1, 0.01)
buff << res if res
timeo = etime - ::Time.now.to_f
end
buff
end
protected
def _interact_stream
fdr = [rstream.fd_rd, user_input.fd]
fdw = [rstream.fd_wr, user_input.fd]
while self.interacting
sd = Rex::ThreadSafe.select(fdr, nil, fdw, 0.5)
next unless sd
if sd[0].include? rstream.fd_rd
user_output.print(shell_read)
end
if sd[0].include? user_input.fd
run_single((user_input.gets || '').chomp("\n"))
end
Thread.pass
end
end
end
end