Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close ssh session on error #19656

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading