metasploit-framework/lib/msf/core/exploit/tcp.rb

460 lines
8.9 KiB
Ruby

module Msf
# this module provides instance methods to be used in overloading to do single byte sending of data
module SmallSend
def write(buf, opts = {})
warn "smallsend write"
tsent = 0; bidx = 0
if self._send_size == nil or self._send_size == 0
self._send_size = 1
end
while (bidx < buf.length)
str = buf[bidx, _send_size]
sent = super(str, opts)
bidx += sent if sent > 0
tsent += sent
if self.is_a?(SlowSend)
sleep(self._send_delay)
else
sleep(0)
end
end
return tsent
end
attr_accessor :_send_size
end
# this module provides instance mehtods to be used in overloading of Socket to insert delays inbetween each write
module SlowSend
def write(buf, opts = {})
warn 'slowsend write'
if !self.is_a?(SmallSend)
sleep(_send_delay)
end
response = super(buf, opts)
return response
end
attr_accessor :_send_delay
end
###
#
# This module provides methods for establish a connection to a remote host and
# communicating with it.
#
###
module Exploit::Remote::Tcp
#
# Initializes an instance of an exploit module that exploits a
# vulnerability in a TCP server.
#
def initialize(info = {})
super
register_options(
[
Opt::RHOST,
Opt::RPORT
], Msf::Exploit::Remote::Tcp
)
register_advanced_options(
[
Opt::SSL,
Opt::Proxies,
Opt::CPORT,
Opt::CHOST,
OptInt.new('ConnectTimeout', [ true, 'Maximum number of seconds to establish a TCP connection', 10])
], Msf::Exploit::Remote::Tcp
)
register_evasion_options(
[
OptInt.new('TCP::max_send_size', [false, 'Maxiumum tcp segment size. (0 = disable)', 0]),
OptInt.new('TCP::send_delay', [false, 'Delays inserted before every send. (0 = disable)', 0])
], Msf::Exploit::Remote::Tcp
)
end
#
# Establishes a TCP connection to the specified RHOST/RPORT
#
def connect(global = true, opts={})
nsock = Rex::Socket::Tcp.create(
'PeerHost' => opts['RHOST'] || rhost,
'PeerPort' => (opts['RPORT'] || rport).to_i,
'LocalHost' => opts['CHOST'] || chost || "0.0.0.0",
'LocalPort' => (opts['CPORT'] || cport || 0).to_i,
'SSL' => ssl,
'Proxies' => proxies,
'Timeout' => (opts['ConnectTimeout'] || connect_timeout || 10).to_i,
'Context' =>
{
'Msf' => framework,
'MsfExploit' => self,
})
# enable evasions on this socket
# XXX implement evasions!!!!
# evasions(nsock)
# Set this socket to the global socket as necessary
self.sock = nsock if (global)
# Add this socket to the list of sockets created by this exploit
sockets << nsock
return nsock
end
def handler(nsock = self.sock)
# If the handler claims the socket, then we don't want it to get closed
# during cleanup
if ((rv = super) == Handler::Claimed)
if (nsock == self.sock)
self.sock = nil
end
# Remove this socket from the list of sockets so that it will not be
# aborted.
sockets.delete(nsock)
end
return rv
end
#
# Closes the TCP connection
#
def disconnect(nsock = self.sock)
begin
if (nsock)
nsock.shutdown
nsock.close
end
rescue IOError
end
if (nsock == sock)
self.sock = nil
end
# Remove this socket from the list of sockets created by this exploit
sockets.delete(nsock)
end
#
# Performs cleanup, disconnects the socket if necessary
#
def cleanup
super
disconnect
end
##
#
# Wrappers for getters
#
##
#
# Returns the target host
#
def rhost
datastore['RHOST']
end
#
# Returns the remote port
#
def rport
datastore['RPORT']
end
#
# Returns the local host
#
def lhost
datastore['LHOST']
end
#
# Returns the local port
#
def lport
datastore['LPORT']
end
#
# Returns the local host for outgoing connections
#
def chost
datastore['CHOST']
end
#
# Returns the local port for outgoing connections
#
def cport
datastore['CPORT']
end
#
# Returns the boolean indicating SSL
#
def ssl
datastore['SSL']
end
#
# Returns the proxy configuration
#
def proxies
datastore['Proxies']
end
#
# Returns the TCP connection timeout
#
def connect_timeout
datastore['ConnectTimeout']
end
protected
attr_accessor :sock
end
###
#
# This mixin provides a generic interface for running a TCP server of some
# sort that is designed to exploit clients. Exploits that include this mixin
# automatically take a passive stance.
#
###
module Exploit::Remote::TcpServer
def initialize(info = {})
super(update_info(info,
'Stance' => Msf::Exploit::Stance::Passive))
register_options(
[
Opt::SSL,
OptAddress.new('SRVHOST', [ true, "The local host to listen on.", '0.0.0.0' ]),
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 8080 ]),
], Msf::Exploit::Remote::TcpServer)
register_evasion_options(
[
OptInt.new('TCP::max_send_size', [false, 'Maximum tcp segment size. (0 = disable)', 0]),
OptInt.new('TCP::send_delay', [false, 'Delays inserted before every send. (0 = disable)', 0])
], Msf::Exploit::Remote::Tcp
)
end
#
# This mixin overrides the exploit method so that it can initiate the
# service that corresponds with what the client has requested.
#
def exploit
start_service()
print_status("Server started.")
# Call the exploit primer
primer
# Wait on the service to stop
self.service.wait
end
#
# Primer method to call after starting service but before handling connections
#
def primer
end
#
# Stops the service, if one was created.
#
def cleanup
if(service)
stop_service()
print_status("Server stopped.")
end
end
#
# Called when a client connects.
#
def on_client_connect(client)
end
#
# Called when a client has data available for reading.
#
def on_client_data(client)
end
#
# Called when a client has disconnected.
#
def on_client_close(client)
end
#
# Starts the service.
#
def start_service(*args)
begin
self.service = Rex::Socket::TcpServer.create(
'LocalHost' => srvhost,
'LocalPort' => srvport,
'SSL' => ssl,
'Context' =>
{
'Msf' => framework,
'MsfExploit' => self,
})
self.service.on_client_connect_proc = Proc.new { |client|
on_client_connect(client)
}
self.service.on_client_data_proc = Proc.new { |client|
on_client_data(client)
}
self.service.on_client_close_proc = Proc.new { |client|
on_client_close(client)
}
# Start the listening service
self.service.start
rescue ::Errno::EACCES => e
if (srvport.to_i < 1024)
print_line(" ")
print_error("Could not start the TCP server: #{e.to_s}.")
print_error(
"This module is configured to use a privileged TCP port (#{srvport}). " +
"On Unix systems, only the root user account is allowed to bind to privileged ports." +
"Please run the framework as root to use this module."
)
print_error(
"On Microsoft Windows systems, this error is returned when a process attempts to "+
"listen on a host/port combination that is already in use. For example, Windows XP "+
"will return this error if a process attempts to bind() over the system SMB/NetBIOS services."
)
print_line(" ")
end
raise e
end
end
#
# Stops the service.
#
def stop_service
if (service)
begin
self.service.deref if self.service.kind_of?(Rex::Service)
self.service.close if self.service.kind_of?(Rex::Socket)
self.service = nil
rescue ::Exception
end
end
end
# Enable evasions on a given client
def evasions(socket)
# XXX - oooogly
return if socket.instance_variables.member?('@tcp_evasion')
if !socket.is_a?(SmallSend) and datastore['TCP::max_send_size'] > 0
socket.extend(SmallSend)
socket._send_size = datastore['TCP::max_send_size']
end
if !socket.is_a?(SlowSend) and datastore['TCP::send_delay'] > 0
socket.extend(SlowSend)
socket._send_delay = datastore['TCP::send_delay']
end
socket.instance_eval('@tcp_evasion = 1')
end
#
# Returns the local host that is being listened on.
#
def srvhost
datastore['SRVHOST']
end
#
# Returns the local port that is being listened on.
#
def srvport
datastore['SRVPORT']
end
#
# Returns the SSL option
#
def ssl
datastore['SSL']
end
#
# Re-generates the payload, substituting the current RHOST and RPORT with
# the supplied client host and port from the socket.
#
def regenerate_payload(cli, arch = nil, platform = nil, target = nil)
ohost = datastore['RHOST']
oport = datastore['RPORT']
p = nil
begin
# Update the datastore with the supplied client peerhost/peerport
datastore['RHOST'] = cli.peerhost
datastore['RPORT'] = cli.peerport
if ((p = super(arch, platform, target)) == nil)
print_error("Failed to generate payload")
return nil
end
# Allow the payload to start a new handler
add_handler({
'RHOST' => datastore['RHOST'],
'RPORT' => datastore['RPORT']
})
ensure
datastore['RHOST'] = ohost
datastore['RPORT'] = oport
end
p
end
protected
attr_accessor :service # :nodoc:
end
end