Skip to content

Commit

Permalink
Land #19656 Close ssh session on error
Browse files Browse the repository at this point in the history
  • Loading branch information
jheysel-r7 authored Dec 12, 2024
2 parents 31930f4 + 566e12b commit c7f7cfd
Show file tree
Hide file tree
Showing 24 changed files with 60 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def desc
end

def bootstrap(datastore = {}, handler = nil)
@ssh_command_stream = Net::SSH::CommandStream.new(ssh_connection)
@ssh_command_stream = Net::SSH::CommandStream.new(ssh_connection, session: self, logger: self)

@ssh_command_stream.verify_channel
# set remote_window_size to 32 which seems to help stability
Expand Down
2 changes: 1 addition & 1 deletion lib/msf/base/sessions/ssh_command_shell_bind.rb
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def bootstrap(datastore = {}, handler = nil)
# shells accessed through SSH may respond to the echo command issued for verification as expected
datastore['AutoVerifySession'] &= @platform.blank?

@rstream = Net::SSH::CommandStream.new(ssh_connection).lsock
@rstream = Net::SSH::CommandStream.new(ssh_connection, session: self, logger: self).lsock
super

@info = "SSH #{username} @ #{@peer_info}"
Expand Down
51 changes: 37 additions & 14 deletions lib/net/ssh/command_stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class Net::SSH::CommandStream

attr_accessor :channel, :thread, :error, :ssh
attr_accessor :channel, :thread, :error, :ssh, :session, :logger
attr_accessor :lsock, :rsock, :monitor

module PeerInfo
Expand All @@ -13,7 +13,8 @@ module PeerInfo

def shell_requested(channel, success)
unless success
raise Net::SSH::ChannelRequestFailed, 'Shell/exec channel request failed'
error = Net::SSH::ChannelRequestFailed.new('Shell/exec channel request failed')
handle_error(error: error)
end

self.channel = channel
Expand All @@ -40,7 +41,9 @@ def shell_requested(channel, success)
end
end

def initialize(ssh, cmd = nil, pty: false, cleanup: false)
def initialize(ssh, cmd = nil, pty: false, cleanup: false, session: nil, logger: nil)
self.session = session
self.logger = logger
self.lsock, self.rsock = Rex::Socket.tcp_socket_pair()
self.lsock.extend(Rex::IO::Stream)
self.lsock.extend(PeerInfo)
Expand Down Expand Up @@ -74,31 +77,40 @@ def initialize(ssh, cmd = nil, pty: false, cleanup: false)
end

channel.on_open_failed do |ch, code, desc|
raise Net::SSH::ChannelOpenFailed.new(code, 'Session channel open failed')
error = Net::SSH::ChannelOpenFailed.new(code, 'Session channel open failed')
handle_error(error: error)
end

self.monitor = Thread.new do
while(true)
next if not self.rsock.has_read_data?(1.0)
buff = self.rsock.read(16384)
break if not buff
verify_channel
self.channel.send_data(buff) if buff
begin
Kernel.loop do
next if not self.rsock.has_read_data?(1.0)

buff = self.rsock.read(16384)
break if not buff

verify_channel
self.channel.send_data(buff) if buff
end
rescue ::StandardError => e
handle_error(error: e)
end
end

while true
rssh.process(0.5) { true }
begin
Kernel.loop { rssh.process(0.5) { true } }
rescue ::StandardError => e
handle_error(error: e)
end

# Shut down the SSH session if requested
if !rcmd.nil? && rcleanup
rssh.close
end
end
rescue ::Exception => e
rescue ::StandardError => e
# XXX: This won't be set UNTIL there's a failure from a thread
self.error = e
handle_error(error: e)
ensure
self.monitor.kill if self.monitor
end
Expand All @@ -113,7 +125,18 @@ def verify_channel
end
end

def handle_error(error: nil)
self.error = error if error

if self.logger
self.logger.print_error("SSH Command Stream encountered an error: #{self.error} (Server Version: #{self.ssh.transport.server_version.version})")
end

cleanup
end

def cleanup
self.session.alive = false if self.session
self.monitor.kill
self.lsock.close rescue nil
self.rsock.close rescue nil
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/scanner/ssh/eaton_xpert_backdoor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def run_host(ip)
info: version
)

shell = Net::SSH::CommandStream.new(ssh)
shell = Net::SSH::CommandStream.new(ssh, logger: self)

# XXX: Wait for CommandStream to log a channel request failure
sleep 0.1
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/scanner/ssh/fortinet_backdoor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def run_host(ip)
info: version
)

shell = Net::SSH::CommandStream.new(ssh)
shell = Net::SSH::CommandStream.new(ssh, logger: self)

# XXX: Wait for CommandStream to log a channel request failure
sleep 0.1
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/scanner/ssh/libssh_auth_bypass.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def run_host(ip)
info: version
)

