Permalink
Browse files

Land #10888, Fix Net::SSH::CommandStream session open failure

  • Loading branch information...
busterb committed Nov 5, 2018
2 parents 9235c1b + e9b3502 commit cb229411bc62fcedec749645d8a3cc432c3abc39
@@ -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) >
@@ -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 @@ module PeerInfo
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 @@ def shell_requested(channel, success)
self.rsock.write(data)
channel[:extended_data] << data
end
self.channel = channel
end
def initialize(ssh, cmd = nil, pty: false, cleanup: false)
@@ -52,51 +48,51 @@ def initialize(ssh, cmd = nil, pty: false, cleanup: false)
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.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
end
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]}"
channel = rssh.open_channel do |rch|
# A PTY will write us to {u,w}tmp and lastlog
rch.request_pty if rpty
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
if rcmd.nil?
rch.send_channel_request('shell', &method(:shell_requested))
else
rch.exec(rcmd, &method(:shell_requested))
end
end
channel.on_open_failed do |ch, code, desc|
raise Net::SSH::ChannelOpenFailed.new(code, 'Session channel open failed')
end
while true
rssh.process(0.5) { true }
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
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
if !rcmd.nil? && rcleanup
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 @@ def cleanup
end
end
end
end
@@ -130,19 +130,19 @@ def run_host(ip)
# 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
case action.name
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

0 comments on commit cb22941

Please sign in to comment.