Okay, hi everyone. Great to be here. We're both very, very excited. First, maybe we wanna 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 Ophir. I lead one of the security teams in Akamai Technologies in Israel. This is Ben, 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. Whew, 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's implementation was written somewhere around the 90s, which is quite a long time ago. And the, 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, or they use a 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, 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, to 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 tried 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 Ben will talk about RPC security mechanisms and demonstration. And then I will 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. I'm good. 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 it's not. 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, they're prototypes. Water, I think. One minute. Okay. 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 a number of types. 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 wanna 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 used as 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 EPMapper. This is a service that the client can query for the server's endpoints. And actually, the EPMapper 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 yada, yada, yada. 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. So the connecting 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 a 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 a 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, marshaling 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 unmarshaling 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 specify 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 really are 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 a function. It's represented by a unique identifier, a UUID. The transport is the communication medium. It's represented by a string called protocol sequence. The endpoint is the actual destination or a 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 you. 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 subparts. The first one is MSRPC security mechanisms, and this subpart is also the basis for the second one, security-related problems in MSRPC. Ophir. Ophir, thank you. So the first thing I want to begin with is 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 developer to make a mistake while trying to secure the interface. In our talk, we tried to simplify this part, and we're going. 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 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 more commonly used is the name type endpoint. And the name type 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 different. We had 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 types. So those are configured in a system-wide policy. And basically what it means is that an unauthenticated client coming from outside the domain can connect to those specific name types 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. 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 or spoofing. And the level of protection is specified by the authentication, authentication level. This is set by the client, and later on, the server can inquire what level was used. So how does this process looks behind the scenes? Basically, there's a bind-bind-ack packets 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. So you can either use 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 Wildshark, and it has the authentication info section. And we can see the NTLM security provider is used, and also the authentication level is six, 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 enforced 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 you're a server developers, and you 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 client. And 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. OK? So that's the answer. But the purpose is to restrict access to specific functions or users or groups, etc., etc. So here we have the prototype of the callback. It basically received 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 ourselves 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 this privacy, the IS one. Also it 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 packet privacy. Authentication level also checks the protocol sequence. Here we have the DHCP one, which checks basically the protocol sequence. And finally we have LSAS, and LSAS does things a little bit differently. It makes a distinction separation. It makes a distinction separation. It makes a 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 named by, 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 disable the security. And this behavior also allows or gives the chance to unauthenticated clients to still access the interface if they pass the security callback. 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. Before Microsoft. So Microsoft is really worried about other RPC endpoints running in the same process. And basically what it means is, let's imagine the following scenario. We have a client and 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 ALPC 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 idea. What's the actual catch? The client can access interface B, the remote one, using ALPC. 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 privileged operations. And there is another one problem here. And that happens. What 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 relates to something that Ophir 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 TCP. 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. Okay. Now, let's move to another design flow 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, opnm0 and opnm1, et cetera, et cetera. And the client tries to call opnm0, and the security callback is called. And it says opnm0. Okay. You can access this function. Now the client tries to call opnm1, and the security callback is called. And it says opnm1, 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 opnm0, 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 opnm1, 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 opnm1. Although it should not be possible. Not 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. Okay. 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 opnm0, then cache entry is going to be created for opnm0. And if it's going to call opnm1, 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 opnm0. 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 mechanism to be a bit more complicated than the security callback, to be the most interesting place to look into and 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 LAN LAN 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 type SRV service. From now on, I'm going to call it SRV service for brevity. It is totally free. So it's 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 open arms between 64 to 69, then deny access if he's a remote client. So those functions are only available to local clients. And when we saw this code, we kind of... Terrorize that maybe in other RPCs, services that implement similar logic, or maybe in newer versions of this service, they might screw up and they will be a vulnerability. So we decided to be on the lookout and look for new versions. And when we look into SRV service, security callback in Windows 10, 20H2, we noticed 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 call back. And in Windows 11 we noticed that a new function was added and the security call back 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 following CVE with CVSS score 8.8. So before we talk about what we can do with this function and exploitation let's talk about what it relates to. And this relates to a feature called feature called SMB over QUIC where SMB is the SMB protocol and QUIC 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. So this is a feature called SMB over QUIC and also low latency. So this is a feature called SMB over QUIC and as part of the network interaction in QUIC the server provides a certificate and that allows the client to verify the identity of the server. Basically that prevents spoofing attacks or man in the middle attacks. And those new functions that were added they basically manage the symbolic link between a QUIC certificate to a real certificate in the Windows certificate store. So this is a feature called certificate mapping and it is basically a symbolic link. So as you can understand we can modify an existing certificate mapping and therefore do some tampering, man in the middle attacks maybe, but we asked ourselves can we do more than that? And when we looked into the structure that the function receives, this is after some reversing, we noticed 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 a 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 to 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 is the RPC server's server presence is 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 the DFS coalesce or shadow coalesce, this is the same exact scenario. We have a network machine that is an authentication coalesce and vulnerability. And in order to exploit this, I based the exploitation on a research by Spectre 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 walk through the activity. So this is the exploitation, although this is not the main part of the talk. So we begin by using the vulnerability we found, the authentication coalesce, 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 a Kerberos TGT and with the Kerberos TGT we can now perform DC sync attack, which basically allows us to retrieve NTLM hashes of local accounts. And finally once we have the NTLM hash of an account, we can use pass the hash attack and get a shell. So I'm going to show a quick demo of this. And let's see if we can do that. . . . . . with MP Alma. One second. Okay. We do have it on here, so maybe wait one second. That had to happen. Okay. Do we have speaker ops here somewhere? Speaker goons, somebody? Yeah, the files. We have a demo. We want to show it. Can we access the sync folder here from this laptop? It's here. Saturday. Yeah, you're up. Okay. You're up? Yeah. Yeah. Okay. Does it play? No, it's not. It's not showing. We see it. You want to come here? Watch it with us. Maybe you have to mirror your display in order to do that. How? The AV guys come up. Yeah, I can see you. So, look. She has a video on it. 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 it'll go. But can't we just put the mirror? You can do that. You know how to put it in there? Yeah. That's fine. You can go back up and then you can put it on there. You can do that. Okay. Okay. Okay. All right. That's what I said. It would have been better to go to logo, so nobody would have seen all this, but. How are you doing all? Please be patient. Just one more minute. We really want to show it. There you go. Okay. Okay. Okay. This is the machine that we are going to attack. And here we have the relay machine. This is the 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 received the certificate of DC. That means that the attack worked. And now we are going to use the full exploitation. We are going to use a tool called Rubeus 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 TGT. And we are going to use the tool Mimikatz 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 pass the hash attack using WMI exec to basically get a shell on the DC machine. Cool. So we are running inside the DC. Okay, so back to presentation. Okay, so to summarize, we found the security callback to be an interesting attack surface, specifically those who deal with open arms. Also because of caching. We encourage other researchers to look into other services, also SMB over quick. We also believe the RPC runtime to be under 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. 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. Thank you. Thank you.