 Okay. Hi everyone. Great to be here. We're both very, very excited. First, maybe we want to thank you for attending DEF CON organizers for having us, accepting us to talk here. Friends on the first and not the first lines to support. And thanks for coming to our talk on Microsoft RPC. We'll start by introducing ourselves. My name is O'Fair. I lead one of the security teams in Akamai Technologies in Israel. This has been senior security researcher in my team. These are our Twitter handles. You're very welcome to follow for more material and the things that we do and see our work. Okay. Why choosing Microsoft RPC as a vulnerability research target? And first of all, what is MSRPC? So Microsoft remote procedure call. It's practically an inter process communication protocol. It can take place both locally on a machine between processes, but also between machines in the network. And Microsoft implementation was written somewhere around the 90s, which is quite a long time ago. And the most important reason why we chose to try to target MSRPC is because it's practically everywhere. This is a screenshot from a program called RPC View. It's on GitHub. There's a link to it if you want to try it yourself. And it shows basically all RPC activity on your machine, on the machine where it runs. And here we can see a list of many processes that use RPC in some way. Either they host an RPC server in the process or they are RPC clients. Many Windows services use RPC to perform and expose their functionality over the network to various clients. But again, this is on a single machine and what I think is very interesting is to see RPC activity in a network. And here's a screenshot of one of a random network, let's say, Windows network, where the edges represent RPC traffic. So this specifically is traffic filtered for TCP port 135, which we will get familiar with soon. But what I want you to take away from this is that networks, Windows networks heavily rely on Microsoft RPC implementation. Good. Yet it's everywhere and there's not a lot of public research on it, at least not that we're too familiar with. So when we try to kind of bootstrap our research and Google Microsoft RPC, most of the information we found boiled to Microsoft's own documentation, which can be quite dazzling sometimes, specifically with old protocols. There are several research-oriented blog posts that we will reference to later on at the end of the presentation. And with regards to public vulnerabilities, also we try to look for bugs that were disclosed to Microsoft. And there weren't a lot of them. Lately, there have been a couple of vulnerabilities in the RPC runtime. I don't know if some of you may have heard. But again, not too many of them, not compared to other products on Windows. Our assumption, again, is that it's not such a fancy research target because it's old. As you'll see, it's quite complex. It has a lot of mechanisms to enforce security, which are not always synced with each other and can be quite confusing. And we thought it was actually a good thing to try to deep dive into. And what we had in mind was specifically exploiting RPC or the services that use RPC to gain lateral movement within a network and gain this ability to hop from one machine to another, or exploit RPC bugs to elevate privileges on a machine. So as I mentioned before, many Windows services use it. They run with higher privileges. Maybe exploiting their RPC server would lead to having higher privileges ourselves. So with the motivation in mind, this is our agenda for today. I will do the part where we all learn about RPC together, and then we'll talk about RPC security mechanisms and demonstrate a bug that he found in a very common Windows service. This is not getting any less exciting. I'm still very excited. Okay. Thanks. Okay. So RPC overview and thank you again. By the end of my section, what I want you to have learned is all these terms, all this terminology that you see here. It might be a little bit confusing, but hopefully if I do my job well, you'll get it right. So I mentioned before RPC, inter process communication protocol. It's based on a client server model. So the client wishes to execute some functionality on a server, local server, remote server, you name it. In our case, the client wants to run a function called foo, which takes two parameters. In our case, five and hello. But how does the client know that foo even exists, that foo is implemented on this server? For this purpose, we have RPC interfaces that are written into plain text textual files called IDL files. Interface definition language. If we scan from top to bottom, we see that an IDL or a very basic IDL file has the unique identifier of the interface at the top, the interface name, which in our case is test, and then the function declarations, parameters, return values, basically their prototypes. Water, I think. One minute. So that's a textual file. Applications can't really use it, right? So they need code. For this reason, Microsoft developed their own IDL compiler called MIDL or middle. It takes an IDL file as input and then outputs source and header files that the client and server can use. So as you can see here, we have files for the server and the client and a header file that is used by both. The two applications can then include these files and make whatever use they want with the RPC functionality. So this is all like very conceptual contract, right? This is how the client knows what the server is capable of, but how does the client know who to reach out to? For this reason, Microsoft came up with the notion of endpoints that are basically the gateways to the RPC server implemented on the server. So endpoints can use various transports. There's a pretty long list of network transports that can be the basis for the traffic. Here we have a non-exhaustive list. So we see TCP and UDP, HTTP, named pipes that are based on SMB, et cetera. For each such transport, we have the protocol sequence, which is a string representing the transport. And the endpoint itself is basically the TCP port, the name of the pipe, the host name for HTTP transports, et cetera. What I'd like all of us to remember for the rest of this talk is that the interface and the endpoint are registered separately. They're not bound to each other. So if I want to implement an RPC server, I can declare a single interface and have various endpoints exposing it, but I can also have various endpoints and expose them over a single endpoint. Good. Some examples for endpoints that we see on regular Windows machines. I don't know if you can see this well, but we see TCP ports here, some named pipes that some of you may know, UUIDs for Hyper-V sockets that are users transport, ALPC ports, et cetera. So really there's everything there. Speaking of endpoints, I want to make a distinction between well-known and dynamic endpoints. Well-known endpoints, as you can guess, are known in advance. So they can be hard-coded in the client and server applications. The endpoint can be hard-coded in the IDL file itself, but eventually the client knows in advance exactly who to talk to. So in our example, the client knows that the server is on TCP port 39776. But this can lead to trouble because these endpoints can be exhausted or one server can override another server's endpoints. So Microsoft came up with dynamic endpoints that are dynamically resolved. For this purpose, we have a Windows service that is called the endpoint mapper or EP mapper. This is a service that the client can query for the server's endpoints. And actually the EP mapper itself has a well-known endpoint, which is TCP port 135. We saw that before, if you remember. So the client simply asks the endpoint mapper, please give me the endpoint for server whose interface UUID is yadda yadda yadda. And they get in return the TCP port or names pipe or whatever it is they need to actually use. So this is it. Now to some examples of Windows services and their endpoints and interface UUIDs. I took three hopefully famous Windows services here. At the top is the task scheduler service. We see that it implements three different RPC interfaces, each with its UUID. But there is no endpoint specified here, right? There's no endpoint mentioned. So it's a dynamically resolved server or endpoint, sorry. The service control manager SEM remote protocol has a UUID for an interface and a well-known named pipe that we see over there in the middle. And the encrypting file system, maybe some of you have heard it due to somewhat recently disclosed vulnerabilities. This one has actually two well-known endpoints, two named pipes and also two RPC interfaces. This is all in Microsoft's portal. It's documented in their technical documentation section. Okay, so dynamic resolution. Let's see what it looks like by observing network traffic. This is a screenshot from Wireshark, obviously. We start by querying the endpoint mapper. Obviously, we start with the TCP handshake over TCP port 1-3-5. We do this handshake and then we move on to sort of what I like to call the RPC handshake, which is also called the binding process. And once we're done with that, we can query the endpoint mapper for the service endpoint. In this case, we're asking for the task scheduler endpoint. And now that we have this information returned to us by the endpoint mapper, we can move on to talk directly to the task scheduler. TCP handshake, as we can expect, and then the binding process again. And then we have an established session with the task scheduler. I mentioned binding, so let's cover this one. Binding is basically the representation or logical representation of the client server session. Practically, it's a handle of a Windows object, and both client and server can set and manipulate data on this object. We will see later on that it is mostly used for authentication purposes. I think we sort of covered all terms at this point, so let's try to kind of wrap it up with the full communication flow. So the client, as we already know, it tries to call foo function. This function is, when it's compiled by the Microsoft compiler, it calls RPC runtime function called NDR client call. I didn't mention the RPC runtime, but that's a library called RPCrt4.dll. It implements both the client and the server side of RPC operations or functionality. On the client side, it does all sorts of things, marshalling the parameters, namely converting them into network representation, being responsible for connecting to the endpoint on the server and authenticating if necessary. On the server side, after the connection has been made, the RPC is, well, before that, it's responsible for listening on the endpoint, then doing the reverse operation of unmarshalling the parameters that were sent to or with the function, and perform access checks on the RPC interface. We'll get into that as well. Eventually, the RPC runtime calls foo, and foo is implemented on the server and being executed. How does the RPC runtime actually specify foo? Well, it doesn't have foo as a string. It rather has an ordinal number of foo. So we already know foo is declared in an IDL file. It's then compiled to a client stub, and this stub calls the RPC runtime, where one of the parameters specifies the ordinal number of the function in the interface file. So since foo is our first, the operation number or opnum is zero. If it were the second function, it would be a one there, and et cetera. So actually remember opnum because it's important for the rest of the talk. Okay, so I think now we're really done. We'll just have a quick recap. Things are not aligned as I was expecting them to be, but okay. So interface, it's the logical representation or conceptual agreement between the client and the server, specifies the functions, and represented by a unique identifier, a UUID. The transport is a communication medium. It's represented by a string called protocol sequence. The endpoint is the actual destination or gateway to connect to. It's represented by a port number, a pipe name, an ALPC port, et cetera. The binding is the session itself and represented by a binding handle. So I think we should all be somewhat RPC experts at this point, and I'll hand the ball to Ben to talk about RPC security and the bug. Thank you, Ophir. So I'm going to talk about MSRPC security, and I'm going to divide this part into two sub parts. The first one is MSRPC security mechanisms. And this sub part is also the basis for the second one, security related problems in MSRPC. So the first thing I want to begin with is that the security mechanisms are basically a complete mess. There are multiple security mechanisms, there are system-wide policies, flags, and various combinations of those. So basically, it's really for a developer to make a mistake while trying to secure the interface. In our talk, we tried to simplify this part, and we are going to mostly focus on remote communication. For each security mechanism, we are going to specify relevant flags. Those flags are set during the interface registration by the server side. And the first authentication, the first security mechanism that I would like to talk about is authentication. And even for authentication, we have two types of authentication. The first one is not really explicitly set by the server or the client. It happens as part of the network interaction. So for example, when we used an endpoint like HTTP, then HTTP uses IIS authentication. And the more commonly used is the name pipe endpoint. And the name pipe endpoint is carried over SMB protocol. And the SMB protocol has authentication as part of the protocol. And it basically requires us to have a valid user for the target machine. In a domain environment, this is not really a problem. We have our own domain user. And that's enough to pass this check against another machine in the same domain. But if we're in some random network, some public Wi-Fi, for example, then unless we have the credentials of a local account on that machine, we cannot pass this check. And in the past, they used to be the option to specify or use the null session access, which basically means providing no user at all. These days, it doesn't work anymore. But there is one caveat. And that's the DC, only for those specific name pipes. So those are configured in a system like policy. And basically what it means is that an unauthenticated client coming from outside the domain can connect to those specific name pipes on the DC, the domain controller. So is it the end of the world if we decide to use an unauthenticated transports like TCP or UDP? The answer is no, because there's another authentication and this is authenticated binding. So just a quick reminder, binding is the representation of a logical connection between a client and a server. So authenticated binding is a binding that has authentication info. And that happens when the server registers authentication info and the client sets authentication info. Why do we actually need this mechanism? Well, it gives us the option to have identity based access control and also various network protections. So we can have the RPC call encrypted or tamper proof against many of the middle attacks of spoofing. And the level of protection is specified by the authentication level. This is set by the client and later on the server can inquire what level was used. So how does this process look behind the scenes? Basically there's a bind-bind-acc package exchange. Those contain the authentication info section. And at the end of the day you have the security provider handle this data. So basically you have the NTLM security provider or the Kerberos one or Negotiate which chooses the best available option between NTLM and Kerberos. And as you can see here we have a snippet from Walshark and it has the authentication info section and we can see the NTLM security provider is used and also the authentication level is sixth, a packet privacy, the highest one. The end result of this process is a security context and the security context is somewhat similar to a normal binding. You can inquire information like what level was used, what security provider was used. Okay, so what's the catch with authenticated binding? If the server register authentication info, it doesn't mean that the client is going to authenticate. He's not in force to, he's not obligated to authenticate. So basically what that means is unauthenticated clients can still access the interface even if the server did register authentication info. And we can see this in this access metrics below. We have an unauthenticated client from the client side and authenticated binding from the server side. And the end result is still success. The client can access the interface. Obviously if we are a server developers and we register authentication info, that means that we want the client to authenticate. So what can we do? We can specify the following flag and the following flag basically tells the RPC runtime to make sure that the client uses an authentication level of at least one, which basically means that the client indeed authenticated. Okay, so let's move to another security mechanism. This is the security descriptor. And the security descriptor is a general windows security mechanism. The concept is that we can set a security descriptor on a windows object. And the security descriptor contains rules like this user can access the object, this user cannot access the object, this group can access the object, et cetera, et cetera. Later on when a client tries to access the object, then windows are going to compare his access token against the security descriptor. And in our case, the object is the endpoint and the interface. So it can set a security descriptor on both the endpoint and the interface or none of them. Cool. So this is an example of a real security descriptor. We can see the security descriptor string and we can convert it into something readable. This is from a service called app ID service. And yeah, so we're going to move to the last security mechanisms. And this is also the one that we believe to be the most interesting one. This is the security callback. And the security callback is basically function callback that is called every time the client tries to access a function on the server. And the logic of the security callback is up to the developer. They can write whatever they want there. But the purpose is to restrict access to specific functions or users or groups, et cetera, et cetera. So here we have the prototype of the callback. It basically receives the interface UUID and also the context which the server can inquire information about the call or the user or the connection. Now one small thing to note is if the server registers a security callback, then unauthenticated clients are going to be denied automatically. So this is another way to prevent unauthenticated clients from accessing the interface. Let's move to some examples to get us familiar with security callbacks. So here we have the task scheduler security callback. And we can notice that it checks the authentication level is at least back at privacy. The IS one also checks the protocol sequence that the client used. So here we have the IAS which checks if the client is a remote one. And if it is, then it needs to use at least back at privacy. Authentication level also checks the protocol sequence. Here we have the DHCP one which checks basically the protocol sequence. And finally we have ELSAS. And ELSAS does things a little bit differently. It makes a distinction, separation, distinction based upon the opnum that the client called. So if the client calls opnum zero, for example, then the transport that should have been used is TCP and opnum one, then it needs to be name pipe, et cetera, et cetera. Cool. So this flag relates to what I've said before about the automatic behavior of automatically denying access to unauthenticated clients. And basically these flags just disabled this behavior so it allows or gives the chance to unauthenticated clients to still access the interface if they pass the security call back. Okay, so we talked about some security mechanisms and we talked about some caveats of those. Let's talk about two design flaws that we found interesting. And the first one is actually somewhat described by Microsoft. Be wary of other RPC endpoints running in the same process. And basically what it means is let's imagine the phone scenario, we have a client in a server and Interface A registers is a local interface and Interface B is a remote one. So Interface A is supposed to be accessible only for local clients and therefore it holds local privileged operations. Interface B is for remote clients. So Interface A registers an ALPC endpoint which is only accessible locally. You can't use LPC over the network. It's an IPC protocol and Interface B registers a TCP endpoint which is a remote one socket. So the client can access Interface A, the local one using ALPC and it can also access Interface B, the remote one using TCP. But here's the actual catch. The client can access Interface B, the remote one using a LPC and more than that it can actually access the Interface A, the local one using TCP. And basically what that means is that a remote machine can access the local interface using TCP and therefore access a privileged operations. And there is another one problem here and that happens when Interface A registers a security descriptor on the endpoint. And the reason is because the client can just use the TCP endpoint and bypass this mechanism, the security check. So why does this happen? This happens, this relates to something that I said before, interfaces are not bound to endpoints. And basically we can have multiple endpoints and we can access each one of the interfaces using each one of the endpoints. But in what real life scenario we will not be aware of other endpoints running in the same process. So in Windows when you write a service then this service is going to be run inside the SVC host process. And that SVC host process might run other services as well. So you might share the same SVC host process with other RPC servers that did in fact register other endpoints. So what can we do to prevent this from happening? We can specify the following flag and the following flag basically tells the RPC runtime to make sure that the client that accesses the interface is a local one. So it doesn't matter what endpoint it's used, it must be a local client. And about the security descriptor problem, well Microsoft just recommends to not use it on the endpoint. Now let's move to another design flow that we found interesting. This is undocumented. This is the security callback caching and I'm going to explain it using the following diagram. So let's say we have a client and a server and the server exposes several functions, op num 0 and op num 1, et cetera, et cetera. And the client tries to call op num 0 and the security callback is called and it says op num 0. Okay, you can access this function. Now the client tries to call op num 1 and the security callback is called and it says op num 1. Yeah, not really. Access denied. So this is what you would expect to happen. But then security callback caching comes right in and changes what happens. So this is how it actually goes. The client calls op num 0, the security callback is called and it says, okay, yeah, you can access this function. And now the result is actually cached. So the next time the same client is going to call the same interface, then the cache is going to be used. So the client calls op num 1 and the RPC runtime says, okay, same client, same interface, you can access this function. And this is obviously not something that we want. This is a dangerous behavior. The client can now access op num 1, although it should not be possible, not supposed to be. So when does this actually happen? This is actually the default behavior for security callbacks. But there is one requirement. The whole caching mechanism depends or relies upon the context identifier of the security context. So the security context is the output of the authentication process. So basically if the binding is not authenticated, then there's no caching. And what can we do to prevent this from happening? By now you should have guessed. We can use one of the two following flags, the first one is somewhat documented. The other one is not documented. The first one basically disables the whole caching mechanism. And the other one changes the default behavior to be on a call basis instead of an interface basis. And that basically means that if the client calls op num 0, then cache entry is going to be created for op num 0. And if it's going to call op num 1, then it's not the same function. The security callback will be called and returns access denied. And if it does decide to call the same function again, then the cache entry will be used and it can access op num 0. Okay, so just a quick recap. We talked about a security mechanism, some caveats, some interesting design flaws. And in our research we found the security callback to be the most interesting place to look into an interesting attack surface. So we decided to look into multiple services and also their security callbacks. And by doing so we found a couple of vulnerabilities, but most of them are still under disclosure. There is one interesting vulnerability that we can talk about. And this is a bug in the server service. So I'm going to talk about the bug and the exploitation and also show a quick demo. So the server service, which is also known as Lannman server, is the service that is responsible for the management of shares, where shares are basically resources like folders or printers, for example, that are shared with other network machines. The service runs by default on all Windows machines and it is accessible through the name pipe SRV service. From now on I'm going to call it SRV service for privacy. It is just much easier. So let's take a look at the security callback of SRV service. And basically the logic of the security callback implemented by the server is to check that if the client tries to access the range of opnums between 64 to 69, then deny access if he is a remote client. So those functions are only available to local clients. And when we saw this code, we kind of theorized that maybe in other RPC services that implement similar logic or maybe in newer versions of this service, they might screw up and there will be availability. So we decided to be on the lookout and look for newer versions. And when we looked into SRV service security callback in Windows 10 20 H2, we noticed that four new functions were added, but the range also changed to include them. So there is no vulnerability here. The code is still okay. And at this point we thought, okay, well maybe they have a macro to somehow automatically calculate this range and it wouldn't have any vulnerability. But we didn't give up and we decided to look into Windows 11 security callback. And in Windows 11 we noticed that a new function was added and the security callback didn't change. The range did not change at all. And the function is a local one. It's local R server certificate mapping modified. This is obviously a local one. And the range does not include this function now. So that means that a remote machine can now access this function. And this is obviously a vulnerability which received the foreign CVE with CVSS score 8.8. So before I talk about what we can do with this function and the exploitation, let's talk about what it relates to. And this relates to a feature called, feature called SMB over Quick where SMB is the SMB protocol. And Quick is somewhat new transport layer protocol designed by Google not that long ago with the purpose of being secure and privacy in mind and also low latency. And as part of the network interaction in Quick, the server provides a certificate and that allows the client to verify the identity of the server. Basically that prevents spoofing attacks or many in the middle attacks. And those new functions that were added, they basically manage the symbolic link between a Quick certificate to a real certificate in the Windows certificate store. So certificate mapping is basically a symbolic link. Okay, so as you can understand, we can modify and existing certificate mapping and therefore do some tampering, many in the middle attacks maybe. But we ask ourselves, can we do more than that? And when we looked into the structure that the function receives, this is after some reversing, we notice the store location variable. And this variable is basically the path of the Windows certificate store. And we thought, okay, well, what would happen if we provide the UNC path? And the UNC path is basically the path of another network machine. And by doing so, we managed to cause the RPC server call, send an RPC request to a machine that we can control. And why is this interesting? That's interesting because as part of this interaction, the RPC server presents his authentication info. And we can now take this authentication info and relate onto another network machine, basically impersonating the RPC server and saying hi, I'm that RPC server. Here's my authentication info. Let me access your service. So for those of you who are familiar with Petit Potam or DFS Coers or Shadow Coers, this is the same exact scenario. We have an authentication, Coers and vulnerability. And in order to exploit this, I base the exploitation on a research by Specter Ops, guys where they found out that you can relay the authentication info of the DC, the domain controller to ADCS, the Active Directory Certificate Service. And by doing so, you can receive a certificate of the DC machine. And I'm going to work through the exploitation, although this is not the main part of the talk. So we begin by using the vulnerability we found, the authentication Coersion. And as a result, we get the credentials of the DC. Once we have the credentials of the DC, we can relay it onto the ADCS and we get a certificate from the ADCS. Using this certificate, we can now request the Kerberos TGT. And with the Kerberos TGT, we can now perform DC sync attack, which basically allows us to retrieve NTLA mashes of local accounts. And finally, once we have the NTLA mash of an account, we can use past the hash attack and get a shell. So I'm going to show a quick demo of this. One second. About it. One second. We do have it on here. So maybe wait one second. Do we have speaker ops here somewhere? Speaker goon, somebody? We have a demo. We want to show it. From this laptop. It's here. Saturday. Yeah, you're up. Okay. Yeah. Does it play? No, it's not. It's not showing. We see it. You want to come here? Watch it with us. How? She has a video. Yeah, yeah, yeah, but you got an extended view. So only you're going to look at it. But what we can do is I can go to logo. You can put it on mirror and then point at me and I'll bring it back up and then we can't we just flip the mirror. I thought I said it would have been better to go to logos. How are you doing all? Please be patient. Just one more minute. We really want to show it. Right. So, okay, so we have here the DC machine. This is the machine that we are going to attack. And here we have the relay machine. This is a Linux machine, which is going to relay the credentials of the DC to the ADCS. And here we have the attacker machine. This is the one that is going to trigger the vulnerability that we found. And we are going to initiate the request. And as you can see, we receive the certificate of the DC. That means that the attack worked. And now we're going to use the full exploitation. We are going to use a tool called Ruberos and use the certificate to request a Kerberos TGT. Now we are going to just make sure that the Kerberos TGT was imported into the K-list, the local Kerberos TGT list. And now we are going to use the tool Mimicats to perform DC sync attack. And now we are going to actually retrieve the NTLM hash. And with the NTLM hash, we can now perform past the hash attack using WMI exec to basically get a shell on the DC machine. So we are running inside the DC to presentation. Okay, so to summarize, we found the security callback to be an interesting attack surface, specifically those who deal with opnams, also because of caching. We encourage other researchers to look into other services, also SMB over quick. We also believe the RPC are trying to be on the research target. The blog post and POC will be shortly available in Akamai's blog post. Also stay tuned because we have other vulnerabilities that are still under disclosure. So once they are fixed, we will share the details. And finally, those are some references to some great blog posts by other authors. This is also the opportunity to thank them for those. And that's it. If you have any questions, then feel free to approach us so you can also send us a message in Twitter.