Skip to content

Commit ef1d4dd

Browse files
author
RageLtMan
committed
Add UDP handlers and payloads (redux)
This is a repackaging effort for the work i originally pushed in 6035. This segment of the PR provides UDP session handlers for bind and reverse sessions, a Windows Metasm stager (really the TCP stager with a small change), and a pair of socat payloads for testing simple UDP shells. Netcat or any scripting language with a sockets library is sufficient to use these sessions as they are stateless and simple. Testing of this PR requires rex/core #1 and rex/socket #2 The SSL testing which was being done on 6035 is backed out, left for a later time when we can do DTLS properly.
1 parent 03d1523 commit ef1d4dd

File tree

8 files changed

+786
-2
lines changed

8 files changed

+786
-2
lines changed

lib/msf/core/handler/bind_udp.rb

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# -*- coding: binary -*-
2+
module Msf
3+
module Handler
4+
5+
###
6+
#
7+
# This module implements the Bind TCP handler. This means that
8+
# it will attempt to connect to a remote host on a given port for a period of
9+
# time (typically the duration of an exploit) to see if a the payload has
10+
# started listening. This can tend to be rather verbose in terms of traffic
11+
# and in general it is preferable to use reverse payloads.
12+
#
13+
###
14+
module BindUdp
15+
16+
include Msf::Handler
17+
18+
#
19+
# Returns the handler specific string representation, in this case
20+
# 'bind_tcp'.
21+
#
22+
def self.handler_type
23+
return "bind_udp"
24+
end
25+
26+
#
27+
# Returns the connection oriented general handler type, in this case bind.
28+
#
29+
def self.general_handler_type
30+
"bind"
31+
end
32+
33+
#
34+
# Initializes a bind handler and adds the options common to all bind
35+
# payloads, such as local port.
36+
#
37+
def initialize(info = {})
38+
super
39+
40+
register_options(
41+
[
42+
Opt::LPORT(4444),
43+
OptAddress.new('RHOST', [false, 'The target address', '']),
44+
], Msf::Handler::BindUdp)
45+
46+
self.conn_threads = []
47+
self.listener_threads = []
48+
self.listener_pairs = {}
49+
end
50+
51+
#
52+
# Kills off the connection threads if there are any hanging around.
53+
#
54+
def cleanup_handler
55+
# Kill any remaining handle_connection threads that might
56+
# be hanging around
57+
conn_threads.each { |thr|
58+
thr.kill
59+
}
60+
end
61+
62+
#
63+
# Starts a new connecting thread
64+
#
65+
def add_handler(opts={})
66+
67+
# Merge the updated datastore values
68+
opts.each_pair do |k,v|
69+
datastore[k] = v
70+
end
71+
72+
# Start a new handler
73+
start_handler
74+
end
75+
76+
#
77+
# Starts monitoring for an outbound connection to become established.
78+
#
79+
def start_handler
80+
81+
# Maximum number of seconds to run the handler
82+
ctimeout = 150
83+
84+
if (exploit_config and exploit_config['active_timeout'])
85+
ctimeout = exploit_config['active_timeout'].to_i
86+
end
87+
88+
# Take a copy of the datastore options
89+
rhost = datastore['RHOST']
90+
lport = datastore['LPORT']
91+
92+
# Ignore this if one of the required options is missing
93+
return if not rhost
94+
return if not lport
95+
96+
# Only try the same host/port combination once
97+
phash = rhost + ':' + lport.to_s
98+
return if self.listener_pairs[phash]
99+
self.listener_pairs[phash] = true
100+
101+
# Start a new handling thread
102+
self.listener_threads << framework.threads.spawn("BindUdpHandlerListener-#{lport}", false) {
103+
client = nil
104+
105+
print_status("Started bind handler")
106+
107+
if (rhost == nil)
108+
raise ArgumentError,
109+
"RHOST is not defined; bind stager cannot function.",
110+
caller
111+
end
112+
113+
stime = Time.now.to_i
114+
115+
while (stime + ctimeout > Time.now.to_i)
116+
begin
117+
client = Rex::Socket::Udp.create(
118+
'PeerHost' => rhost,
119+
'PeerPort' => lport.to_i,
120+
'Proxies' => datastore['Proxies'],
121+
'Context' =>
122+
{
123+
'Msf' => framework,
124+
'MsfPayload' => self,
125+
'MsfExploit' => assoc_exploit
126+
})
127+
rescue Rex::ConnectionRefused
128+
# Connection refused is a-okay
129+
rescue ::Exception
130+
wlog("Exception caught in bind handler: #{$!.class} #{$!}")
131+
end
132+
133+
client.extend(Rex::IO::Stream)
134+
break if client
135+
136+
# Wait a second before trying again
137+
Rex::ThreadSafe.sleep(0.5)
138+
end
139+
140+
# Valid client connection?
141+
if (client)
142+
# Increment the has connection counter
143+
self.pending_connections += 1
144+
145+
# Timeout and datastore options need to be passed through to the client
146+
opts = {
147+
:datastore => datastore,
148+
:expiration => datastore['SessionExpirationTimeout'].to_i,
149+
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
150+
:retry_total => datastore['SessionRetryTotal'].to_i,
151+
:retry_wait => datastore['SessionRetryWait'].to_i,
152+
:udp_session => true
153+
}
154+
155+
# Start a new thread and pass the client connection
156+
# as the input and output pipe. Client's are expected
157+
# to implement the Stream interface.
158+
conn_threads << framework.threads.spawn("BindUdpHandlerSession", false, client) { |client_copy|
159+
begin
160+
handle_connection(client_copy, opts)
161+
rescue
162+
elog("Exception raised from BindUdp.handle_connection: #{$!}")
163+
end
164+
}
165+
else
166+
wlog("No connection received before the handler completed")
167+
end
168+
}
169+
end
170+
171+
#
172+
# Nothing to speak of.
173+
#
174+
def stop_handler
175+
# Stop the listener threads
176+
self.listener_threads.each do |t|
177+
t.kill
178+
end
179+
self.listener_threads = []
180+
self.listener_pairs = {}
181+
end
182+
183+
protected
184+
185+
attr_accessor :conn_threads # :nodoc:
186+
attr_accessor :listener_threads # :nodoc:
187+
attr_accessor :listener_pairs # :nodoc:
188+
end
189+
190+
end
191+
end

0 commit comments

Comments
 (0)