Responder/tools/MultiRelay/impacket-dev/impacket/dcerpc/v5/dcomrt.py

1904 lines
65 KiB
Python

# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Author: Alberto Solino (@agsolino)
#
# Description:
# [MS-DCOM] Interface implementation
#
# Best way to learn how to use these calls is to grab the protocol standard
# so you understand what the call does, and then read the test case located
# at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC
#
# Some calls have helper functions, which makes it even easier to use.
# They are located at the end of this file.
# Helper functions start with "h"<name of the call>.
# There are test cases for them too.
#
# ToDo:
# [X] Use the same DCE connection for all the calls. Right now is connecting to the remote machine
# for each call, making it slower.
#
# [X] Implement a ping mechanism, otherwise the garbage collector at the server shuts down the objects if
# not used, returning RPC_E_DISCONNECTED
#
from __future__ import division
from __future__ import print_function
import socket
from struct import pack
from threading import Timer, currentThread
from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRTLSTRUCT, UNKNOWNDATA
from impacket.dcerpc.v5.dtypes import LPWSTR, ULONGLONG, HRESULT, GUID, USHORT, WSTR, DWORD, LPLONG, LONG, PGUID, ULONG, \
UUID, WIDESTR, NULL
from impacket import hresult_errors, LOG
from impacket.uuid import string_to_bin, uuidtup_to_bin, generate
from impacket.dcerpc.v5.rpcrt import TypeSerialization1, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_NONE, \
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_WINNT, DCERPCException
from impacket.dcerpc.v5 import transport
CLSID_ActivationContextInfo = string_to_bin('000001a5-0000-0000-c000-000000000046')
CLSID_ActivationPropertiesIn = string_to_bin('00000338-0000-0000-c000-000000000046')
CLSID_ActivationPropertiesOut = string_to_bin('00000339-0000-0000-c000-000000000046')
CLSID_CONTEXT_EXTENSION = string_to_bin('00000334-0000-0000-c000-000000000046')
CLSID_ContextMarshaler = string_to_bin('0000033b-0000-0000-c000-000000000046')
CLSID_ERROR_EXTENSION = string_to_bin('0000031c-0000-0000-c000-000000000046')
CLSID_ErrorObject = string_to_bin('0000031b-0000-0000-c000-000000000046')
CLSID_InstanceInfo = string_to_bin('000001ad-0000-0000-c000-000000000046')
CLSID_InstantiationInfo = string_to_bin('000001ab-0000-0000-c000-000000000046')
CLSID_PropsOutInfo = string_to_bin('00000339-0000-0000-c000-000000000046')
CLSID_ScmReplyInfo = string_to_bin('000001b6-0000-0000-c000-000000000046')
CLSID_ScmRequestInfo = string_to_bin('000001aa-0000-0000-c000-000000000046')
CLSID_SecurityInfo = string_to_bin('000001a6-0000-0000-c000-000000000046')
CLSID_ServerLocationInfo = string_to_bin('000001a4-0000-0000-c000-000000000046')
CLSID_SpecialSystemProperties = string_to_bin('000001b9-0000-0000-c000-000000000046')
IID_IActivation = uuidtup_to_bin(('4d9f4ab8-7d1c-11cf-861e-0020af6e7c57','0.0'))
IID_IActivationPropertiesIn = uuidtup_to_bin(('000001A2-0000-0000-C000-000000000046','0.0'))
IID_IActivationPropertiesOut = uuidtup_to_bin(('000001A3-0000-0000-C000-000000000046','0.0'))
IID_IContext = uuidtup_to_bin(('000001c0-0000-0000-C000-000000000046','0.0'))
IID_IObjectExporter = uuidtup_to_bin(('99fcfec4-5260-101b-bbcb-00aa0021347a','0.0'))
IID_IRemoteSCMActivator = uuidtup_to_bin(('000001A0-0000-0000-C000-000000000046','0.0'))
IID_IRemUnknown = uuidtup_to_bin(('00000131-0000-0000-C000-000000000046','0.0'))
IID_IRemUnknown2 = uuidtup_to_bin(('00000143-0000-0000-C000-000000000046','0.0'))
IID_IUnknown = uuidtup_to_bin(('00000000-0000-0000-C000-000000000046','0.0'))
IID_IClassFactory = uuidtup_to_bin(('00000001-0000-0000-C000-000000000046','0.0'))
class DCERPCSessionError(DCERPCException):
def __init__(self, error_string=None, error_code=None, packet=None):
DCERPCException.__init__(self, error_string, error_code, packet)
def __str__( self ):
if self.error_code in hresult_errors.ERROR_MESSAGES:
error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0]
error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1]
return 'DCOM SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
else:
return 'DCOM SessionError: unknown error code: 0x%x' % self.error_code
################################################################################
# CONSTANTS
################################################################################
# 2.2.1 OID
OID = ULONGLONG
class OID_ARRAY(NDRUniConformantArray):
item = OID
class POID_ARRAY(NDRPOINTER):
referent = (
('Data', OID_ARRAY),
)
# 2.2.2 SETID
SETID = ULONGLONG
# 2.2.4 error_status_t
error_status_t = ULONG
# 2.2.6 CID
CID = GUID
# 2.2.7 CLSID
CLSID = GUID
# 2.2.8 IID
IID = GUID
PIID = PGUID
# 2.2.9 IPID
IPID = GUID
# 2.2.10 OXID
OXID = ULONGLONG
# 2.2.18 OBJREF
FLAGS_OBJREF_STANDARD = 0x00000001
FLAGS_OBJREF_HANDLER = 0x00000002
FLAGS_OBJREF_CUSTOM = 0x00000004
FLAGS_OBJREF_EXTENDED = 0x00000008
# 2.2.18.1 STDOBJREF
SORF_NOPING = 0x00001000
# 2.2.20 Context
CTXMSHLFLAGS_BYVAL = 0x00000002
# 2.2.20.1 PROPMARSHALHEADER
CPFLAG_PROPAGATE = 0x00000001
CPFLAG_EXPOSE = 0x00000002
CPFLAG_ENVOY = 0x00000004
# 2.2.22.2.1 InstantiationInfoData
ACTVFLAGS_DISABLE_AAA = 0x00000002
ACTVFLAGS_ACTIVATE_32_BIT_SERVER = 0x00000004
ACTVFLAGS_ACTIVATE_64_BIT_SERVER = 0x00000008
ACTVFLAGS_NO_FAILURE_LOG = 0x00000020
# 2.2.22.2.2 SpecialPropertiesData
SPD_FLAG_USE_CONSOLE_SESSION = 0x00000001
# 2.2.28.1 IDL Range Constants
MAX_REQUESTED_INTERFACES = 0x8000
MAX_REQUESTED_PROTSEQS = 0x8000
MIN_ACTPROP_LIMIT = 1
MAX_ACTPROP_LIMIT = 10
################################################################################
# STRUCTURES
################################################################################
class handle_t(NDRSTRUCT):
structure = (
('context_handle_attributes',ULONG),
('context_handle_uuid',UUID),
)
def __init__(self, data=None, isNDR64=False):
NDRSTRUCT.__init__(self, data, isNDR64)
self['context_handle_uuid'] = b'\x00'*16
def isNull(self):
return self['context_handle_uuid'] == b'\x00'*16
# 2.2.11 COMVERSION
class COMVERSION(NDRSTRUCT):
structure = (
('MajorVersion',USHORT),
('MinorVersion',USHORT),
)
def __init__(self, data = None,isNDR64 = False):
NDRSTRUCT.__init__(self, data, isNDR64)
if data is None:
self['MajorVersion'] = 5
self['MinorVersion'] = 7
class PCOMVERSION(NDRPOINTER):
referent = (
('Data', COMVERSION),
)
# 2.2.13.1 ORPC_EXTENT
# This MUST contain an array of bytes that form the extent data.
# The array size MUST be a multiple of 8 for alignment reasons.
class BYTE_ARRAY(NDRUniConformantArray):
item = 'c'
class ORPC_EXTENT(NDRSTRUCT):
structure = (
('id',GUID),
('size',ULONG),
('data',BYTE_ARRAY),
)
# 2.2.13.2 ORPC_EXTENT_ARRAY
# ThisMUSTbeanarrayofORPC_EXTENTs.ThearraysizeMUSTbeamultipleof2for alignment reasons.
class PORPC_EXTENT(NDRPOINTER):
referent = (
('Data', ORPC_EXTENT),
)
class EXTENT_ARRAY(NDRUniConformantArray):
item = PORPC_EXTENT
class PEXTENT_ARRAY(NDRPOINTER):
referent = (
('Data', EXTENT_ARRAY),
)
class ORPC_EXTENT_ARRAY(NDRSTRUCT):
structure = (
('size',ULONG),
('reserved',ULONG),
('extent',PEXTENT_ARRAY),
)
class PORPC_EXTENT_ARRAY(NDRPOINTER):
referent = (
('Data', ORPC_EXTENT_ARRAY),
)
# 2.2.13.3 ORPCTHIS
class ORPCTHIS(NDRSTRUCT):
structure = (
('version',COMVERSION),
('flags',ULONG),
('reserved1',ULONG),
('cid',CID),
('extensions',PORPC_EXTENT_ARRAY),
)
# 2.2.13.4 ORPCTHAT
class ORPCTHAT(NDRSTRUCT):
structure = (
('flags',ULONG),
('extensions',PORPC_EXTENT_ARRAY),
)
# 2.2.14 MInterfacePointer
class MInterfacePointer(NDRSTRUCT):
structure = (
('ulCntData',ULONG),
('abData',BYTE_ARRAY),
)
# 2.2.15 PMInterfacePointerInternal
class PMInterfacePointerInternal(NDRPOINTER):
referent = (
('Data', MInterfacePointer),
)
# 2.2.16 PMInterfacePointer
class PMInterfacePointer(NDRPOINTER):
referent = (
('Data', MInterfacePointer),
)
class PPMInterfacePointer(NDRPOINTER):
referent = (
('Data', PMInterfacePointer),
)
# 2.2.18 OBJREF
class OBJREF(NDRSTRUCT):
commonHdr = (
('signature',ULONG),
('flags',ULONG),
('iid',GUID),
)
def __init__(self, data = None,isNDR64 = False):
NDRSTRUCT.__init__(self, data, isNDR64)
if data is None:
self['signature'] = 0x574F454D
# 2.2.18.1 STDOBJREF
class STDOBJREF(NDRSTRUCT):
structure = (
('flags',ULONG),
('cPublicRefs',ULONG),
('oxid',OXID),
('oid',OID),
('ipid',IPID),
)
# 2.2.18.4 OBJREF_STANDARD
class OBJREF_STANDARD(OBJREF):
structure = (
('std',STDOBJREF),
('saResAddr',':'),
)
def __init__(self, data = None,isNDR64 = False):
OBJREF.__init__(self, data, isNDR64)
if data is None:
self['flags'] = FLAGS_OBJREF_STANDARD
# 2.2.18.5 OBJREF_HANDLER
class OBJREF_HANDLER(OBJREF):
structure = (
('std',STDOBJREF),
('clsid',CLSID),
('saResAddr',':'),
)
def __init__(self, data = None,isNDR64 = False):
OBJREF.__init__(self, data, isNDR64)
if data is None:
self['flags'] = FLAGS_OBJREF_HANDLER
# 2.2.18.6 OBJREF_CUSTOM
class OBJREF_CUSTOM(OBJREF):
structure = (
('clsid',CLSID),
('cbExtension',ULONG),
('ObjectReferenceSize',ULONG),
('pObjectData',':'),
)
def __init__(self, data = None,isNDR64 = False):
OBJREF.__init__(self, data, isNDR64)
if data is None:
self['flags'] = FLAGS_OBJREF_CUSTOM
# 2.2.18.8 DATAELEMENT
class DATAELEMENT(NDRSTRUCT):
structure = (
('dataID',GUID),
('cbSize',ULONG),
('cbRounded',ULONG),
('Data',':'),
)
class DUALSTRINGARRAYPACKED(NDRSTRUCT):
structure = (
('wNumEntries',USHORT),
('wSecurityOffset',USHORT),
('aStringArray',':'),
)
def getDataLen(self, data, offset=0):
return self['wNumEntries']*2
# 2.2.18.7 OBJREF_EXTENDED
class OBJREF_EXTENDED(OBJREF):
structure = (
('std',STDOBJREF),
('Signature1',ULONG),
('saResAddr',DUALSTRINGARRAYPACKED),
('nElms',ULONG),
('Signature2',ULONG),
('ElmArray',DATAELEMENT),
)
def __init__(self, data = None, isNDR64 = False):
OBJREF.__init__(self, data, isNDR64)
if data is None:
self['flags'] = FLAGS_OBJREF_EXTENDED
self['Signature1'] = 0x4E535956
self['Signature1'] = 0x4E535956
self['nElms'] = 0x4E535956
# 2.2.19 DUALSTRINGARRAY
class USHORT_ARRAY(NDRUniConformantArray):
item = '<H'
class PUSHORT_ARRAY(NDRPOINTER):
referent = (
('Data', USHORT_ARRAY),
)
class DUALSTRINGARRAY(NDRSTRUCT):
structure = (
('wNumEntries',USHORT),
('wSecurityOffset',USHORT),
('aStringArray',USHORT_ARRAY),
)
class PDUALSTRINGARRAY(NDRPOINTER):
referent = (
('Data',DUALSTRINGARRAY),
)
# 2.2.19.3 STRINGBINDING
class STRINGBINDING(NDRSTRUCT):
structure = (
('wTowerId',USHORT),
('aNetworkAddr',WIDESTR),
)
# 2.2.19.4 SECURITYBINDING
class SECURITYBINDING(NDRSTRUCT):
structure = (
('wAuthnSvc',USHORT),
('Reserved',USHORT),
('aPrincName',WIDESTR),
)
# 2.2.20.1 PROPMARSHALHEADER
class PROPMARSHALHEADER(NDRSTRUCT):
structure = (
('clsid',CLSID),
('policyId',GUID),
('flags',ULONG),
('cb',ULONG),
('ctxProperty',':'),
)
class PROPMARSHALHEADER_ARRAY(NDRUniConformantArray):
item = PROPMARSHALHEADER
# 2.2.20 Context
class Context(NDRSTRUCT):
structure = (
('MajorVersion',USHORT),
('MinVersion',USHORT),
('ContextId',GUID),
('Flags',ULONG),
('Reserved',ULONG),
('dwNumExtents',ULONG),
('cbExtents',ULONG),
('MshlFlags',ULONG),
('Count',ULONG),
('Frozen',ULONG),
('PropMarshalHeader',PROPMARSHALHEADER_ARRAY),
)
# 2.2.21.3 ErrorInfoString
class ErrorInfoString(NDRSTRUCT):
structure = (
('dwMax',ULONG),
('dwOffSet',ULONG),
('dwActual',IID),
('Name',WSTR),
)
# 2.2.21.2 Custom-Marshaled Error Information Format
class ORPC_ERROR_INFORMATION(NDRSTRUCT):
structure = (
('dwVersion',ULONG),
('dwHelpContext',ULONG),
('iid',IID),
('dwSourceSignature',ULONG),
('Source',ErrorInfoString),
('dwDescriptionSignature',ULONG),
('Description',ErrorInfoString),
('dwHelpFileSignature',ULONG),
('HelpFile',ErrorInfoString),
)
# 2.2.21.5 EntryHeader
class EntryHeader(NDRSTRUCT):
structure = (
('Signature',ULONG),
('cbEHBuffer',ULONG),
('cbSize',ULONG),
('reserved',ULONG),
('policyID',GUID),
)
class EntryHeader_ARRAY(NDRUniConformantArray):
item = EntryHeader
# 2.2.21.4 Context ORPC Extension
class ORPC_CONTEXT(NDRSTRUCT):
structure = (
('SignatureVersion',ULONG),
('Version',ULONG),
('cPolicies',ULONG),
('cbBuffer',ULONG),
('cbSize',ULONG),
('hr',ULONG),
('hrServer',ULONG),
('reserved',ULONG),
('EntryHeader',EntryHeader_ARRAY),
('PolicyData',':'),
)
def __init__(self, data = None, isNDR64 = False):
NDRSTRUCT.__init__(self, data, isNDR64)
if data is None:
self['SignatureVersion'] = 0x414E554B
# 2.2.22.1 CustomHeader
class CLSID_ARRAY(NDRUniConformantArray):
item = CLSID
class PCLSID_ARRAY(NDRPOINTER):
referent = (
('Data', CLSID_ARRAY),
)
class DWORD_ARRAY(NDRUniConformantArray):
item = DWORD
class PDWORD_ARRAY(NDRPOINTER):
referent = (
('Data', DWORD_ARRAY),
)
class CustomHeader(TypeSerialization1):
structure = (
('totalSize',DWORD),
('headerSize',DWORD),
('dwReserved',DWORD),
('destCtx',DWORD),
('cIfs',DWORD),
('classInfoClsid',CLSID),
('pclsid',PCLSID_ARRAY),
('pSizes',PDWORD_ARRAY),
('pdwReserved',LPLONG),
#('pdwReserved',LONG),
)
def getData(self, soFar = 0):
self['headerSize'] = len(TypeSerialization1.getData(self, soFar)) + len(
TypeSerialization1.getDataReferents(self, soFar))
self['cIfs'] = len(self['pclsid'])
return TypeSerialization1.getData(self, soFar)
# 2.2.22 Activation Properties BLOB
class ACTIVATION_BLOB(NDRTLSTRUCT):
structure = (
('dwSize',ULONG),
('dwReserved',ULONG),
('CustomHeader',CustomHeader),
('Property',UNKNOWNDATA),
)
def getData(self, soFar = 0):
self['dwSize'] = len(self['CustomHeader'].getData(soFar)) + len(
self['CustomHeader'].getDataReferents(soFar)) + len(self['Property'])
self['CustomHeader']['totalSize'] = self['dwSize']
return NDRTLSTRUCT.getData(self)
# 2.2.22.2.1 InstantiationInfoData
class IID_ARRAY(NDRUniConformantArray):
item = IID
class PIID_ARRAY(NDRPOINTER):
referent = (
('Data', IID_ARRAY),
)
class InstantiationInfoData(TypeSerialization1):
structure = (
('classId',CLSID),
('classCtx',DWORD),
('actvflags',DWORD),
('fIsSurrogate',LONG),
('cIID',DWORD),
('instFlag',DWORD),
('pIID',PIID_ARRAY),
('thisSize',DWORD),
('clientCOMVersion',COMVERSION),
)
# 2.2.22.2.2 SpecialPropertiesData
class SpecialPropertiesData(TypeSerialization1):
structure = (
('dwSessionId',ULONG),
('fRemoteThisSessionId',LONG),
('fClientImpersonating',LONG),
('fPartitionIDPresent',LONG),
('dwDefaultAuthnLvl',DWORD),
('guidPartition',GUID),
('dwPRTFlags',DWORD),
('dwOrigClsctx',DWORD),
('dwFlags',DWORD),
('Reserved0',DWORD),
('Reserved0',DWORD),
('Reserved', '32s=""'),
#('Reserved1',DWORD),
#('Reserved2',ULONGLONG),
#('Reserved3_1',DWORD),
#('Reserved3_2',DWORD),
#('Reserved3_3',DWORD),
#('Reserved3_4',DWORD),
#('Reserved3_5',DWORD),
)
# 2.2.22.2.3 InstanceInfoData
class InstanceInfoData(TypeSerialization1):
structure = (
('fileName',LPWSTR),
('mode',DWORD),
('ifdROT',PMInterfacePointer),
('ifdStg',PMInterfacePointer),
)
# 2.2.22.2.4.1 customREMOTE_REQUEST_SCM_INFO
class customREMOTE_REQUEST_SCM_INFO(NDRSTRUCT):
structure = (
('ClientImpLevel',DWORD),
('cRequestedProtseqs',USHORT),
('pRequestedProtseqs',PUSHORT_ARRAY),
)
class PcustomREMOTE_REQUEST_SCM_INFO(NDRPOINTER):
referent = (
('Data', customREMOTE_REQUEST_SCM_INFO),
)
# 2.2.22.2.4 ScmRequestInfoData
class ScmRequestInfoData(TypeSerialization1):
structure = (
('pdwReserved',LPLONG),
('remoteRequest',PcustomREMOTE_REQUEST_SCM_INFO),
)
# 2.2.22.2.5 ActivationContextInfoData
class ActivationContextInfoData(TypeSerialization1):
structure = (
('clientOK',LONG),
('bReserved1',LONG),
('dwReserved1',DWORD),
('dwReserved2',DWORD),
('pIFDClientCtx',PMInterfacePointer),
('pIFDPrototypeCtx',PMInterfacePointer),
)
# 2.2.22.2.6 LocationInfoData
class LocationInfoData(TypeSerialization1):
structure = (
('machineName',LPWSTR),
('processId',DWORD),
('apartmentId',DWORD),
('contextId',DWORD),
)
# 2.2.22.2.7.1 COSERVERINFO
class COSERVERINFO(NDRSTRUCT):
structure = (
('dwReserved1',DWORD),
('pwszName',LPWSTR),
('pdwReserved',LPLONG),
('dwReserved2',DWORD),
)
class PCOSERVERINFO(NDRPOINTER):
referent = (
('Data', COSERVERINFO),
)
# 2.2.22.2.7 SecurityInfoData
class SecurityInfoData(TypeSerialization1):
structure = (
('dwAuthnFlags',DWORD),
('pServerInfo',PCOSERVERINFO),
('pdwReserved',LPLONG),
)
# 2.2.22.2.8.1 customREMOTE_REPLY_SCM_INFO
class customREMOTE_REPLY_SCM_INFO(NDRSTRUCT):
structure = (
('Oxid',OXID),
('pdsaOxidBindings',PDUALSTRINGARRAY),
('ipidRemUnknown',IPID),
('authnHint',DWORD),
('serverVersion',COMVERSION),
)
class PcustomREMOTE_REPLY_SCM_INFO(NDRPOINTER):
referent = (
('Data', customREMOTE_REPLY_SCM_INFO),
)
# 2.2.22.2.8 ScmReplyInfoData
class ScmReplyInfoData(TypeSerialization1):
structure = (
('pdwReserved',DWORD),
('remoteReply',PcustomREMOTE_REPLY_SCM_INFO),
)
# 2.2.22.2.9 PropsOutInfo
class HRESULT_ARRAY(NDRUniConformantArray):
item = HRESULT
class PHRESULT_ARRAY(NDRPOINTER):
referent = (
('Data', HRESULT_ARRAY),
)
class MInterfacePointer_ARRAY(NDRUniConformantArray):
item = MInterfacePointer
class PMInterfacePointer_ARRAY(NDRUniConformantArray):
item = PMInterfacePointer
class PPMInterfacePointer_ARRAY(NDRPOINTER):
referent = (
('Data', PMInterfacePointer_ARRAY),
)
class PropsOutInfo(TypeSerialization1):
structure = (
('cIfs',DWORD),
('piid',PIID_ARRAY),
('phresults',PHRESULT_ARRAY),
('ppIntfData',PPMInterfacePointer_ARRAY),
)
# 2.2.23 REMINTERFACEREF
class REMINTERFACEREF(NDRSTRUCT):
structure = (
('ipid',IPID),
('cPublicRefs',LONG),
('cPrivateRefs',LONG),
)
class REMINTERFACEREF_ARRAY(NDRUniConformantArray):
item = REMINTERFACEREF
# 2.2.24 REMQIRESULT
class REMQIRESULT(NDRSTRUCT):
structure = (
('hResult',HRESULT),
('std',STDOBJREF),
)
# 2.2.25 PREMQIRESULT
class PREMQIRESULT(NDRPOINTER):
referent = (
('Data', REMQIRESULT),
)
# 2.2.26 REFIPID
REFIPID = GUID
################################################################################
# RPC CALLS
################################################################################
class DCOMCALL(NDRCALL):
commonHdr = (
('ORPCthis', ORPCTHIS),
)
class DCOMANSWER(NDRCALL):
commonHdr = (
('ORPCthat', ORPCTHAT),
)
# 3.1.2.5.1.1 IObjectExporter::ResolveOxid (Opnum 0)
class ResolveOxid(NDRCALL):
opnum = 0
structure = (
('pOxid', OXID),
('cRequestedProtseqs', USHORT),
('arRequestedProtseqs', USHORT_ARRAY),
)
class ResolveOxidResponse(NDRCALL):
structure = (
('ppdsaOxidBindings', PDUALSTRINGARRAY),
('pipidRemUnknown', IPID),
('pAuthnHint', DWORD),
('ErrorCode', error_status_t),
)
# 3.1.2.5.1.2 IObjectExporter::SimplePing (Opnum 1)
class SimplePing(NDRCALL):
opnum = 1
structure = (
('pSetId', SETID),
)
class SimplePingResponse(NDRCALL):
structure = (
('ErrorCode', error_status_t),
)
# 3.1.2.5.1.3 IObjectExporter::ComplexPing (Opnum 2)
class ComplexPing(NDRCALL):
opnum = 2
structure = (
('pSetId', SETID),
('SequenceNum', USHORT),
('cAddToSet', USHORT),
('cDelFromSet', USHORT),
('AddToSet', POID_ARRAY),
('DelFromSet', POID_ARRAY),
)
class ComplexPingResponse(NDRCALL):
structure = (
('pSetId', SETID),
('pPingBackoffFactor', USHORT),
('ErrorCode', error_status_t),
)
# 3.1.2.5.1.4 IObjectExporter::ServerAlive (Opnum 3)
class ServerAlive(NDRCALL):
opnum = 3
structure = (
)
class ServerAliveResponse(NDRCALL):
structure = (
('ErrorCode', error_status_t),
)
# 3.1.2.5.1.5 IObjectExporter::ResolveOxid2 (Opnum 4)
class ResolveOxid2(NDRCALL):
opnum = 4
structure = (
('pOxid', OXID),
('cRequestedProtseqs', USHORT),
('arRequestedProtseqs', USHORT_ARRAY),
)
class ResolveOxid2Response(NDRCALL):
structure = (
('ppdsaOxidBindings', PDUALSTRINGARRAY),
('pipidRemUnknown', IPID),
('pAuthnHint', DWORD),
('pComVersion', COMVERSION),
('ErrorCode', error_status_t),
)
# 3.1.2.5.1.6 IObjectExporter::ServerAlive2 (Opnum 5)
class ServerAlive2(NDRCALL):
opnum = 5
structure = (
)
class ServerAlive2Response(NDRCALL):
structure = (
('pComVersion', COMVERSION),
('ppdsaOrBindings', PDUALSTRINGARRAY),
('pReserved', LPLONG),
('ErrorCode', error_status_t),
)
# 3.1.2.5.2.3.1 IActivation:: RemoteActivation (Opnum 0)
class RemoteActivation(NDRCALL):
opnum = 0
structure = (
('ORPCthis', ORPCTHIS),
('Clsid', GUID),
('pwszObjectName', LPWSTR),
('pObjectStorage', PMInterfacePointer),
('ClientImpLevel', DWORD),
('Mode', DWORD),
('Interfaces', DWORD),
('pIIDs', PIID_ARRAY),
('cRequestedProtseqs', USHORT),
('aRequestedProtseqs', USHORT_ARRAY),
)
class RemoteActivationResponse(NDRCALL):
structure = (
('ORPCthat', ORPCTHAT),
('pOxid', OXID),
('ppdsaOxidBindings', PDUALSTRINGARRAY),
('pipidRemUnknown', IPID),
('pAuthnHint', DWORD),
('pServerVersion', COMVERSION),
('phr', HRESULT),
('ppInterfaceData', PMInterfacePointer_ARRAY),
('pResults', HRESULT_ARRAY),
('ErrorCode', error_status_t),
)
# 3.1.2.5.2.3.2 IRemoteSCMActivator:: RemoteGetClassObject (Opnum 3)
class RemoteGetClassObject(NDRCALL):
opnum = 3
structure = (
('ORPCthis', ORPCTHIS),
('pActProperties', PMInterfacePointer),
)
class RemoteGetClassObjectResponse(NDRCALL):
structure = (
('ORPCthat', ORPCTHAT),
('ppActProperties', PMInterfacePointer),
('ErrorCode', error_status_t),
)
# 3.1.2.5.2.3.3 IRemoteSCMActivator::RemoteCreateInstance (Opnum 4)
class RemoteCreateInstance(NDRCALL):
opnum = 4
structure = (
('ORPCthis', ORPCTHIS),
('pUnkOuter', PMInterfacePointer),
('pActProperties', PMInterfacePointer),
)
class RemoteCreateInstanceResponse(NDRCALL):
structure = (
('ORPCthat', ORPCTHAT),
('ppActProperties', PMInterfacePointer),
('ErrorCode', error_status_t),
)
# 3.1.1.5.6.1.1 IRemUnknown::RemQueryInterface (Opnum 3)
class RemQueryInterface(DCOMCALL):
opnum = 3
structure = (
('ripid', REFIPID),
('cRefs', ULONG),
('cIids', USHORT),
('iids', IID_ARRAY),
)
class RemQueryInterfaceResponse(DCOMANSWER):
structure = (
('ppQIResults', PREMQIRESULT),
('ErrorCode', error_status_t),
)
# 3.1.1.5.6.1.2 IRemUnknown::RemAddRef (Opnum 4 )
class RemAddRef(DCOMCALL):
opnum = 4
structure = (
('cInterfaceRefs', USHORT),
('InterfaceRefs', REMINTERFACEREF_ARRAY),
)
class RemAddRefResponse(DCOMANSWER):
structure = (
('pResults', DWORD_ARRAY),
('ErrorCode', error_status_t),
)
# 3.1.1.5.6.1.3 IRemUnknown::RemRelease (Opnum 5)
class RemRelease(DCOMCALL):
opnum = 5
structure = (
('cInterfaceRefs', USHORT),
('InterfaceRefs', REMINTERFACEREF_ARRAY),
)
class RemReleaseResponse(DCOMANSWER):
structure = (
('ErrorCode', error_status_t),
)
################################################################################
# OPNUMs and their corresponding structures
################################################################################
OPNUMS = {
}
################################################################################
# HELPER FUNCTIONS
################################################################################
class DCOMConnection:
"""
This class represents a DCOM Connection. It is in charge of establishing the
DCE connection against the portmap, and then launch a thread that will be
pinging the objects created against the target.
In theory, there should be a single instance of this class for every target
"""
PINGTIMER = None
OID_ADD = {}
OID_DEL = {}
OID_SET = {}
PORTMAPS = {}
def __init__(self, target, username='', password='', domain='', lmhash='', nthash='', aesKey='', TGT=None, TGS=None,
authLevel=RPC_C_AUTHN_LEVEL_PKT_PRIVACY, oxidResolver=False, doKerberos=False, kdcHost=None):
self.__target = target
self.__userName = username
self.__password = password
self.__domain = domain
self.__lmhash = lmhash
self.__nthash = nthash
self.__aesKey = aesKey
self.__TGT = TGT
self.__TGS = TGS
self.__authLevel = authLevel
self.__portmap = None
self.__oxidResolver = oxidResolver
self.__doKerberos = doKerberos
self.__kdcHost = kdcHost
self.initConnection()
@classmethod
def addOid(cls, target, oid):
if (target in DCOMConnection.OID_ADD) is False:
DCOMConnection.OID_ADD[target] = set()
DCOMConnection.OID_ADD[target].add(oid)
if (target in DCOMConnection.OID_SET) is False:
DCOMConnection.OID_SET[target] = {}
DCOMConnection.OID_SET[target]['oids'] = set()
DCOMConnection.OID_SET[target]['setid'] = 0
@classmethod
def delOid(cls, target, oid):
if (target in DCOMConnection.OID_DEL) is False:
DCOMConnection.OID_DEL[target] = set()
DCOMConnection.OID_DEL[target].add(oid)
if (target in DCOMConnection.OID_SET) is False:
DCOMConnection.OID_SET[target] = {}
DCOMConnection.OID_SET[target]['oids'] = set()
DCOMConnection.OID_SET[target]['setid'] = 0
@classmethod
def pingServer(cls):
# Here we need to go through all the objects opened and ping them.
# ToDo: locking for avoiding race conditions
#print DCOMConnection.PORTMAPS
#print DCOMConnection.OID_SET
try:
for target in DCOMConnection.OID_SET:
addedOids = set()
deletedOids = set()
if target in DCOMConnection.OID_ADD:
addedOids = DCOMConnection.OID_ADD[target]
del(DCOMConnection.OID_ADD[target])
if target in DCOMConnection.OID_DEL:
deletedOids = DCOMConnection.OID_DEL[target]
del(DCOMConnection.OID_DEL[target])
objExporter = IObjectExporter(DCOMConnection.PORTMAPS[target])
if len(addedOids) > 0 or len(deletedOids) > 0:
if 'setid' in DCOMConnection.OID_SET[target]:
setId = DCOMConnection.OID_SET[target]['setid']
else:
setId = 0
resp = objExporter.ComplexPing(setId, 0, addedOids, deletedOids)
DCOMConnection.OID_SET[target]['oids'] -= deletedOids
DCOMConnection.OID_SET[target]['oids'] |= addedOids
DCOMConnection.OID_SET[target]['setid'] = resp['pSetId']
else:
objExporter.SimplePing(DCOMConnection.OID_SET[target]['setid'])
except Exception as e:
# There might be exceptions when sending packets
# We should try to continue tho.
LOG.error(str(e))
pass
DCOMConnection.PINGTIMER = Timer(120,DCOMConnection.pingServer)
try:
DCOMConnection.PINGTIMER.start()
except Exception as e:
if str(e).find('threads can only be started once') < 0:
raise e
def initTimer(self):
if self.__oxidResolver is True:
if DCOMConnection.PINGTIMER is None:
DCOMConnection.PINGTIMER = Timer(120, DCOMConnection.pingServer)
try:
DCOMConnection.PINGTIMER.start()
except Exception as e:
if str(e).find('threads can only be started once') < 0:
raise e
def initConnection(self):
stringBinding = r'ncacn_ip_tcp:%s' % self.__target
rpctransport = transport.DCERPCTransportFactory(stringBinding)
if hasattr(rpctransport, 'set_credentials') and len(self.__userName) >=0:
# This method exists only for selected protocol sequences.
rpctransport.set_credentials(self.__userName, self.__password, self.__domain, self.__lmhash, self.__nthash,
self.__aesKey, self.__TGT, self.__TGS)
rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost)
self.__portmap = rpctransport.get_dce_rpc()
self.__portmap.set_auth_level(self.__authLevel)
if self.__doKerberos is True:
self.__portmap.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
self.__portmap.connect()
DCOMConnection.PORTMAPS[self.__target] = self.__portmap
def CoCreateInstanceEx(self, clsid, iid):
scm = IRemoteSCMActivator(self.__portmap)
iInterface = scm.RemoteCreateInstance(clsid, iid)
self.initTimer()
return iInterface
def get_dce_rpc(self):
return DCOMConnection.PORTMAPS[self.__target]
def disconnect(self):
if DCOMConnection.PINGTIMER is not None:
del(DCOMConnection.PORTMAPS[self.__target])
del(DCOMConnection.OID_SET[self.__target])
if len(DCOMConnection.PORTMAPS) == 0:
# This means there are no more clients using this object, kill it
DCOMConnection.PINGTIMER.cancel()
DCOMConnection.PINGTIMER.join()
DCOMConnection.PINGTIMER = None
if self.__target in INTERFACE.CONNECTIONS:
del(INTERFACE.CONNECTIONS[self.__target][currentThread().getName()])
self.__portmap.disconnect()
#print INTERFACE.CONNECTIONS
class CLASS_INSTANCE:
def __init__(self, ORPCthis, stringBinding):
self.__stringBindings = stringBinding
self.__ORPCthis = ORPCthis
self.__authType = RPC_C_AUTHN_WINNT
self.__authLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY
def get_ORPCthis(self):
return self.__ORPCthis
def get_string_bindings(self):
return self.__stringBindings
def get_auth_level(self):
if RPC_C_AUTHN_LEVEL_NONE < self.__authLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
if self.__authType == RPC_C_AUTHN_WINNT:
return RPC_C_AUTHN_LEVEL_PKT_INTEGRITY
else:
return RPC_C_AUTHN_LEVEL_PKT_PRIVACY
return self.__authLevel
def set_auth_level(self, level):
self.__authLevel = level
def get_auth_type(self):
return self.__authType
def set_auth_type(self, authType):
self.__authType = authType
class INTERFACE:
# class variable holding the transport connections, organized by target IP
CONNECTIONS = {}
def __init__(self, cinstance=None, objRef=None, ipidRemUnknown=None, iPid=None, oxid=None, oid=None, target=None,
interfaceInstance=None):
if interfaceInstance is not None:
self.__target = interfaceInstance.get_target()
self.__iPid = interfaceInstance.get_iPid()
self.__oid = interfaceInstance.get_oid()
self.__oxid = interfaceInstance.get_oxid()
self.__cinstance = interfaceInstance.get_cinstance()
self.__objRef = interfaceInstance.get_objRef()
self.__ipidRemUnknown = interfaceInstance.get_ipidRemUnknown()
else:
if target is None:
raise Exception('No target')
self.__target = target
self.__iPid = iPid
self.__oid = oid
self.__oxid = oxid
self.__cinstance = cinstance
self.__objRef = objRef
self.__ipidRemUnknown = ipidRemUnknown
# We gotta check if we have a container inside our connection list, if not, create
if (self.__target in INTERFACE.CONNECTIONS) is not True:
INTERFACE.CONNECTIONS[self.__target] = {}
INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {}
if objRef is not None:
self.process_interface(objRef)
def process_interface(self, data):
objRefType = OBJREF(data)['flags']
objRef = None
if objRefType == FLAGS_OBJREF_CUSTOM:
objRef = OBJREF_CUSTOM(data)
elif objRefType == FLAGS_OBJREF_HANDLER:
objRef = OBJREF_HANDLER(data)
elif objRefType == FLAGS_OBJREF_STANDARD:
objRef = OBJREF_STANDARD(data)
elif objRefType == FLAGS_OBJREF_EXTENDED:
objRef = OBJREF_EXTENDED(data)
else:
LOG.error("Unknown OBJREF Type! 0x%x" % objRefType)
if objRefType != FLAGS_OBJREF_CUSTOM:
if objRef['std']['flags'] & SORF_NOPING == 0:
DCOMConnection.addOid(self.__target, objRef['std']['oid'])
self.__iPid = objRef['std']['ipid']
self.__oid = objRef['std']['oid']
self.__oxid = objRef['std']['oxid']
if self.__oxid is None:
objRef.dump()
raise Exception('OXID is None')
def get_oxid(self):
return self.__oxid
def set_oxid(self, oxid):
self.__oxid = oxid
def get_oid(self):
return self.__oid
def set_oid(self, oid):
self.__oid = oid
def get_target(self):
return self.__target
def get_iPid(self):
return self.__iPid
def set_iPid(self, iPid):
self.__iPid = iPid
def get_objRef(self):
return self.__objRef
def set_objRef(self, objRef):
self.__objRef = objRef
def get_ipidRemUnknown(self):
return self.__ipidRemUnknown
def get_dce_rpc(self):
return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce']
def get_cinstance(self):
return self.__cinstance
def set_cinstance(self, cinstance):
self.__cinstance = cinstance
def is_fdqn(self):
# I will assume the following
# If I can't socket.inet_aton() then it's not an IPv4 address
# Same for ipv6, but since socket.inet_pton is not available in Windows, I'll look for ':'. There can't be
# an FQDN with ':'
# Is it isn't both, then it is a FDQN
try:
socket.inet_aton(self.__target)
except:
# Not an IPv4
try:
self.__target.index(':')
except:
# Not an IPv6, it's a FDQN
return True
return False
def connect(self, iid = None):
if (self.__target in INTERFACE.CONNECTIONS) is True:
if currentThread().getName() in INTERFACE.CONNECTIONS[self.__target] and \
(self.__oxid in INTERFACE.CONNECTIONS[self.__target][currentThread().getName()]) is True:
dce = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce']
currentBinding = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding']
if currentBinding == iid:
# We don't need to alter_ctx
pass
else:
newDce = dce.alter_ctx(iid)
INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = newDce
INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid
else:
stringBindings = self.get_cinstance().get_string_bindings()
# No OXID present, we should create a new connection and store it
stringBinding = None
isTargetFDQN = self.is_fdqn()
LOG.debug('Target system is %s and isFDQN is %s' % (self.get_target(), isTargetFDQN))
for strBinding in stringBindings:
# Here, depending on the get_target() value several things can happen
# 1) it's an IPv4 address
# 2) it's an IPv6 address
# 3) it's a NetBios Name
# we should handle all this cases accordingly
# Does this match exactly what get_target() returns?
LOG.debug('StringBinding: %s' % strBinding['aNetworkAddr'])
if strBinding['wTowerId'] == 7:
# If there's port information, let's strip it for now.
if strBinding['aNetworkAddr'].find('[') >= 0:
binding, _, bindingPort = strBinding['aNetworkAddr'].partition('[')
bindingPort = '[' + bindingPort
else:
binding = strBinding['aNetworkAddr']
bindingPort = ''
if binding.upper().find(self.get_target().upper()) >= 0:
stringBinding = 'ncacn_ip_tcp:' + strBinding['aNetworkAddr'][:-1]
break
# If get_target() is a FQDN, does it match the hostname?
elif isTargetFDQN and binding.upper().find(self.get_target().upper().partition('.')[0]) >= 0:
# Here we replace the aNetworkAddr with self.get_target()
# This is to help resolving the target system name.
# self.get_target() has been resolved already otherwise we wouldn't be here whereas
# aNetworkAddr is usually the NetBIOS name and unless you have your DNS resolver
# with the right suffixes it will probably not resolve right.
stringBinding = 'ncacn_ip_tcp:%s%s' % (self.get_target(), bindingPort)
break
LOG.debug('StringBinding chosen: %s' % stringBinding)
if stringBinding is None:
# Something wen't wrong, let's just report it
raise Exception('Can\'t find a valid stringBinding to connect')
dcomInterface = transport.DCERPCTransportFactory(stringBinding)
if hasattr(dcomInterface, 'set_credentials'):
# This method exists only for selected protocol sequences.
dcomInterface.set_credentials(*DCOMConnection.PORTMAPS[self.__target].get_credentials())
dcomInterface.set_kerberos(DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kerberos(),
DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kdcHost())
dcomInterface.set_connect_timeout(300)
dce = dcomInterface.get_dce_rpc()
if iid is None:
raise Exception('IID is None')
else:
dce.set_auth_level(self.__cinstance.get_auth_level())
dce.set_auth_type(self.__cinstance.get_auth_type())
dce.connect()
if iid is None:
raise Exception('IID is None')
else:
dce.bind(iid)
if self.__oxid is None:
#import traceback
#traceback.print_stack()
raise Exception("OXID NONE, something wrong!!!")
INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {}
INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid] = {}
INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = dce
INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid
else:
# No connection created
raise Exception('No connection created')
def request(self, req, iid = None, uuid = None):
req['ORPCthis'] = self.get_cinstance().get_ORPCthis()
req['ORPCthis']['flags'] = 0
self.connect(iid)
dce = self.get_dce_rpc()
try:
resp = dce.request(req, uuid)
except Exception as e:
if str(e).find('RPC_E_DISCONNECTED') >= 0:
msg = str(e) + '\n'
msg += "DCOM keep-alive pinging it might not be working as expected. You can't be idle for more than 14 minutes!\n"
msg += "You should exit the app and start again\n"
raise DCERPCException(msg)
else:
raise
return resp
def disconnect(self):
return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'].disconnect()
# 3.1.1.5.6.1 IRemUnknown Methods
class IRemUnknown(INTERFACE):
def __init__(self, interface):
self._iid = IID_IRemUnknown
#INTERFACE.__init__(self, interface.get_cinstance(), interface.get_objRef(), interface.get_ipidRemUnknown(),
# interface.get_iPid(), target=interface.get_target())
INTERFACE.__init__(self, interfaceInstance=interface)
self.set_oxid(interface.get_oxid())
def RemQueryInterface(self, cRefs, iids):
# For now, it only supports a single IID
request = RemQueryInterface()
request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
request['ORPCthis']['flags'] = 0
request['ripid'] = self.get_iPid()
request['cRefs'] = cRefs
request['cIids'] = len(iids)
for iid in iids:
_iid = IID()
_iid['Data'] = iid
request['iids'].append(_iid)
resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown())
#resp.dump()
return IRemUnknown2(
INTERFACE(self.get_cinstance(), None, self.get_ipidRemUnknown(), resp['ppQIResults']['std']['ipid'],
oxid=resp['ppQIResults']['std']['oxid'], oid=resp['ppQIResults']['std']['oxid'],
target=self.get_target()))
def RemAddRef(self):
request = RemAddRef()
request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
request['ORPCthis']['flags'] = 0
request['cInterfaceRefs'] = 1
element = REMINTERFACEREF()
element['ipid'] = self.get_iPid()
element['cPublicRefs'] = 1
request['InterfaceRefs'].append(element)
resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown())
return resp
def RemRelease(self):
request = RemRelease()
request['ORPCthis'] = self.get_cinstance().get_ORPCthis()
request['ORPCthis']['flags'] = 0
request['cInterfaceRefs'] = 1
element = REMINTERFACEREF()
element['ipid'] = self.get_iPid()
element['cPublicRefs'] = 1
request['InterfaceRefs'].append(element)
resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown())
DCOMConnection.delOid(self.get_target(), self.get_oid())
return resp
# 3.1.1.5.7 IRemUnknown2 Interface
class IRemUnknown2(IRemUnknown):
def __init__(self, interface):
IRemUnknown.__init__(self, interface)
self._iid = IID_IRemUnknown2
# 3.1.2.5.1 IObjectExporter Methods
class IObjectExporter:
def __init__(self, dce):
self.__portmap = dce
# 3.1.2.5.1.1 IObjectExporter::ResolveOxid (Opnum 0)
def ResolveOxid(self, pOxid, arRequestedProtseqs):
self.__portmap.connect()
self.__portmap.bind(IID_IObjectExporter)
request = ResolveOxid()
request['pOxid'] = pOxid
request['cRequestedProtseqs'] = len(arRequestedProtseqs)
for protSeq in arRequestedProtseqs:
request['arRequestedProtseqs'].append(protSeq)
resp = self.__portmap.request(request)
Oxids = b''.join(pack('<H', x) for x in resp['ppdsaOxidBindings']['aStringArray'])
strBindings = Oxids[:resp['ppdsaOxidBindings']['wSecurityOffset']*2]
done = False
stringBindings = list()
while not done:
if strBindings[0:1] == b'\x00' and strBindings[1:2] == b'\x00':
done = True
else:
binding = STRINGBINDING(strBindings)
stringBindings.append(binding)
strBindings = strBindings[len(binding):]
return stringBindings
# 3.1.2.5.1.2 IObjectExporter::SimplePing (Opnum 1)
def SimplePing(self, setId):
self.__portmap.connect()
self.__portmap.bind(IID_IObjectExporter)
request = SimplePing()
request['pSetId'] = setId
resp = self.__portmap.request(request)
return resp
# 3.1.2.5.1.3 IObjectExporter::ComplexPing (Opnum 2)
def ComplexPing(self, setId = 0, sequenceNum = 0, addToSet = [], delFromSet = []):
self.__portmap.connect()
#self.__portmap.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
self.__portmap.bind(IID_IObjectExporter)
request = ComplexPing()
request['pSetId'] = setId
request['SequenceNum'] = setId
request['cAddToSet'] = len(addToSet)
request['cDelFromSet'] = len(delFromSet)
if len(addToSet) > 0:
for oid in addToSet:
oidn = OID()
oidn['Data'] = oid
request['AddToSet'].append(oidn)
else:
request['AddToSet'] = NULL
if len(delFromSet) > 0:
for oid in delFromSet:
oidn = OID()
oidn['Data'] = oid
request['DelFromSet'].append(oidn)
else:
request['DelFromSet'] = NULL
resp = self.__portmap.request(request)
return resp
# 3.1.2.5.1.4 IObjectExporter::ServerAlive (Opnum 3)
def ServerAlive(self):
self.__portmap.connect()
self.__portmap.bind(IID_IObjectExporter)
request = ServerAlive()
resp = self.__portmap.request(request)
return resp
# 3.1.2.5.1.5 IObjectExporter::ResolveOxid2 (Opnum 4)
def ResolveOxid2(self,pOxid, arRequestedProtseqs):
self.__portmap.connect()
self.__portmap.bind(IID_IObjectExporter)
request = ResolveOxid2()
request['pOxid'] = pOxid
request['cRequestedProtseqs'] = len(arRequestedProtseqs)
for protSeq in arRequestedProtseqs:
request['arRequestedProtseqs'].append(protSeq)
resp = self.__portmap.request(request)
Oxids = b''.join(pack('<H', x) for x in resp['ppdsaOxidBindings']['aStringArray'])
strBindings = Oxids[:resp['ppdsaOxidBindings']['wSecurityOffset']*2]
done = False
stringBindings = list()
while not done:
if strBindings[0:1] == b'\x00' and strBindings[1:2] == b'\x00':
done = True
else:
binding = STRINGBINDING(strBindings)
stringBindings.append(binding)
strBindings = strBindings[len(binding):]
return stringBindings
# 3.1.2.5.1.6 IObjectExporter::ServerAlive2 (Opnum 5)
def ServerAlive2(self):
self.__portmap.connect()
self.__portmap.bind(IID_IObjectExporter)
request = ServerAlive2()
resp = self.__portmap.request(request)
Oxids = b''.join(pack('<H', x) for x in resp['ppdsaOrBindings']['aStringArray'])
strBindings = Oxids[:resp['ppdsaOrBindings']['wSecurityOffset']*2]
done = False
stringBindings = list()
while not done:
if strBindings[0:1] == b'\x00' and strBindings[1:2] == b'\x00':
done = True
else:
binding = STRINGBINDING(strBindings)
stringBindings.append(binding)
strBindings = strBindings[len(binding):]
return stringBindings
# 3.1.2.5.2.1 IActivation Methods
class IActivation:
def __init__(self, dce):
self.__portmap = dce
# 3.1.2.5.2.3.1 IActivation:: RemoteActivation (Opnum 0)
def RemoteActivation(self, clsId, iid):
# Only supports one interface at a time
self.__portmap.bind(IID_IActivation)
ORPCthis = ORPCTHIS()
ORPCthis['cid'] = generate()
ORPCthis['extensions'] = NULL
ORPCthis['flags'] = 1
request = RemoteActivation()
request['Clsid'] = clsId
request['pwszObjectName'] = NULL
request['pObjectStorage'] = NULL
request['ClientImpLevel'] = 2
request['Mode'] = 0
request['Interfaces'] = 1
_iid = IID()
_iid['Data'] = iid
request['pIIDs'].append(_iid)
request['cRequestedProtseqs'] = 1
request['aRequestedProtseqs'].append(7)
resp = self.__portmap.request(request)
# Now let's parse the answer and build an Interface instance
ipidRemUnknown = resp['pipidRemUnknown']
Oxids = b''.join(pack('<H', x) for x in resp['ppdsaOxidBindings']['aStringArray'])
strBindings = Oxids[:resp['ppdsaOxidBindings']['wSecurityOffset']*2]
securityBindings = Oxids[resp['ppdsaOxidBindings']['wSecurityOffset']*2:]
done = False
stringBindings = list()
while not done:
if strBindings[0:1] == b'\x00' and strBindings[1:2] == b'\x00':
done = True
else:
binding = STRINGBINDING(strBindings)
stringBindings.append(binding)
strBindings = strBindings[len(binding):]
done = False
while not done:
if len(securityBindings) < 2:
done = True
elif securityBindings[0:1] == b'\x00' and securityBindings[1:2 ]== b'\x00':
done = True
else:
secBinding = SECURITYBINDING(securityBindings)
securityBindings = securityBindings[len(secBinding):]
classInstance = CLASS_INSTANCE(ORPCthis, stringBindings)
return IRemUnknown2(INTERFACE(classInstance, b''.join(resp['ppInterfaceData'][0]['abData']), ipidRemUnknown,
target=self.__portmap.get_rpc_transport().getRemoteHost()))
# 3.1.2.5.2.2 IRemoteSCMActivator Methods
class IRemoteSCMActivator:
def __init__(self, dce):
self.__portmap = dce
def RemoteGetClassObject(self, clsId, iid):
# iid should be IID_IClassFactory
self.__portmap.bind(IID_IRemoteSCMActivator)
ORPCthis = ORPCTHIS()
ORPCthis['cid'] = generate()
ORPCthis['extensions'] = NULL
ORPCthis['flags'] = 1
request = RemoteGetClassObject()
request['ORPCthis'] = ORPCthis
activationBLOB = ACTIVATION_BLOB()
activationBLOB['CustomHeader']['destCtx'] = 2
activationBLOB['CustomHeader']['pdwReserved'] = NULL
clsid = CLSID()
clsid['Data'] = CLSID_InstantiationInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
clsid = CLSID()
clsid['Data'] = CLSID_ActivationContextInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
clsid = CLSID()
clsid['Data'] = CLSID_ServerLocationInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
clsid = CLSID()
clsid['Data'] = CLSID_ScmRequestInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
properties = b''
# InstantiationInfo
instantiationInfo = InstantiationInfoData()
instantiationInfo['classId'] = clsId
instantiationInfo['cIID'] = 1
_iid = IID()
_iid['Data'] = iid
instantiationInfo['pIID'].append(_iid)
dword = DWORD()
marshaled = instantiationInfo.getData()+instantiationInfo.getDataReferents()
pad = (8 - (len(marshaled) % 8)) % 8
dword['Data'] = len(marshaled) + pad
activationBLOB['CustomHeader']['pSizes'].append(dword)
instantiationInfo['thisSize'] = dword['Data']
properties += marshaled + b'\xFA'*pad
# ActivationContextInfoData
activationInfo = ActivationContextInfoData()
activationInfo['pIFDClientCtx'] = NULL
activationInfo['pIFDPrototypeCtx'] = NULL
dword = DWORD()
marshaled = activationInfo.getData()+activationInfo.getDataReferents()
pad = (8 - (len(marshaled) % 8)) % 8
dword['Data'] = len(marshaled) + pad
activationBLOB['CustomHeader']['pSizes'].append(dword)
properties += marshaled + b'\xFA'*pad
# ServerLocation
locationInfo = LocationInfoData()
locationInfo['machineName'] = NULL
dword = DWORD()
dword['Data'] = len(locationInfo.getData())
activationBLOB['CustomHeader']['pSizes'].append(dword)
properties += locationInfo.getData()+locationInfo.getDataReferents()
# ScmRequestInfo
scmInfo = ScmRequestInfoData()
scmInfo['pdwReserved'] = NULL
#scmInfo['remoteRequest']['ClientImpLevel'] = 2
scmInfo['remoteRequest']['cRequestedProtseqs'] = 1
scmInfo['remoteRequest']['pRequestedProtseqs'].append(7)
dword = DWORD()
marshaled = scmInfo.getData()+scmInfo.getDataReferents()
pad = (8 - (len(marshaled) % 8)) % 8
dword['Data'] = len(marshaled) + pad
activationBLOB['CustomHeader']['pSizes'].append(dword)
properties += marshaled + b'\xFA'*pad
activationBLOB['Property'] = properties
objrefcustom = OBJREF_CUSTOM()
objrefcustom['iid'] = IID_IActivationPropertiesIn[:-4]
objrefcustom['clsid'] = CLSID_ActivationPropertiesIn
objrefcustom['pObjectData'] = activationBLOB.getData()
objrefcustom['ObjectReferenceSize'] = len(objrefcustom['pObjectData'])+8
request['pActProperties']['ulCntData'] = len(objrefcustom.getData())
request['pActProperties']['abData'] = list(objrefcustom.getData())
resp = self.__portmap.request(request)
# Now let's parse the answer and build an Interface instance
objRefType = OBJREF(b''.join(resp['ppActProperties']['abData']))['flags']
objRef = None
if objRefType == FLAGS_OBJREF_CUSTOM:
objRef = OBJREF_CUSTOM(b''.join(resp['ppActProperties']['abData']))
elif objRefType == FLAGS_OBJREF_HANDLER:
objRef = OBJREF_HANDLER(b''.join(resp['ppActProperties']['abData']))
elif objRefType == FLAGS_OBJREF_STANDARD:
objRef = OBJREF_STANDARD(b''.join(resp['ppActProperties']['abData']))
elif objRefType == FLAGS_OBJREF_EXTENDED:
objRef = OBJREF_EXTENDED(b''.join(resp['ppActProperties']['abData']))
else:
LOG.error("Unknown OBJREF Type! 0x%x" % objRefType)
activationBlob = ACTIVATION_BLOB(objRef['pObjectData'])
propOutput = activationBlob['Property'][:activationBlob['CustomHeader']['pSizes'][0]['Data']]
scmReply = activationBlob['Property'][
activationBlob['CustomHeader']['pSizes'][0]['Data']:activationBlob['CustomHeader']['pSizes'][0]['Data'] +
activationBlob['CustomHeader']['pSizes'][1]['Data']]
scmr = ScmReplyInfoData()
size = scmr.fromString(scmReply)
# Processing the scmReply
scmr.fromStringReferents(scmReply[size:])
ipidRemUnknown = scmr['remoteReply']['ipidRemUnknown']
Oxids = b''.join(pack('<H', x) for x in scmr['remoteReply']['pdsaOxidBindings']['aStringArray'])
strBindings = Oxids[:scmr['remoteReply']['pdsaOxidBindings']['wSecurityOffset']*2]
securityBindings = Oxids[scmr['remoteReply']['pdsaOxidBindings']['wSecurityOffset']*2:]
done = False
stringBindings = list()
while not done:
if strBindings[0:1] == b'\x00' and strBindings[1:2] == b'\x00':
done = True
else:
binding = STRINGBINDING(strBindings)
stringBindings.append(binding)
strBindings = strBindings[len(binding):]
done = False
while not done:
if len(securityBindings) < 2:
done = True
elif securityBindings[0:1] == b'\x00' and securityBindings[1:2] == b'\x00':
done = True
else:
secBinding = SECURITYBINDING(securityBindings)
securityBindings = securityBindings[len(secBinding):]
# Processing the Properties Output
propsOut = PropsOutInfo()
size = propsOut.fromString(propOutput)
propsOut.fromStringReferents(propOutput[size:])
classInstance = CLASS_INSTANCE(ORPCthis, stringBindings)
classInstance.set_auth_level(scmr['remoteReply']['authnHint'])
classInstance.set_auth_type(self.__portmap.get_auth_type())
return IRemUnknown2(INTERFACE(classInstance, b''.join(propsOut['ppIntfData'][0]['abData']), ipidRemUnknown,
target=self.__portmap.get_rpc_transport().getRemoteHost()))
def RemoteCreateInstance(self, clsId, iid):
# Only supports one interface at a time
self.__portmap.bind(IID_IRemoteSCMActivator)
ORPCthis = ORPCTHIS()
ORPCthis['cid'] = generate()
ORPCthis['extensions'] = NULL
ORPCthis['flags'] = 1
request = RemoteCreateInstance()
request['ORPCthis'] = ORPCthis
request['pUnkOuter'] = NULL
activationBLOB = ACTIVATION_BLOB()
activationBLOB['CustomHeader']['destCtx'] = 2
activationBLOB['CustomHeader']['pdwReserved'] = NULL
clsid = CLSID()
clsid['Data'] = CLSID_InstantiationInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
clsid = CLSID()
clsid['Data'] = CLSID_ActivationContextInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
clsid = CLSID()
clsid['Data'] = CLSID_ServerLocationInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
clsid = CLSID()
clsid['Data'] = CLSID_ScmRequestInfo
activationBLOB['CustomHeader']['pclsid'].append(clsid)
properties = b''
# InstantiationInfo
instantiationInfo = InstantiationInfoData()
instantiationInfo['classId'] = clsId
instantiationInfo['cIID'] = 1
_iid = IID()
_iid['Data'] = iid
instantiationInfo['pIID'].append(_iid)
dword = DWORD()
marshaled = instantiationInfo.getData()+instantiationInfo.getDataReferents()
pad = (8 - (len(marshaled) % 8)) % 8
dword['Data'] = len(marshaled) + pad
activationBLOB['CustomHeader']['pSizes'].append(dword)
instantiationInfo['thisSize'] = dword['Data']
properties += marshaled + b'\xFA'*pad
# ActivationContextInfoData
activationInfo = ActivationContextInfoData()
activationInfo['pIFDClientCtx'] = NULL
activationInfo['pIFDPrototypeCtx'] = NULL
dword = DWORD()
marshaled = activationInfo.getData()+activationInfo.getDataReferents()
pad = (8 - (len(marshaled) % 8)) % 8
dword['Data'] = len(marshaled) + pad
activationBLOB['CustomHeader']['pSizes'].append(dword)
properties += marshaled + b'\xFA'*pad
# ServerLocation
locationInfo = LocationInfoData()
locationInfo['machineName'] = NULL
dword = DWORD()
dword['Data'] = len(locationInfo.getData())
activationBLOB['CustomHeader']['pSizes'].append(dword)
properties += locationInfo.getData()+locationInfo.getDataReferents()
# ScmRequestInfo
scmInfo = ScmRequestInfoData()
scmInfo['pdwReserved'] = NULL
#scmInfo['remoteRequest']['ClientImpLevel'] = 2
scmInfo['remoteRequest']['cRequestedProtseqs'] = 1
scmInfo['remoteRequest']['pRequestedProtseqs'].append(7)
dword = DWORD()
marshaled = scmInfo.getData()+scmInfo.getDataReferents()
pad = (8 - (len(marshaled) % 8)) % 8
dword['Data'] = len(marshaled) + pad
activationBLOB['CustomHeader']['pSizes'].append(dword)
properties += marshaled + b'\xFA'*pad
activationBLOB['Property'] = properties
objrefcustom = OBJREF_CUSTOM()
objrefcustom['iid'] = IID_IActivationPropertiesIn[:-4]
objrefcustom['clsid'] = CLSID_ActivationPropertiesIn
objrefcustom['pObjectData'] = activationBLOB.getData()
objrefcustom['ObjectReferenceSize'] = len(objrefcustom['pObjectData'])+8
request['pActProperties']['ulCntData'] = len(objrefcustom.getData())
request['pActProperties']['abData'] = list(objrefcustom.getData())
resp = self.__portmap.request(request)
# Now let's parse the answer and build an Interface instance
objRefType = OBJREF(b''.join(resp['ppActProperties']['abData']))['flags']
objRef = None
if objRefType == FLAGS_OBJREF_CUSTOM:
objRef = OBJREF_CUSTOM(b''.join(resp['ppActProperties']['abData']))
elif objRefType == FLAGS_OBJREF_HANDLER:
objRef = OBJREF_HANDLER(b''.join(resp['ppActProperties']['abData']))
elif objRefType == FLAGS_OBJREF_STANDARD:
objRef = OBJREF_STANDARD(b''.join(resp['ppActProperties']['abData']))
elif objRefType == FLAGS_OBJREF_EXTENDED:
objRef = OBJREF_EXTENDED(b''.join(resp['ppActProperties']['abData']))
else:
LOG.error("Unknown OBJREF Type! 0x%x" % objRefType)
activationBlob = ACTIVATION_BLOB(objRef['pObjectData'])
propOutput = activationBlob['Property'][:activationBlob['CustomHeader']['pSizes'][0]['Data']]
scmReply = activationBlob['Property'][
activationBlob['CustomHeader']['pSizes'][0]['Data']:activationBlob['CustomHeader']['pSizes'][0]['Data'] +
activationBlob['CustomHeader']['pSizes'][1]['Data']]
scmr = ScmReplyInfoData()
size = scmr.fromString(scmReply)
# Processing the scmReply
scmr.fromStringReferents(scmReply[size:])
ipidRemUnknown = scmr['remoteReply']['ipidRemUnknown']
Oxids = b''.join(pack('<H', x) for x in scmr['remoteReply']['pdsaOxidBindings']['aStringArray'])
strBindings = Oxids[:scmr['remoteReply']['pdsaOxidBindings']['wSecurityOffset']*2]
securityBindings = Oxids[scmr['remoteReply']['pdsaOxidBindings']['wSecurityOffset']*2:]
done = False
stringBindings = list()
while not done:
if strBindings[0:1] == b'\x00' and strBindings[1:2] == b'\x00':
done = True
else:
binding = STRINGBINDING(strBindings)
stringBindings.append(binding)
strBindings = strBindings[len(binding):]
done = False
while not done:
if len(securityBindings) < 2:
done = True
elif securityBindings[0:1] == b'\x00' and securityBindings[1:2] == b'\x00':
done = True
else:
secBinding = SECURITYBINDING(securityBindings)
securityBindings = securityBindings[len(secBinding):]
# Processing the Properties Output
propsOut = PropsOutInfo()
size = propsOut.fromString(propOutput)
propsOut.fromStringReferents(propOutput[size:])
classInstance = CLASS_INSTANCE(ORPCthis, stringBindings)
classInstance.set_auth_level(scmr['remoteReply']['authnHint'])
classInstance.set_auth_type(self.__portmap.get_auth_type())
return IRemUnknown2(INTERFACE(classInstance, b''.join(propsOut['ppIntfData'][0]['abData']), ipidRemUnknown,
target=self.__portmap.get_rpc_transport().getRemoteHost()))