Skip to content

DCE/RPC and NDR

Back to the Technology Index

RPC lets a client call a function on a remote system. Impacket’s MSRPC implementation separates locating the endpoint, exchanging messages, and encoding arguments into distinct layers. It implements connection-oriented RPC from C706 and [MS-RPCE], with separate transport, runtime, NDR, and interface layers.

ModuleResponsibility
transport.pystring binding → TCP / SMB pipe / HTTP / UDP / local
rpcrt.pyPDUs, bind / alter context, AUTH3, SIGN/SEAL
rpch.pyRPC over HTTP v1/v2
ndr.pyNDR / NDR64 packing
epm.pyEndpoint Mapper
dcomrt.py + dcom/DCOM OXID / OBJREF, WMI

Related commands: rpcdump, rpcmap, services, atexec, wmiexec, samrdump

[uuid@]proto:address[endpoint,opt=val]

DCERPCTransportFactory() selects a transport:

ProtoClassTypical Use
ncacn_npSMBTransportncacn_np:host[\pipe\svcctl]
ncacn_ip_tcpTCPTransportPort 135 by default; resolve dynamic ports through EPM
ncacn_httpHTTPTransportDirect port 593 or RpcProxy=host:443
ncadg_ip_udpUDPTransportConnectionless DCERPC_v4
ncalocalLOCALTransport\\\\.\\PIPE\\...; not LPC (ncalrpc)

SMBTransport can reuse an existing SMBConnection. Use this when opening multiple interfaces over the same session.

rpch.py implements [MS-RPCH].

  • Direct: port 593, banner ncacn_http/1.0 (RPC_OVER_HTTP_v1)
  • Proxy: option RpcProxy=host:80|443 → /rpc/rpcproxy.dll?RemoteName:RemotePort. It opens paired IN (RPC_IN_DATA) and OUT (RPC_OUT_DATA) channels, then establishes the tunnel through RTS (CONN_A1/B1/A3/C2)
  • Exchange commonly uses ports 6001–6004 (OXCRPC / OXABREF / OXNSPI)

set_credentials() automatically raises the authentication level to CONNECT. The caller must explicitly set PKT_PRIVACY when required by DRSUAPI or some DCOM interfaces.

Credentials reside on the transport and DCERPC_v5.set_credentials() reads them during bind. An SMB transport can reuse the same SMBConnection.

Main types (rpcrt.py):

ValueName
0x00 / 0x02REQUEST / RESPONSE
0x03FAULT
0x0B / 0x0C / 0x0DBIND / BINDACK / BINDNAK
0x0E / 0x0FALTERCTX / ALTERCTX_R
0x10AUTH3 (NTLM Type3)
0x14RTS (RPC over HTTP)

DCERPC_v5.bind(iface_uuid) puts the abstract syntax (interface UUID+version) and transfer syntax in a CtxItem.

Transfer syntaxUUID
NDR 2.08a885d04-1ceb-11c9-9fe8-08002b104860
NDR64 1.071710533-beba-4937-8319-b5dbef9ccc36

bogus_binds prepends dummy contexts (to avoid fingerprinting by some hosts). If the bind is rejected, it raises DCERPCException with rpc_cont_def_result / rpc_status_codes.

The EPM (epm.py) UUID is E1AF8308-5D1F-11C9-91A4-08002B14A0FA v3.0, and its default binding is ncacn_ip_tcp:host[135].

HelperRole
hept_lookupAll towers and annotations; used by rpcdump
hept_mapReturns one string binding for an interface; dynamic DRSUAPI/GKDI ports
PrintStringBindingConverts floors to a string

A tower is a sequence of floors for the interface UUID, transfer syntax, protocol, pipe/port, and host. rpcmap uses mgmt (hinq_if_ids) or UUID/opnum probing on a specified binding.

Shared types in dtypes.py ([MS-DTYP]) include DWORD, WSTR, RPC_SID, GUID, and SECURITY_DESCRIPTOR. NULL is the NDRPOINTERNULL singleton.

DCERPC.request(req) looks for a {ClassName}Response in the same module as req and raises that module’s DCERPCSessionError if the trailing four bytes are nonzero.

set_auth_type / set_auth_level:

auth_typeValueImplementation
RPC_C_AUTHN_NONE0x00None
RPC_C_AUTHN_GSS_NEGOTIATE0x09Kerberos (getKerberosType1)
RPC_C_AUTHN_WINNT0x0ANTLMSSP (default)
RPC_C_AUTHN_NETLOGON0x44Secure Channel (nrpc.getSSPType1)
auth_levelValueMeaning
NONE1No authentication
CONNECT2Bind only (default with set_credentials)
CALL3Per call
PKT4Per packet
PKT_INTEGRITY5Signing
PKT_PRIVACY6Signing and encryption