shell = Net::SSH::CommandStream.new(ssh, datastore['CMD'], pty: datastore['SPAWN_PTY'])
shell = Net::SSH::CommandStream.new(ssh, datastore['CMD'], pty: datastore['SPAWN_PTY'], logger: self)

# XXX: Wait for CommandStream to log a channel request failure
sleep 0.1
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/apple_ios/ssh/cydia_default_ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def do_login(user, pass)
end

if ssh
conn = Net::SSH::CommandStream.new(ssh)
conn = Net::SSH::CommandStream.new(ssh, logger: self)
ssh = nil
return conn
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def ssh_login
end

if ssh
Net::SSH::CommandStream.new(ssh)
Net::SSH::CommandStream.new(ssh, logger: self)
end
end

Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/http/ubiquiti_airos_file_upload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def ssh_login
private: private_key,
private_type: :ssh_key
)
return Net::SSH::CommandStream.new(ssh)
return Net::SSH::CommandStream.new(ssh, logger: self)
end

nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def do_login(user)
if ssh_socket

# Create a new session from the socket, then dump it.
conn = Net::SSH::CommandStream.new(ssh_socket)
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
ssh_socket = nil

return conn
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/cisco_ucs_scpuser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def do_login(user, pass)
end

if ssh
conn = Net::SSH::CommandStream.new(ssh)
conn = Net::SSH::CommandStream.new(ssh, logger: self)
ssh = nil
return conn
end
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/exagrid_known_privkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def do_login(ssh_options)
if ssh_socket

# Create a new session from the socket, then dump it.
conn = Net::SSH::CommandStream.new(ssh_socket)
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
ssh_socket = nil

return conn
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/f5_bigip_known_privkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def do_login(user)
return false unless ssh_socket

# Create a new session from the socket, then dump it.
conn = Net::SSH::CommandStream.new(ssh_socket)
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
ssh_socket = nil
conn
end
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/ibm_drm_a3user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def do_login(user, pass)
fail_with(Failure::Unknown, "#{peer} SSH Error: #{e.class} : #{e.message}")
end

return Net::SSH::CommandStream.new(ssh) if ssh
return Net::SSH::CommandStream.new(ssh, logger: self) if ssh

nil
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def do_login(user)
if ssh_socket

# Create a new session from the socket, then dump it.
conn = Net::SSH::CommandStream.new(ssh_socket)
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
ssh_socket = nil

return conn
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/microfocus_obr_shrboadmin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def do_login(user, pass)
end

if ssh
conn = Net::SSH::CommandStream.new(ssh)
conn = Net::SSH::CommandStream.new(ssh, logger: self)
ssh = nil
return conn
end
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/quantum_dxi_known_privkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def do_login(user)
if ssh_socket

# Create a new session from the socket, then dump it.
conn = Net::SSH::CommandStream.new(ssh_socket)
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
ssh_socket = nil

return conn
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/quantum_vmpro_backdoor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def do_login(user, pass)
end

if ssh
conn = Net::SSH::CommandStream.new(ssh, 'shell-escape')
conn = Net::SSH::CommandStream.new(ssh, 'shell-escape', logger: self)
return conn
end

Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/symantec_smg_ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def do_login(user, pass)
end

if ssh
conn = Net::SSH::CommandStream.new(ssh)
conn = Net::SSH::CommandStream.new(ssh, logger: self)
ssh = nil
return conn
end
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def do_login
if ssh_socket

# Create a new session from the socket, then dump it.
conn = Net::SSH::CommandStream.new(ssh_socket)
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
sockets.delete(ssh_socket.transport.socket)

return conn
Expand Down
2 changes: 1 addition & 1 deletion modules/exploits/linux/ssh/vmware_vrni_known_privkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def do_login(user, key_data)

if ssh_socket
# Create a new session from the socket, then close it.
conn = Net::SSH::CommandStream.new(ssh_socket)
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
ssh_socket = nil

return conn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def do_login
print_error "#{rhost}:22 SSH Error: #{e.class} : #{e.message}"
end
if ssh
conn = Net::SSH::CommandStream.new(ssh)
conn = Net::SSH::CommandStream.new(ssh, logger: self)
return conn
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,6 @@ def exploit

# Make the SSH connection and execute our commands + payload
print_status("#{rhost}:#{rport} - Sending and executing payload to gain root privileges!")
Net::SSH::CommandStream.new(ssh, build_command)
Net::SSH::CommandStream.new(ssh, build_command, logger: self)
end
end
2 changes: 1 addition & 1 deletion modules/exploits/unix/ssh/tectia_passwd_changereq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def userauth_passwd_change(user, transport, connection)
message = transport.next_message.type

if message.to_i == 6 #SSH2_MSG_SERVICE_ACCEPT
shell = Net::SSH::CommandStream.new(connection)
shell = Net::SSH::CommandStream.new(connection, logger: self)
connection = nil
return shell
end
Expand Down

0 comments on commit c7f7cfd

Please sign in to comment.