What the Hell Is RPC?

If you’ve spent any time working with Windows or Active Directory, you’ve probably come across RPC (Remote Procedure Call). It’s one of those technologies that’s everywhere, but unless you’ve had a reason to dig into it, you might not know exactly how it works.

RPC allows one program to execute a function in another process, even if that process is running on a completely different machine. Instead of developers having to write their own networking code every time two systems need to communicate, RPC handles much of that work for them.

Pretty simple concept, but there’s a lot going on underneath.

It’s also something worth understanding from a security perspective. Attacks like PrintNightmare, PetitPotam and DCSync all involve RPC. Tools like PsExec use it to manage services remotely. In some cases, attackers exploit vulnerabilities in the services themselves. In others, they’re simply using legitimate Windows functionality to do things they shouldn’t be doing.

I want to break this into two posts. First, we’ll look at how RPC works, the different implementations, and how Windows uses it. In the next post, we’ll get into how attackers abuse it and what we can do to prevent that.

How RPC Actually Works

Normally, when an application calls a function, that function executes locally. You provide some arguments, the function does its thing, and you get a result.

Something like this:

result = GetUserInfo("GorillaTech")

Now imagine GetUserInfo doesn’t exist locally. Instead, the function is running on a domain controller somewhere else on your network.

With RPC, the application can make that call without having to manually establish a socket connection, construct a network message, send it to the server, interpret the response and so on.

RPC handles the communication between the two processes.

From the application’s perspective, it still looks like a normal function call. Obviously, there’s a network involved now, so latency, authentication and connectivity can come into play. But the developer doesn’t have to build all of that communication logic from scratch.

This isn’t new technology either. Andrew Birrell and Bruce Nelson published a paper called Implementing Remote Procedure Calls at Xerox PARC in 1984. The basic concept has been around for more than 40 years.

Microsoft adopted the DCE/RPC architecture in the 1990s and built much of Windows remote administration around it.

What’s Happening Behind the Scenes?

There are a few components involved in making an RPC call work.

The first is the interface definition. This describes the functions a service makes available, the arguments they accept and what they return. Microsoft uses Interface Definition Language (IDL) for this.

Think of it as the contract between the client and server. Both sides need to agree on what functions exist and how the data should be structured.

Microsoft’s MIDL compiler can generate client and server stubs from those definitions.

The client stub acts as a local representation of the remote function. When the application calls it, the stub takes the arguments and marshals them into a format suitable for transmission. In Windows RPC, this generally means Network Data Representation (NDR).

On the receiving end, the server stub unmarshals the data and passes it to the actual function.

Once the function finishes, the process works in reverse, returning the result to the client.

So our original function call looks something like this:

Of course, before the client can make that call, it needs to know where the service is listening. Some RPC implementations use fixed ports. Others, including Windows RPC over TCP, use an endpoint mapper to help clients locate the correct service.

One thing to understand here is that the server is executing a function because another process requested it. That makes authentication and authorization particularly important.

Just because someone can reach an RPC service doesn’t mean they should be allowed to execute everything that service exposes.

And as we’ll see in the next post, knowing who made the request isn’t always enough.

Different Types of RPC

RPC isn’t exclusive to Microsoft. There are several implementations, although they all follow roughly the same concept.

MS-RPC (Microsoft RPC)

Microsoft’s implementation of DCE/RPC. This is what you’ll encounter when working with Windows, Active Directory, remote service management and quite a few other administrative functions.

ONC RPC (Sun RPC)

Commonly associated with NFS and older Unix environments. It typically uses rpcbind on port 111 for service discovery and XDR for encoding data.

gRPC

Google’s modern RPC framework, open-sourced in 2015. Common in microservices and cloud-native environments. It generally uses HTTP/2 and Protocol Buffers, although other serialization formats are possible.

JSON-RPC

A lightweight RPC protocol that uses JSON to represent requests and responses. You’ll run across it in Ethereum APIs, language servers and some AI tooling.

For the rest of this article, we’re going to focus on Microsoft’s implementation.

That’s where things get particularly interesting from a Windows security standpoint.

How Windows Uses RPC

Windows supports several RPC transports, but the two I want to focus on are RPC over TCP and RPC over SMB named pipes.

Both are commonly encountered on internal Windows networks, and understanding the difference is important when we start looking at lateral movement.

RPC over TCP

Microsoft refers to this transport as ncacn_ip_tcp.

When a client wants to communicate with an RPC service, it can first connect to the RPC Endpoint Mapper on TCP port 135.

The Endpoint Mapper maintains information about registered RPC interfaces and their endpoints.

The client asks where a particular interface is listening. The Endpoint Mapper returns the appropriate endpoint, which for RPC over TCP is often a dynamically assigned port.

On Windows Vista and Server 2008 onward, the default dynamic TCP port range is:

49152-65535

The client can then establish a connection to that endpoint and make its RPC calls.

For example:

Port 49667 is just an example. The actual port depends on what the service registered.

This is why you’ll often see Windows firewall configurations allowing TCP 135 along with a fairly large range of dynamic ports.

It’s also why filtering RPC strictly by port can become a pain. You might know that a server requires RPC, but allowing the entire dynamic range potentially exposes quite a few other interfaces.

RPC over SMB

The other common transport is ncacn_np, which uses named pipes over SMB.

Instead of connecting to the Endpoint Mapper on TCP 135 and then a dynamic TCP port, the client establishes an SMB connection, generally over TCP 445, and opens a named pipe.

For example:

\\server\pipe\svcctl

The svcctl pipe provides access to the Service Control Manager Remote Protocol.

This is one of the interfaces used to manage Windows services remotely.

Other examples include:

