diff --git a/documentation/modules/auxiliary/scanner/ssh/libssh_auth_bypass.md b/documentation/modules/auxiliary/scanner/ssh/libssh_auth_bypass.md index bcfe0a5f50..8b5bfe6bb2 100644 --- a/documentation/modules/auxiliary/scanner/ssh/libssh_auth_bypass.md +++ b/documentation/modules/auxiliary/scanner/ssh/libssh_auth_bypass.md @@ -122,7 +122,14 @@ msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > run [*] 172.28.128.3:2222 - Attempting authentication bypass [+] 172.28.128.3:2222 - SSH-2.0-libssh_0.8.3 appears to be unpatched -[-] 172.28.128.3:2222 - shell/exec channel request failed +[-] 172.28.128.3:2222 - Net::SSH::ChannelOpenFailed: Session channel open failed (1) +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > run + +[*] 172.28.128.3:2222 - Attempting authentication bypass +[+] 172.28.128.3:2222 - SSH-2.0-libssh_0.8.3 appears to be unpatched +[-] 172.28.128.3:2222 - Net::SSH::ChannelRequestFailed: Shell/exec channel request failed [*] Scanned 1 of 1 hosts (100% complete) [*] Auxiliary module execution completed msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > diff --git a/lib/net/ssh/command_stream.rb b/lib/net/ssh/command_stream.rb index 79008a57b5..f8835fb28f 100644 --- a/lib/net/ssh/command_stream.rb +++ b/lib/net/ssh/command_stream.rb @@ -1,10 +1,6 @@ # -*- coding: binary -*- -require 'rex' -module Net -module SSH - -class CommandStream +class Net::SSH::CommandStream attr_accessor :channel, :thread, :error, :ssh attr_accessor :lsock, :rsock, :monitor @@ -17,9 +13,11 @@ class CommandStream def shell_requested(channel, success) unless success - raise Net::SSH::ChannelRequestFailed, 'shell/exec channel request failed' + raise Net::SSH::ChannelRequestFailed, 'Shell/exec channel request failed' end + self.channel = channel + channel[:data] = '' channel[:extended_data] = '' @@ -40,8 +38,6 @@ class CommandStream self.rsock.write(data) channel[:extended_data] << data end - - self.channel = channel end def initialize(ssh, cmd = nil, pty: false, cleanup: false) @@ -52,44 +48,39 @@ class CommandStream self.ssh = ssh self.thread = Thread.new(ssh, cmd, pty, cleanup) do |rssh, rcmd, rpty, rcleanup| - begin - info = rssh.transport.socket.getpeername_as_array - self.lsock.peerinfo = "#{info[1]}:#{info[2]}" + info = rssh.transport.socket.getpeername_as_array + self.lsock.peerinfo = "#{info[1]}:#{info[2]}" - info = rssh.transport.socket.getsockname - self.lsock.localinfo = "#{info[1]}:#{info[2]}" + info = rssh.transport.socket.getsockname + self.lsock.localinfo = "#{info[1]}:#{info[2]}" - rssh.open_channel do |rch| - # A PTY will write us to {u,w}tmp and lastlog - rch.request_pty if rpty - if rcmd.nil? - rch.send_channel_request('shell', &method(:shell_requested)) - else - rch.exec(rcmd, &method(:shell_requested)) - end + channel = rssh.open_channel do |rch| + # A PTY will write us to {u,w}tmp and lastlog + rch.request_pty if rpty + + if rcmd.nil? + rch.send_channel_request('shell', &method(:shell_requested)) + else + rch.exec(rcmd, &method(:shell_requested)) end + 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 - end + channel.on_open_failed do |ch, code, desc| + raise Net::SSH::ChannelOpenFailed.new(code, 'Session channel open failed') + 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 end + end - while true - rssh.process(0.5) { true } - end - - rescue ::Exception => e - # XXX: This won't be set UNTIL there's a failure from a thread - self.error = e - #::Kernel.warn "BOO: #{e.inspect}" - #::Kernel.warn e.backtrace.join("\n") - ensure - self.monitor.kill if self.monitor + while true + rssh.process(0.5) { true } end # Shut down the SSH session if requested @@ -97,6 +88,11 @@ class CommandStream rssh.close end end + rescue ::Exception => e + # XXX: This won't be set UNTIL there's a failure from a thread + self.error = e + ensure + self.monitor.kill if self.monitor end # @@ -118,6 +114,3 @@ class CommandStream end end -end -end - diff --git a/modules/auxiliary/scanner/ssh/libssh_auth_bypass.rb b/modules/auxiliary/scanner/ssh/libssh_auth_bypass.rb index 7cdcbcbe9b..7200414cc1 100644 --- a/modules/auxiliary/scanner/ssh/libssh_auth_bypass.rb +++ b/modules/auxiliary/scanner/ssh/libssh_auth_bypass.rb @@ -130,8 +130,8 @@ class MetasploitModule < Msf::Auxiliary # XXX: Wait for CommandStream to log a channel request failure sleep 0.1 - if shell.error - print_error("#{ip}:#{rport} - #{shell.error}") + if (e = shell.error) + print_error("#{ip}:#{rport} - #{e.class}: #{e.message}") return end @@ -139,10 +139,10 @@ class MetasploitModule < Msf::Auxiliary when 'Shell' start_session(self, "#{self.name} (#{version})", {}, false, shell.lsock) when 'Execute' - output = shell.channel[:data].chomp + output = shell.channel && (shell.channel[:data] || '').chomp if output.blank? - print_error("Empty or blank output: #{datastore['CMD']}") + print_error("#{ip}:#{rport} - Empty or blank command output") return end