f0b24339fe
Create the Rex::Proto::Ssh namespace and implement hrr_rb_ssh objects in the Rex namespace with Rex' sockets stack, permissive default connection options to accept any authentication, ACLs for port forwarding, and a modified Connection #initialize method for simplified instantiation. The actual Rex::Proto::Ssh::Server object follow standard Rex semantics for services to permit use in handlers, exploits, and auxiliary modules in the same manner as the Http::Server is used today. This work is far from complete - the HrrRbSsh low-level objects should be decomposed into Rex' pattern as they currently depend heavily on their own Procs and Threads internally which use the parent Connection object's attributes to look up which Proc should be called in response to a Channel or Authentication request. This is a bit difficult to do piecemeal given the intertwined data and execution dependency inside of HrrRbSsh. Next steps: 1. Create handler and reverse_ssh command session payloads 1a. POSIX systems generally have SSH already 1b. Windows Powershell is likely able to hotload SSH libs as a pre-stager. 1c. Other interpreted runtimes usually have client-ssh libraries 2. Implement options parsing, handling, etc for user-customizable functionality from the Msf namespace. 3. Use libssh2 to permit mettle use of the SSH transport. 3a. Bother @OJ about doing the same for Windows Meterpreter. 3b. Bother @zeroSteiner to implement SSH transport for PyMeterp. 3c. Ask @timwr and @mihi how viable this is for Android/Java. 3d. See if @OJ will do this for CLR-meterp on a livestream. 4. Write a post module which runs this SSH server from a mettle session using the compromised hosts's own host keys and passwd file for "valid" authentication while logging and MITMing the entire command stream remotely - help folks shake off some of the complacency around "secure shells." 5. Write a plugin which will permit sharing of the entire console context, specific acquired sessions, or TCP forwards with the pugin's SSH clients based on the credentials used to connect. 6. Further decompose the server code into Rex to permit writing client fuzzers, loggers, and other tooling to test the posture of SSH client implementations. 7. Work to implement SSH client functionality in HrrRbSsh and convert the rest of Rex/Msf to use this library instead only. 8. Rewrite and import MetaSsh into Metasploit proper using the new Rex::Proto::Ssh code. ----- Huge thanks to @hirura for writing HrrRbSsh. I've spent countless hours on and off working to implement server-side semantics in net/ssh years ago and it was becoming a pretty full rewrite due to the ordering of server/client req/resp messages and who sent what to whom. This library is a much much cleaner implementation and provides full, modern SSH servers in pure Ruby.
121 lines
2.6 KiB
Ruby
121 lines
2.6 KiB
Ruby
# -*- coding: binary -*-
|
|
require 'rex/socket'
|
|
require 'thread'
|
|
require 'msf/core/handler/reverse_tcp'
|
|
|
|
module Msf
|
|
module Handler
|
|
|
|
###
|
|
#
|
|
# This handler implements the SSH tunneling interface.
|
|
#
|
|
###
|
|
module ReverseSsh
|
|
|
|
include Msf::Handler::ReverseTcp
|
|
|
|
#
|
|
# Returns the string representation of the handler type
|
|
#
|
|
def self.handler_type
|
|
return 'reverse_ssh'
|
|
end
|
|
|
|
#
|
|
# Returns the connection-described general handler type, in this case
|
|
# 'tunnel'.
|
|
#
|
|
def self.general_handler_type
|
|
"tunnel"
|
|
end
|
|
|
|
# Initializes the reverse SSH handler and ads the options that are required
|
|
# for all reverse SSH payloads, like version string and auth params.
|
|
#
|
|
def initialize(info = {})
|
|
super
|
|
register_advanced_options(
|
|
[
|
|
OptString.new('Ssh::Version', [
|
|
true,
|
|
'The SSH version string to provide',
|
|
Rex::Proto::Ssh::Connection.default_options['local_version']
|
|
])
|
|
], Msf::Handler::ReverseSsh
|
|
)
|
|
end
|
|
|
|
# A URI describing where we are listening
|
|
#
|
|
# @param addr [String] the address that
|
|
# @return [String] A URI of the form +ssh://host:port/+
|
|
def listener_uri(addr=datastore['ReverseListenerBindAddress'])
|
|
addr = datastore['LHOST'] if addr.nil? || addr.empty?
|
|
uri_host = Rex::Socket.is_ipv6?(addr) ? "[#{addr}]" : addr
|
|
"ssh://#{uri_host}:#{bind_port}"
|
|
end
|
|
|
|
# Create an Ssh listener
|
|
#
|
|
# @return [void]
|
|
def setup_handler
|
|
|
|
local_addr = nil
|
|
local_port = bind_port
|
|
ex = false
|
|
|
|
ssh_opts = Rex::Proto::Ssh::Connection.default_options
|
|
ssh_opts['local_version'] = datastore['Ssh::Version']
|
|
|
|
# Start the SSH server service on this host/port
|
|
bind_addresses.each do |ip|
|
|
begin
|
|
self.service = Rex::ServiceManager.start(Rex::Proto::Ssh::Server,
|
|
local_port, ip,
|
|
{
|
|
'Msf' => framework,
|
|
'MsfExploit' => self,
|
|
},
|
|
comm,
|
|
ssh_opts
|
|
)
|
|
local_addr = ip
|
|
rescue
|
|
ex = $!
|
|
print_error("Handler failed to bind to #{ip}:#{local_port}")
|
|
else
|
|
ex = false
|
|
break
|
|
end
|
|
end
|
|
|
|
raise ex if (ex)
|
|
|
|
print_status("Started SSH reverse handler on #{listener_uri(local_addr)}")
|
|
|
|
if datastore['IgnoreUnknownPayloads']
|
|
print_status("Handler is ignoring unknown payloads")
|
|
end
|
|
end
|
|
|
|
# Stops the handler & service
|
|
#
|
|
# @return [void]
|
|
def stop_handler
|
|
if self.service
|
|
if self.sessions == 0
|
|
Rex::ServiceManager.stop_service(self.service)
|
|
end
|
|
end
|
|
end
|
|
|
|
attr_accessor :service # :nodoc:
|
|
|
|
protected
|
|
|
|
|
|
end
|
|
end
|
|
end
|