\pipe\samr
\pipe\spoolss
\pipe\lsarpc
\pipe\atsvc

Each pipe provides a way to communicate with particular Windows RPC services or interfaces.

One important distinction is that these are not individual TCP ports. Multiple RPC interfaces can be accessed through the same SMB connection.

So blocking TCP 135 doesn’t necessarily prevent RPC communication. If TCP 445 is accessible and the required named pipe and interface are available, RPC calls can still take place.

There’s also ncalrpc, which Windows uses for local communication between processes, and RPC over HTTP, commonly associated with TCP 593.

For what we’re discussing, TCP 135, dynamic RPC ports and SMB on 445 are the ones to pay attention to.

RPC Interfaces Worth Knowing

Windows exposes quite a few RPC interfaces. If you’ve ever enumerated the endpoints on a domain controller, you’ve probably noticed just how many there are.

Some are particularly interesting from a security perspective.

MS-DRSR (DRSUAPI)

This is the Directory Replication Service Remote Protocol used by Active Directory domain controllers to replicate directory data.

One of its methods, IDL_DRSGetNCChanges, is responsible for retrieving directory changes during replication.

It’s also the method used during DCSync attacks.

A caller with the necessary directory replication permissions can request password-related data from a domain controller without logging onto the DC and accessing NTDS.dit directly.

That’s a pretty significant capability, especially when those permissions have been granted to accounts that shouldn’t have them.

MS-SAMR

The Security Account Manager Remote Protocol provides access to account and group management functionality.

Depending on permissions and system configuration, it can be used to enumerate domain users, groups and other account information.

This is one of the interfaces you’ll encounter when looking at Windows domain reconnaissance.

MS-SCMR

The Service Control Manager Remote Protocol allows remote management of Windows services.

This includes creating, starting, stopping and modifying services, assuming the caller has sufficient permissions.

Tools like PsExec take advantage of this functionality to execute commands remotely.

The service creation itself isn’t an exploit. It’s legitimate Windows functionality.

The security issue is whether the person or machine making the request should be allowed to use it.

MS-TSCH

The Task Scheduler Service Remoting Protocol exposes functionality for managing scheduled tasks remotely.

With the appropriate permissions, a client can register and execute tasks on another Windows machine.

As you can imagine, that’s useful for administrators. It’s also useful for an attacker who has compromised an account with administrative privileges.

MS-RPRN

The Print System Remote Protocol exposes functionality associated with Windows printing.

This is relevant to attacks like PrinterBug and to understanding Windows Print Spooler exposure.

PrintNightmare also involved RPC-accessible spooler functionality, specifically vulnerabilities involving printer driver installation.

MS-EFSR

The Encrypting File System Remote Protocol supports remote operations associated with EFS.

It’s particularly interesting because of PetitPotam, which demonstrated how certain EFSRPC calls could be abused to coerce a Windows machine into authenticating to another system.

The attacker doesn’t necessarily need to execute code on the target. Getting the target to initiate authentication can be enough to support a relay attack when other conditions are present.

We’ll cover that in more detail in the next article.

Looking at RPC on Your Own Network

One of the easiest ways to get familiar with RPC is to enumerate the interfaces exposed by a Windows machine.

Impacket includes rpcdump.py, which can query RPC endpoint information from a remote host.

For example:

impacket-rpcdump 192.168.1.10

Depending on how Impacket was installed, the command may also be available as rpcdump.py.

Point it at a domain controller and you’ll likely get a pretty long list of interfaces.

You’ll see interface UUIDs, protocol bindings, endpoints and other information that can help identify which RPC services are registered.

An example binding might look like this:

ncacn_ip_tcp:192.168.1.10[49667]

Or, for a named pipe:

ncacn_np:192.168.1.10[\pipe\svcctl]

You can also look at RPC endpoint information locally using Windows tools or PowerShell, depending on what you’re trying to inspect.

For example, to see the TCP connections associated with port 135:

Get-NetTCPConnection -LocalPort 135

That won’t enumerate the RPC interfaces themselves, but it can help when troubleshooting connections.

Keep in mind that enumerating an interface doesn’t automatically mean you can perform every operation it exposes. Authentication, permissions and additional service-level restrictions still apply.

Why I Think RPC Deserves More Attention

When we talk about network segmentation, we typically focus on which machines are allowed to communicate over which ports.

That works well enough for a lot of applications, but RPC presents an interesting problem.

Take SMB on TCP 445.

You might allow a workstation to communicate with a file server because it needs access to a shared folder.

That same connection can potentially provide access to RPC interfaces used for remote administration.

Whether those interfaces can actually be used depends on permissions and configuration, but the network connection itself is already allowed.

The firewall sees TCP 445. Unless it’s doing something more sophisticated, it doesn’t know whether the client is accessing a file share or attempting to communicate with the Service Control Manager.

The same issue exists with RPC over TCP. Allowing the dynamic RPC port range to a domain controller doesn’t distinguish between the interfaces a client legitimately needs and ones it has no reason to contact.

This is something I’ve been digging into quite a bit lately while looking at Windows lateral movement and microsegmentation.

There’s an important difference between allowing a machine to communicate with a domain controller and allowing that machine to invoke every reachable RPC interface on the domain controller.

Those are not the same thing.

In the next post, I’ll walk through DCSync, PsExec, PetitPotam and PrintNightmare, including the specific RPC interfaces and methods involved. I’ll also look at Microsoft’s built-in RPC filtering capabilities using netsh rpc filter, the open-source RPC Firewall project from Zero Networks, and how microsegmentation can reduce exposure before those calls ever reach the service.

Leave a Reply

Your email address will not be published. Required fields are marked *