An NTLM bind puts Type1 in BIND, reads Type2 from BINDACK, and sends Type3 in AUTH3. With PKT_INTEGRITY / PKT_PRIVACY, subsequent REQUESTs carry a SEC_TRAILER and signing/encryption. Kerberos uses a SPNEGO AP-REQ/AP-REP (DCE_STYLE).

Over SMB3, RPC uses the ApplicationKey from SMBConnection.getSessionKey() as its signing key, not the raw NTLM exported key.

NDR uses declarations similar to Structure, but follows C706 alignment rules. It inserts minimal padding before primitives.

ClassPurpose
NDRSMALL / NDRSHORT / NDRLONG / NDRHYPER and unsigned variantsScalars
NDRBOOLEAN / NDRCHAR / NDRFLOATOther primitives
NDRENUMEnumeration
NDRSTRUCTStructure
NDRUNIONDiscriminated union
NDRUniFixedArray / NDRUniConformantArray / NDRUniVaryingArray / NDRUniConformantVaryingArrayArrays
NDRVaryingString / NDRConformantVaryingStringStrings
NDRPOINTER / NDRPOINTERNULLReference pointers; referents follow later
NDRCALLTop-level requests / responses

isNDR64=True switches to commonHdr64 / structure64 / align64. Pointers grow from four to eight bytes.

The pattern in interface modules is:

  1. MSRPC_UUID_* = uuidtup_to_bin((uuid, version))
  2. Declare types with NDRSTRUCT / NDRPOINTER
  3. Make each operation an NDRCALL subclass and add a helper hXxxYyy(dce, ...)

When adding an operation, follow the IDL’s alignment and the MaximumCount / Offset / ActualCount values for conformant arrays. Building a Structure manually gives the wrong padding.

Named pipes shown here are representative. On some hosts, an interface may be reachable only over TCP via EPM or through a pipe with another name.

ModuleUUID (excerpt)Typical Pipe / PortPurpose
epmE1AF8308-...A0FA v3TCP 135Endpoint resolution
mgmtafa8bd80-...AnyInterface inquiry (rpcmap)
samr12345778-...89AC v1samrAccount enumeration, creation, passwords
lsat / lsad12345778-...89AB v0lsarpcSID lookup, policies, secrets
nrpc12345678-...CFFB v1netlogonSecure Channel, challenge/authenticate
scmr367ABB81-... v2svcctlCreate, start, or stop services; also RCreateWowService (opnum 60) and ROpenSCManager2 (opnum 64)
tsch86D35949-... v1TaskSchedulerXML tasks (atexec)
atsvc / sasec1FF70682-...atsvcLegacy AT jobs, task accounts
srvs4B324FC8-...E188 v3srvsvcShares and sessions
fsrvpA8E0653C-...2292 v1FssagentRpcFile server remote VSS (MS-FSRVP)
wkst6BFFD098-...345A v1wkssvcWorkstation / join
rrp338CD001-... v1winregRemote Registry, including boot key class names
drsuapiE3514235-...DCD2 v4TCP (EPM)DRSGetNCChanges; usually PKT_PRIVACY
bkrp3dde7c30-...db40 v1—DPAPI domain backup key
gkdiB9785960-...2085 v1TCP (EPM)GkdiGetKey for LAPS v2 / DPAPI-NG
dcomrt + dcom/wmiOXID / IWbem*TCP 135 + dynamic portsWMI / MMC / ShellWindows; OXID ping thread
nspiF5CC5A18-...8426 v56Also HTTP 6004Exchange address book
oxabref1544F5E0-...BD09Around HTTP 6001RfrGetNewDSA
icpr91ae6020-...91becertCertificate requests (AD CS relay)
tstsMultipleLSM_API_service, etc.Session operations (tstool)
rprn / par12345678-...89AB, etc.spoolssPrint spooler
even / even682273FDC-... / F6BEAFF7-...eventlogEvent logs
mimilib17FC11E9-...6244—mimikatz RPC (not a Microsoft interface)
dhcpm / raa / iphlp / dsspVarious specifications—DHCP, Authz, machine roles

Beyond a normal bind, DCOM has OXID resolution, OBJREF, and IRemUnknown reference counting. wmiexec uses Win32_Process.Create, dcomexec uses ShellWindows / ShellBrowserWindow / MMC20.Application, and wmipersist uses a permanent event subscription. On intermediate failures, RemRelease / object release is part of the contract.

rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:host[\pipe\svcctl]')
rpctransport.set_credentials(user, password, domain, lmhash, nthash)
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(scmr.MSRPC_UUID_SCMR)
# scmr.hROpenSCManagerW(dce, ...)
dce.disconnect()

For Kerberos, also call set_kerberos(True, kdcHost) on the transport.

  • Changing an interface UUID, version, or opnum causes a FAULT from the peer
  • Switching to NDR64 changes both pointer widths and array headers
  • A new auth_type needs handling in bind, AUTH3, and SIGN/SEAL on subsequent PDUs
  • Related tests: tests/dcerpc/, tests/misc/test_dcerpc_v5_ndr.py