mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-12 11:52:01 +01:00
Commit the Ruby end for TCP server channels, the modified TCP client channels and the support for pivoting a reverse_tcp meterpreter.
git-svn-id: file:///home/svn/framework3/trunk@8384 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
a80d1ad2ee
commit
fd2469db24
@ -1,3 +1,5 @@
|
||||
require 'rex/socket'
|
||||
|
||||
module Msf
|
||||
module Handler
|
||||
|
||||
@ -67,28 +69,38 @@ module ReverseTcp
|
||||
ex = false
|
||||
# Switch to IPv6 ANY address if the LHOST is also IPv6
|
||||
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
|
||||
# First attempt to bind ANY_ADDR. If that fails, the user probably has
|
||||
# something else listening on one interface. Try again with the
|
||||
# specific LHOST. Use the any addr for whatever LHOST was, ipv4 or 6.
|
||||
# First attempt to bind LHOST. If that fails, the user probably has
|
||||
# something else listening on that interface. Try again with ANY_ADDR.
|
||||
any = (addr.length == 4) ? "0.0.0.0" : "::0"
|
||||
[ any, Rex::Socket.addr_ntoa(addr) ].each { |ip|
|
||||
[ Rex::Socket.addr_ntoa(addr), any ].each { |ip|
|
||||
begin
|
||||
print_status("Handler trying to bind to #{ip}") if ip != any
|
||||
|
||||
self.listener_sock = Rex::Socket::TcpServer.create(
|
||||
'LocalHost' => ip,
|
||||
'LocalPort' => datastore['LPORT'].to_i,
|
||||
'Comm' => comm,
|
||||
'Context' =>
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfPayload' => self,
|
||||
'MsfExploit' => assoc_exploit
|
||||
})
|
||||
|
||||
ex = false
|
||||
|
||||
comm_used = Rex::Socket::SwitchBoard.best_comm( ip )
|
||||
comm_used = Rex::Socket::Comm::Local if comm_used == nil
|
||||
|
||||
if( comm_used.respond_to?( :type ) and comm_used.respond_to?( :sid ) )
|
||||
via = "via the #{comm_used.type} on session #{comm_used.sid}"
|
||||
else
|
||||
via = ""
|
||||
end
|
||||
|
||||
print_status("Started reverse handler on #{ip}:#{datastore['LPORT']} #{via}")
|
||||
break
|
||||
rescue
|
||||
ex = $!
|
||||
print_error("Handler failed to bind to #{ip}")
|
||||
print_error("Handler failed to bind to #{ip}:#{datastore['LPORT']}")
|
||||
end
|
||||
}
|
||||
raise ex if (ex)
|
||||
@ -114,8 +126,6 @@ module ReverseTcp
|
||||
self.listener_thread = Thread.new {
|
||||
client = nil
|
||||
|
||||
print_status("Started reverse handler on port #{datastore['LPORT']}")
|
||||
|
||||
begin
|
||||
# Accept a client connection
|
||||
begin
|
||||
|
@ -32,22 +32,26 @@ module Stream
|
||||
# of, at most, 32768 bytes.
|
||||
#
|
||||
def write(buf, opts = {})
|
||||
tsent = 0
|
||||
bidx = 0
|
||||
|
||||
total_sent = 0
|
||||
total_length = buf.length
|
||||
begin
|
||||
while (bidx < buf.length)
|
||||
sent = fd.syswrite(buf[bidx, 32768])
|
||||
bidx += sent if sent > 0
|
||||
tsent += sent
|
||||
while( total_sent < total_length )
|
||||
s = Rex::ThreadSafe.select( nil, [ fd ], nil, 0.2 )
|
||||
if( s == nil || s[0] == nil )
|
||||
next
|
||||
end
|
||||
data = buf[0, 32768]
|
||||
sent = fd.syswrite( data )
|
||||
if sent > 0
|
||||
total_sent += sent
|
||||
buf[0, sent] = ""
|
||||
end
|
||||
end
|
||||
rescue ::IOError, ::Errno::EPIPE
|
||||
return nil if (fd.abortive_close == true)
|
||||
|
||||
raise $!
|
||||
end
|
||||
|
||||
tsent
|
||||
total_sent
|
||||
end
|
||||
|
||||
#
|
||||
@ -90,7 +94,7 @@ module Stream
|
||||
#
|
||||
def fd
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
@ -290,7 +294,7 @@ module Stream
|
||||
# This flag indicates whether or not an abortive close has been issued.
|
||||
#
|
||||
attr_accessor :abortive_close
|
||||
|
||||
|
||||
protected
|
||||
|
||||
end
|
||||
|
@ -4,6 +4,7 @@ require 'thread'
|
||||
require 'rex/socket'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/tlv'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel'
|
||||
require 'rex/logging'
|
||||
|
||||
module Rex
|
||||
@ -31,23 +32,21 @@ class Socket
|
||||
##
|
||||
|
||||
#
|
||||
# Initialize the socket subsystem and start monitoring sockets
|
||||
# as they come in.
|
||||
# Initialize the socket subsystem and start monitoring sockets as they come in.
|
||||
#
|
||||
def initialize(client)
|
||||
self.client = client
|
||||
self.monitored_sockets = []
|
||||
self.monitored_socket_channels = {}
|
||||
self.client = client
|
||||
|
||||
# register the inbound handler for the tcp server channel (allowing us to receive new client connections to a tcp server channel)
|
||||
client.register_inbound_handler( Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel )
|
||||
|
||||
# Start monitoring the sockets
|
||||
self.monitor_sockets
|
||||
end
|
||||
|
||||
#
|
||||
# Terminate the monitor thread.
|
||||
# Deregister the inbound handler for the tcp server channel
|
||||
#
|
||||
def shutdown
|
||||
monitor_thread.kill
|
||||
client.deregister_inbound_handler( Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel )
|
||||
end
|
||||
|
||||
##
|
||||
@ -61,39 +60,23 @@ class Socket
|
||||
# supplied in the socket parameters instance. The 'params' argument
|
||||
# is expected to be of type Rex::Socket::Parameters.
|
||||
#
|
||||
def create(params)
|
||||
channel = nil
|
||||
res = nil
|
||||
|
||||
# begin
|
||||
if (params.tcp?)
|
||||
if (params.server?)
|
||||
channel = create_tcp_server(params)
|
||||
else
|
||||
channel = create_tcp_client(params)
|
||||
end
|
||||
|
||||
# Add this channel's right socket to the socket monitor
|
||||
add_monitored_socket(channel.rsock, channel)
|
||||
|
||||
# If we get a valid channel back, create a stream
|
||||
# representation of the left side of the socket for
|
||||
# the caller to use
|
||||
if (channel != nil)
|
||||
res = channel.lsock
|
||||
end
|
||||
elsif (params.udp?)
|
||||
if (params.server?)
|
||||
res = create_udp_server(params)
|
||||
else
|
||||
res = create_udp_client(params)
|
||||
end
|
||||
|
||||
# TODO: Datagram wrapper
|
||||
def create( params )
|
||||
res = nil
|
||||
|
||||
if( params.tcp? )
|
||||
if( params.server? )
|
||||
res = create_tcp_server( params )
|
||||
else
|
||||
res = create_tcp_client( params )
|
||||
end
|
||||
# rescue
|
||||
# end
|
||||
|
||||
elsif( params.udp? )
|
||||
if( params.server? )
|
||||
res = create_udp_server( params )
|
||||
else
|
||||
res = create_udp_client( params )
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
@ -101,6 +84,15 @@ class Socket
|
||||
# Create a TCP server channel.
|
||||
#
|
||||
def create_tcp_server(params)
|
||||
begin
|
||||
return SocketSubsystem::TcpServerChannel.open(client, params)
|
||||
rescue ::Rex::Post::Meterpreter::RequestError => e
|
||||
case e.result
|
||||
when 10000 .. 10100
|
||||
raise ::Rex::ConnectionError.new
|
||||
end
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
@ -108,7 +100,11 @@ class Socket
|
||||
#
|
||||
def create_tcp_client(params)
|
||||
begin
|
||||
return SocketSubsystem::TcpClientChannel.open(client, params)
|
||||
channel = SocketSubsystem::TcpClientChannel.open(client, params)
|
||||
if( channel != nil )
|
||||
return channel.lsock
|
||||
end
|
||||
return nil
|
||||
rescue ::Rex::Post::Meterpreter::RequestError => e
|
||||
case e.result
|
||||
when 10000 .. 10100
|
||||
@ -132,104 +128,6 @@ class Socket
|
||||
|
||||
protected
|
||||
|
||||
##
|
||||
#
|
||||
# Socket monitoring
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Monitors zero or more sockets and handles forwarding traffic
|
||||
# to the remote half of the associated channel.
|
||||
#
|
||||
def monitor_sockets
|
||||
self.monitor_thread = ::Thread.new {
|
||||
|
||||
loop do
|
||||
|
||||
# Watch for data
|
||||
begin
|
||||
socks = select(monitored_sockets, nil, nil, 0.25)
|
||||
|
||||
rescue StreamClosedError => e
|
||||
channel = monitored_socket_channels[e.stream.object_id]
|
||||
|
||||
dlog("monitor_channels: channel #{channel} closed (#{e.stream})",'meterpreter', LEV_3)
|
||||
|
||||
if (channel)
|
||||
begin
|
||||
channel.close
|
||||
rescue IOError
|
||||
end
|
||||
|
||||
remove_monitored_socket(e.stream)
|
||||
end
|
||||
|
||||
next
|
||||
end
|
||||
|
||||
# No data?
|
||||
if (socks == nil || socks[0] == nil)
|
||||
next
|
||||
end
|
||||
|
||||
# Enumerate through each of the indicated sockets
|
||||
socks[0].each { |sock|
|
||||
channel = monitored_socket_channels[sock.object_id]
|
||||
closed = false
|
||||
data = nil
|
||||
|
||||
if (channel == nil)
|
||||
remove_monitored_socket(sock)
|
||||
|
||||
next
|
||||
end
|
||||
|
||||
begin
|
||||
data = sock.sysread(16384)
|
||||
rescue
|
||||
closed = true
|
||||
end
|
||||
|
||||
if (data == nil)
|
||||
closed = true
|
||||
end
|
||||
|
||||
# If the socket closed, notify the other side and remove
|
||||
# this socket from the monitored socket list
|
||||
if (closed)
|
||||
channel.close_write
|
||||
|
||||
remove_monitored_socket(sock)
|
||||
# Otherwise, write the data to the remote side
|
||||
else
|
||||
channel.write(data)
|
||||
end
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Adds a socket to the list of monitored sockets.
|
||||
#
|
||||
def add_monitored_socket(sock, channel)
|
||||
monitored_sockets << sock
|
||||
monitored_socket_channels[sock.object_id] = channel
|
||||
end
|
||||
|
||||
#
|
||||
# Removes a socket from the list of monitored sockets.
|
||||
#
|
||||
def remove_monitored_socket(sock)
|
||||
monitored_socket_channels.delete(sock.object_id)
|
||||
monitored_sockets.delete(sock)
|
||||
end
|
||||
|
||||
attr_accessor :monitored_sockets, :monitored_socket_channels # :nodoc:
|
||||
attr_accessor :monitor_thread # :nodoc:
|
||||
attr_accessor :client # :nodoc:
|
||||
|
||||
end
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'thread'
|
||||
require 'rex/post/meterpreter/channel'
|
||||
require 'rex/post/meterpreter/channels/stream'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/tlv'
|
||||
|
||||
@ -20,7 +22,13 @@ module SocketSubsystem
|
||||
#
|
||||
###
|
||||
class TcpClientChannel < Rex::Post::Meterpreter::Stream
|
||||
|
||||
|
||||
class << self
|
||||
def cls
|
||||
return CHANNEL_CLASS_STREAM
|
||||
end
|
||||
end
|
||||
|
||||
module SocketInterface
|
||||
def type?
|
||||
'tcp'
|
||||
@ -28,7 +36,6 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
|
||||
|
||||
def getsockname
|
||||
return super if not channel
|
||||
|
||||
# Find the first host in our chain (our address)
|
||||
hops = 0
|
||||
csock = channel.client.sock
|
||||
@ -36,7 +43,6 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
|
||||
csock = csock.channel.client.sock
|
||||
hops += 1
|
||||
end
|
||||
|
||||
tmp,caddr,cport = csock.getsockname
|
||||
tmp,raddr,rport = csock.getpeername
|
||||
maddr,mport = [ channel.params.localhost, channel.params.localport ]
|
||||
@ -52,7 +58,26 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
|
||||
|
||||
attr_accessor :channel
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Simple mixin for lsock in order to help avoid a ruby interpreter issue with ::Socket.pair
|
||||
# Instead of writing to the lsock, reading from the rsock and then writing to the channel,
|
||||
# we use this mixin to directly write to the channel.
|
||||
#
|
||||
# Note: This does not work with OpenSSL as OpenSSL is implemented nativly and requires a real
|
||||
# socket to write to and we cant intercept the sockets syswrite at a native level.
|
||||
#
|
||||
# Note: The deadlock only seems to effect the Ruby build for cygwin.
|
||||
#
|
||||
module DirectChannelWrite
|
||||
|
||||
def syswrite( buf )
|
||||
channel._write( buf )
|
||||
end
|
||||
|
||||
attr_accessor :channel
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# Factory
|
||||
@ -99,15 +124,18 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
|
||||
#
|
||||
# Passes the channel initialization information up to the base class.
|
||||
#
|
||||
def initialize(client, cid, type, flags)
|
||||
super(client, cid, type, flags)
|
||||
def initialize( client, cid, type, flags )
|
||||
super( client, cid, type, flags )
|
||||
|
||||
# Implement some of the required socket interfaces on the local side of
|
||||
# the stream abstraction.
|
||||
lsock.extend(SocketInterface)
|
||||
rsock.extend(SocketInterface)
|
||||
lsock.extend( SocketInterface )
|
||||
lsock.extend( DirectChannelWrite )
|
||||
lsock.channel = self
|
||||
|
||||
rsock.extend( SocketInterface )
|
||||
rsock.channel = self
|
||||
|
||||
monitor_rsock()
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
@ -133,7 +161,67 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
|
||||
response = client.send_request(request)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def monitor_rsock
|
||||
self.monitor_thread = ::Thread.new {
|
||||
loop do
|
||||
closed = false
|
||||
buf = nil
|
||||
|
||||
begin
|
||||
s = Rex::ThreadSafe.select( [ self.rsock ], nil, nil, 0.2 )
|
||||
if( s == nil || s[0] == nil )
|
||||
next
|
||||
end
|
||||
rescue Exception => e
|
||||
closed = true
|
||||
end
|
||||
|
||||
if( closed == false )
|
||||
begin
|
||||
buf = self.rsock.sysread( 32768 )
|
||||
closed = true if( buf == nil )
|
||||
rescue
|
||||
closed = true
|
||||
end
|
||||
end
|
||||
|
||||
if( closed == false )
|
||||
total_sent = 0
|
||||
total_length = buf.length
|
||||
while( total_sent < total_length )
|
||||
begin
|
||||
data = buf[0, buf.length]
|
||||
sent = self.write( data )
|
||||
# sf: Only remove the data off the queue is syswrite was successfull.
|
||||
# This way we naturally perform a resend if a failure occured.
|
||||
# Catches an edge case with meterpreter TCP channels where remote send
|
||||
# failes gracefully and a resend is required.
|
||||
if( sent > 0 )
|
||||
total_sent += sent
|
||||
buf[0, sent] = ""
|
||||
end
|
||||
rescue ::IOError => e
|
||||
closed = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if( closed )
|
||||
self.close_write
|
||||
::Thread.exit
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
}
|
||||
end
|
||||
|
||||
attr_accessor :monitor_thread
|
||||
|
||||
end
|
||||
|
||||
|
@ -0,0 +1,167 @@
|
||||
require 'timeout'
|
||||
require 'thread'
|
||||
require 'rex/socket/parameters'
|
||||
require 'rex/post/meterpreter/channels/stream'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/tlv'
|
||||
require 'rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
module Extensions
|
||||
module Stdapi
|
||||
module Net
|
||||
module SocketSubsystem
|
||||
|
||||
class TcpServerChannel < Rex::Post::Meterpreter::Channel
|
||||
|
||||
#
|
||||
# This is a class variable to store all pending client tcp connections which have not been passed
|
||||
# off via a call to the respective server tcp channels accept method. The dictionary key is the
|
||||
# tcp server channel instance and the values held are an array of pending tcp client channels
|
||||
# connected to the tcp server channel.
|
||||
#
|
||||
@@server_channels = {}
|
||||
|
||||
class << self
|
||||
include Rex::Post::Meterpreter::InboundPacketHandler
|
||||
|
||||
#
|
||||
# This is the request handler which is registerd to the respective meterpreter instance via
|
||||
# Rex::Post::Meterpreter::Extensions::Stdapi::Net::Socket. All incoming requests from the meterpreter
|
||||
# for a 'tcp_channel_open' will be processed here. We create a new TcpClientChannel for each request
|
||||
# received and store it in the respective tcp server channels list of new pending client channels.
|
||||
# These new tcp client channels are passed off via a call the the tcp server channels accept() method.
|
||||
#
|
||||
def request_handler( client, packet )
|
||||
|
||||
if( packet.method == "tcp_channel_open" )
|
||||
|
||||
cid = packet.get_tlv_value( TLV_TYPE_CHANNEL_ID )
|
||||
pid = packet.get_tlv_value( TLV_TYPE_CHANNEL_PARENTID )
|
||||
localhost = packet.get_tlv_value( TLV_TYPE_LOCAL_HOST )
|
||||
localport = packet.get_tlv_value( TLV_TYPE_LOCAL_PORT )
|
||||
peerhost = packet.get_tlv_value( TLV_TYPE_PEER_HOST )
|
||||
peerport = packet.get_tlv_value( TLV_TYPE_PEER_PORT )
|
||||
|
||||
if( cid == nil or pid == nil )
|
||||
return false
|
||||
end
|
||||
|
||||
server_channel = client.find_channel( pid )
|
||||
if( server_channel == nil )
|
||||
return false
|
||||
end
|
||||
|
||||
params = Rex::Socket::Parameters.from_hash(
|
||||
{
|
||||
'Proto' => 'tcp',
|
||||
'LocalHost' => localhost,
|
||||
'LocalPort' => localport,
|
||||
'PeerHost' => peerhost,
|
||||
'PeerPort' => peerport,
|
||||
'Comm' => server_channel.client
|
||||
}
|
||||
)
|
||||
|
||||
client_channel = TcpClientChannel.new( client, cid, TcpClientChannel, CHANNEL_FLAG_SYNCHRONOUS )
|
||||
|
||||
client_channel.params = params
|
||||
|
||||
if( @@server_channels[server_channel] == nil )
|
||||
@@server_channels[server_channel] = []
|
||||
end
|
||||
|
||||
@@server_channels[server_channel] << client_channel
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def cls
|
||||
return CHANNEL_CLASS_STREAM
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Open a new tcp server channel on the remote end.
|
||||
#
|
||||
def TcpServerChannel.open(client, params)
|
||||
c = Channel.create(client, 'stdapi_net_tcp_server', self, CHANNEL_FLAG_SYNCHRONOUS,
|
||||
[
|
||||
{
|
||||
'type' => TLV_TYPE_LOCAL_HOST,
|
||||
'value' => params.localhost
|
||||
},
|
||||
{
|
||||
'type' => TLV_TYPE_LOCAL_PORT,
|
||||
'value' => params.localport
|
||||
}
|
||||
] )
|
||||
c.params = params
|
||||
c
|
||||
end
|
||||
|
||||
#
|
||||
# Simply initilize this instance.
|
||||
#
|
||||
def initialize(client, cid, type, flags)
|
||||
super(client, cid, type, flags)
|
||||
# add this instance to the class variables dictionary of tcp server channels
|
||||
@@server_channels[self] = []
|
||||
end
|
||||
|
||||
#
|
||||
# Accept a new tcp client connection form this tcp server channel. This method does not block
|
||||
# and returns nil if no new client connection is available.
|
||||
#
|
||||
def accept_nonblock
|
||||
result = nil
|
||||
if( @@server_channels[self].length > 0 )
|
||||
channel = @@server_channels[self].shift
|
||||
result = channel.lsock
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
#
|
||||
# Accept a new tcp client connection form this tcp server channel. This method will block indefinatly
|
||||
# if no timeout is specified.
|
||||
#
|
||||
def accept( opts={} )
|
||||
timeout = opts['Timeout'] || -1
|
||||
if( timeout == -1 )
|
||||
result = _accept
|
||||
else
|
||||
begin
|
||||
::Timeout.timeout( timeout ) {
|
||||
result = _accept
|
||||
}
|
||||
rescue Timeout::Error
|
||||
result = nil
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def _accept
|
||||
while( true )
|
||||
if( @@server_channels[self].empty? )
|
||||
Rex::ThreadSafe.sleep( 0.2 )
|
||||
next
|
||||
end
|
||||
result = accept_nonblock
|
||||
break if result != nil
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end; end; end; end; end; end; end
|
||||
|
@ -53,6 +53,7 @@ TLV_TYPE_CHANNEL_TYPE = TLV_META_TYPE_STRING | 51
|
||||
TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52
|
||||
TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53
|
||||
TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54
|
||||
TLV_TYPE_CHANNEL_PARENTID = TLV_META_TYPE_UINT | 55
|
||||
|
||||
TLV_TYPE_SEEK_WHENCE = TLV_META_TYPE_UINT | 70
|
||||
TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71
|
||||
|
@ -1,4 +1,5 @@
|
||||
require 'socket'
|
||||
require 'thread'
|
||||
require 'resolv'
|
||||
require 'rex/exceptions'
|
||||
|
||||
@ -390,23 +391,41 @@ module Socket
|
||||
rescue ::Exception
|
||||
return '127.0.0.1'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# sf: This create a socket pair using native ruby sockets and will work
|
||||
# on Windows where ::Socket.pair is not implemented.
|
||||
# Note: OpenSSL requires native ruby sockets for its io.
|
||||
def self.socket_pair
|
||||
begin
|
||||
pair = ::Socket.pair(::Socket::AF_UNIX, ::Socket::SOCK_STREAM, 0)
|
||||
|
||||
# Windows does not support Socket.pair, so we emulate it
|
||||
rescue ::NotImplementedError
|
||||
srv = TCPServer.new('localhost', 0)
|
||||
rsock = TCPSocket.new(srv.addr[3], srv.addr[1])
|
||||
lsock = srv.accept
|
||||
srv.close
|
||||
[lsock, rsock]
|
||||
end
|
||||
lsock = nil
|
||||
rsock = nil
|
||||
laddr = '127.0.0.1'
|
||||
lport = 0
|
||||
threads = []
|
||||
mutex = ::Mutex.new
|
||||
|
||||
threads << ::Thread.new {
|
||||
server = nil
|
||||
mutex.synchronize {
|
||||
threads << ::Thread.new {
|
||||
mutex.synchronize {
|
||||
rsock = ::TCPSocket.new( laddr, lport )
|
||||
}
|
||||
}
|
||||
server = ::Socket.new( ::Socket::AF_INET, ::Socket::SOCK_STREAM, 0 )
|
||||
server.bind( ::Socket.sockaddr_in( 0, laddr ) )
|
||||
lport, caddr = ::Socket.unpack_sockaddr_in( server.getsockname )
|
||||
server.listen( 1 )
|
||||
}
|
||||
lsock, saddr = server.accept
|
||||
server.close
|
||||
}
|
||||
|
||||
threads.each { |t| t.join }
|
||||
|
||||
return [lsock, rsock]
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
#
|
||||
# Class initialization
|
||||
|
@ -19,6 +19,7 @@ module Rex::Socket::Ip
|
||||
# Creates the client using the supplied hash.
|
||||
#
|
||||
def self.create(hash = {})
|
||||
hash['Proto'] = 'ip'
|
||||
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
||||
end
|
||||
|
||||
@ -28,7 +29,6 @@ module Rex::Socket::Ip
|
||||
#
|
||||
def self.create_param(param)
|
||||
param.proto = 'ip'
|
||||
|
||||
Rex::Socket.create_param(param)
|
||||
end
|
||||
|
||||
|
@ -158,11 +158,17 @@ class Rex::Socket::Parameters
|
||||
|
||||
# The context that was passed in, if any.
|
||||
self.context = hash['Context'] || {}
|
||||
|
||||
|
||||
# If no comm was supplied, try to use the comm that is best fit to
|
||||
# handle the provided host based on the current routing table.
|
||||
if (self.comm == nil and self.peerhost)
|
||||
self.comm = Rex::Socket::SwitchBoard.best_comm(self.peerhost)
|
||||
if( self.server )
|
||||
if (self.comm == nil and self.localhost)
|
||||
self.comm = Rex::Socket::SwitchBoard.best_comm(self.localhost)
|
||||
end
|
||||
else
|
||||
if (self.comm == nil and self.peerhost)
|
||||
self.comm = Rex::Socket::SwitchBoard.best_comm(self.peerhost)
|
||||
end
|
||||
end
|
||||
|
||||
# If we still haven't found a comm, we default to the local comm.
|
||||
|
@ -29,8 +29,9 @@ begin
|
||||
#
|
||||
# Creates an SSL TCP instance.
|
||||
#
|
||||
def self.create(hash)
|
||||
def self.create(hash = {})
|
||||
raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
|
||||
hash['SSL'] = true
|
||||
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
||||
end
|
||||
|
||||
|
@ -27,7 +27,10 @@ module Rex::Socket::SslTcpServer
|
||||
#
|
||||
##
|
||||
|
||||
def self.create(hash)
|
||||
def self.create(hash = {})
|
||||
hash['Proto'] = 'tcp'
|
||||
hash['Server'] = true
|
||||
hash['SSL'] = true
|
||||
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
||||
end
|
||||
|
||||
@ -39,7 +42,6 @@ module Rex::Socket::SslTcpServer
|
||||
param.proto = 'tcp'
|
||||
param.server = true
|
||||
param.ssl = true
|
||||
|
||||
Rex::Socket.create_param(param)
|
||||
end
|
||||
|
||||
|
@ -20,7 +20,8 @@ module Rex::Socket::Tcp
|
||||
#
|
||||
# Creates the client using the supplied hash.
|
||||
#
|
||||
def self.create(hash)
|
||||
def self.create(hash = {})
|
||||
hash['Proto'] = 'tcp'
|
||||
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
||||
end
|
||||
|
||||
@ -30,7 +31,6 @@ module Rex::Socket::Tcp
|
||||
#
|
||||
def self.create_param(param)
|
||||
param.proto = 'tcp'
|
||||
|
||||
Rex::Socket.create_param(param)
|
||||
end
|
||||
|
||||
|
@ -23,7 +23,9 @@ module Rex::Socket::TcpServer
|
||||
#
|
||||
# Creates the server using the supplied hash.
|
||||
#
|
||||
def self.create(hash)
|
||||
def self.create(hash = {})
|
||||
hash['Proto'] = 'tcp'
|
||||
hash['Server'] = true
|
||||
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
||||
end
|
||||
|
||||
@ -34,7 +36,6 @@ module Rex::Socket::TcpServer
|
||||
def self.create_param(param)
|
||||
param.proto = 'tcp'
|
||||
param.server = true
|
||||
|
||||
Rex::Socket.create_param(param)
|
||||
end
|
||||
|
||||
|
@ -19,6 +19,7 @@ module Rex::Socket::Udp
|
||||
# Creates the client using the supplied hash.
|
||||
#
|
||||
def self.create(hash = {})
|
||||
hash['Proto'] = 'udp'
|
||||
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
||||
end
|
||||
|
||||
@ -28,7 +29,6 @@ module Rex::Socket::Udp
|
||||
#
|
||||
def self.create_param(param)
|
||||
param.proto = 'udp'
|
||||
|
||||
Rex::Socket.create_param(param)
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user