 ב pockets, 3 3, כל Welkom to track 3 3. is a new speaker 3. is a new speaker 3. is a new speaker 1. first time speaking 1. first time speaking 1. what does that mean 1. what does that mean 1. let's start off 1. let's start off 1. with saying 1. 차אים טראנ today we are going to be talking with you about a new method to dump the memory of 1. Al Jazeera 1. Al Jazeera 1. Al Jazeera which is called Al Jaze as Stinkering 1. Al Jazeera in case you don't know, Stinkering is the Hebrew word for snitch שלום לכם. sorry. We are going to snitch on Elsa's. And we all know the phrases snitches get stitches, but luckily no one will know this is us. So a little bit about us. This method was discovered by Asaf Gilboa, a friend and a colleague of mine. Unfortunately he couldn't join us today. And my name is Ron Ben-Itschak. I'm a security researcher at DP Instinct. And the fun fact about me, last night I lost 300. Dollars at the casino. So this is the agenda for this talk. I'll start with an overview about credential-dabbing attacks. I'll go over known memory-dumping techniques and common tools. Then I'll explain how this method was discovered by reverse-engineering the client-side of the Windows error reporting mechanism. Then I'll talk about reverse-engineering the server-side, and I'll finish with ways to detect and prevent this attack. So credential access is a huge subject. It's a whole tactic in the mitometrics. And on this screenshot you can see all the techniques under this tactic. In this talk I'll focus on the ELSA's memory sub-technique. Credentials are important for attackers. They use it to move across the network, spread their tools, and usually they're ransomware. And harvesting valid credentials is a simple way to log in to other systems. It doesn't require exploiting vulnerabilities. The holy grail for attackers is the domain controller. Credential access is constantly used in actual attacks in the wild. And here you can see reports from multiple security vendors about some of the most infamous groups today that use credential-dumping as part of their attacks. You can see reports about conty, black cat, lock bit, and many more. But how does a credential-dumping attack go? So once a user has logged in to the system, their credentials are stored in the memory of ELSA's. This memory can be read and written to disk, then passed by its tools like Mimicats. The credentials are extracted and used for lateral movement. So a little bit about ELSA's. The local security authority subsystem service. It is a system process that is responsible for authenticating users and verifying log-ons. And the problem with this is that it works as a single sign-on. Like I said, the user logs in once and the credentials are stored in the memory of this process. And this memory can be dumped to disk by other processes with APIs like mini-dump, pry-dump. Another thing we should talk about is the Windows error reporting service. It is a building component of the Windows operating system. It collects information about processes that had an unhandled exception and can create memory dumps of those processes. We already looked into this service as part of a previous research that I'll talk about soon. And the target of this research was to find a new way to perform a credential-dumping attack. We wanted to force this service to dump the memory of ELSA's for us. And that way we will have a stealthy way to evade EDR solutions. Now let's talk about some existing dumping techniques. The first one is using the tool PROC Dump, which is part of SIT's internals. It can dump the memory of ELSA's with the following command line. Here is the example for that. And another way to do that is by using the DLL, commerce VCS. It has an exported function, which is called mini-dump. You can supply the process ID of ELSA's to this function. And this will do the work for us. And here is an example for that as well. Here are easy ways to just use the Task Manager. We can right-click on the process and select Create a Dump File. Now another method we should talk about is Silent Process Exit, which was also discovered by us. And it is a documented mechanism that was introduced in Windows 7. It is activated when a process terminates. And it can do one of the following. Show a message box, launch a new process, or create a Dump File. You can configure this mechanism by using the registry. Simply create the keys and the values for the process this mechanism should operate on, and trigger it by calling RTL Report Silent Process Exits. And this is the research I mentioned earlier. Behind the scenes, it communicates with the Windows error reporting service. And also for the rest of this talk, I'll refer to the services that were service. Now I have to show off a little bit. So this method caught the attention of Benjamin Delphi, Florian Roth, and also a Reddit user tested it against a security product, and it's completely bypassed it. But there are protections against dumping the memory of Velsas, such as protected process slides, or PPL. This is a security mechanism in Windows that prevents tampering with sensitive processes. A flag is set in the kernel for the protected process, and it restricts the access that the regular process can gain on it. As this can be set as a PPL with a single registry value. And that will prevent other processes from gaining a handle with the permission of VM Read. The permission that is required for reading the memory of another process. So you might be thinking that PPL is a perfect solution. But there is a problem with it, especially for enterprises and large networks. It prevents third party DLL files from loading into Velsas. That means that benign authentication packages and plugins cannot be used. It can cause issues when there are many solutions and products that are installed in the network, and that is why some organizations don't use it. So we talked about several dumping techniques, and they all have issues. They are easy to identify, either by the command line or the APIs they use. And also some of the tools might be blocked by security products. So now let's talk about ELSAS stinkering. Like I said, it is a new method to dump the memory of ELSAS, and it doesn't use a vulnerability. It abuses the service we talked about, the Windows error reporting service. We are going to manually report an error to this service that will make it think that an exception occurred inside ELSAS. Then it will produce a memory dump for us without terminating it. This will bypass security products that allow processors like werefolds to dump the memory of ELSAS. This is an abstract of what is going to happen. We are going to create a message, then start the service, send the message to the service, is going to process and validate it, and hopefully perform the dump. What is required for the dumping procedure is an inheritable process handle with VM-read and query-limited information, also an inheritable thread handle with query-limited information, and the final requirement is setting the registry value dump type under the local dumps key to full dump. Now let's see what happens when a process crashes. This process tries to read the others zero. The report spawns as a child process and produces a memory dump. But what happened behind the scenes? Every process has exception handlers, and the last one is called C-specific handler. It is implemented inside NTDLL, and it is responsible for two things. The first one is reporting the exception details to the were service. It does that by calling NT-ALPC, same way to receive ports. And the second thing is terminating the process. So that raises a question, can we report an exception on our own process? And turns out, the service won't terminate our process. The responsibility for terminating the process that crashes is on the process itself. So how do we do that? How do we report an exception on our own process? To understand that, we need to reverse engineer the client side of well. Sorry. I'll start with explaining how to create a message. Then we'll see how to send a message, and eventually we'll do that and see what happens. So the function wereP report fault internal is responsible for creating a message. It starts with creating two unnamed events. These events will be used by the service. It will signal them to communicate with the clients. The next step is creating an unnamed file mapping with the protection of read-rides. This mapping is then open into a view. The step after that is duplicating the pseudo-handles for the process and the thread. Then all those values are written into the file mapping as an undocumented stock. Those values are also sent to the function report exception internal, which stores them in another undocumented stock and send it to the function sendMessageToWareService. But before we send the message, let's understand how the communication between the client and the server work. So the communication is done with the advanced local procedure call, or the LPC protocol. It is an undocumented IPC mechanism, which is used by RPC. And on the client side, there are two important functions. The first function receives a string that represents the server and retains a port and a del. The second function is called LPC SendWayToReceivePort, and it uses the port and it will send the message to the service and receive a message back. The next function we're going to talk about is SendMessageToWareService. Before the message is sent, we need to make sure the service is running. So this is done by calling anti-update WNF state data with the parameter WNFWareServiceStart. Then we signal the service, it starts initializing, and once the event system error report ready is signaled, we know that the service is up and running. The next step will be using the string Windows error reporting service port to connect to the LPC port, and finally, we can send the message. So let's try to do that. We are reporting an exception on our own process. The POC tool is launched, Warfault spawns as a child process. We wait for it to finish, and a memory dump is produced. And also the tool continues to execute until it exits. So let's talk a little bit more about what happened in this demo. When the service receives a request, it duplicates the file mapping handle to access the undocumented stack that was written into it. And also two instances of Warfault are spawned. The first instance is spawned under the service itself. And the command line of this instance specifies the file mapping handle, the idea of the process that is being reported on, and the idea of the process that sent the request. The second instance of Warfault is spawned under the process that sent the request by calling create processes user. And this will be the process that eventually calls mini-dump pry-dump and report the exception details to the event log. So now we know how to send report an exception. So let's try to report on LDAS. We can just change the process ID and the handle. So let's see what happens. We launch our tool, but it fails, and it specifies an error code. So what happened? The message back from the service specified an error code, which means access denied. And to understand why we got that, we need to reverse engineer the service side of Warf. I'll start with an overview about the service, then we'll see where the error code came from and what we need to do to pass the validation checks performed by the service. The Warf service is implemented inside the WarSVC.dll, which means it is executed under SVC host. This service is also set to manual start, which is why we needed to signal it first. The information about programs that crashed is sent to the service, and the logs that are produced will be used for diagnostics. The service initialization process happens inside the function startLPCserver, and we can see this function uses a string we already saw, Windows error reporting service port. This string will be part of a struct called object attribute, and this struct will be sent to LPC create port. And also the next step in the initialization is creating a thread for the function static LPCserver thread. This function will process incoming LPC messages. So now let's see why we got that error code. To find that out, we search for references inside a code for this value. We place the breakpoints on each reference and executed the service. Where breakpoint that hits is inside the function, check if system connecting to port. So what is this function? The first thing it does is calling a personate logged on user. The third that renders our request is executed under the same user as the service, which is anti-authority system. But after the impersonation, it will be executed under the same user as the process that sent the request. Then it tries to open the event where we see system permission is event, but that call fails with the error code access denied, which causes our request to fail. So what is so special about this event? Why can't we access it? To learn more about this event, we search for other references to that string. It is referenced inside a function start LPCserver, the same function that initializes the service. And here we can see the creation of it. It is created with a security descriptor that specifies generic read to the system user. But there is also another special thing about this event. It has a prefix. So now we need to understand what is the purpose of this prefix, so guess what we did? We searched for other references to that string. It is referenced inside a function create private namespace. Now let's understand what are those. That namespaces are used with objects called boundary descriptor to protect from a squatting attack. This is a denial of service attack where one program interferes with the execution of another program by using shared synchronization objects. Or in other words, unprivileged application creates the object before the privileged application, thus denying access to the legitimate one. And here is an example for that. In CIE, we have a malware and an EDI agent executing on the same system. The malware executes first as a low privilege process, and then the EDI agent starts as a privileged one. The malware tries to create the mutex, service mutex, and it is the first one to try to do so, so it will be successful. And then it starts doing malicious stuff. Then the EDI agent starts. It tries to create the same mutex, but the error code will be error already existing, and then it will exit. So how does objects protect from this attack? Private namespaces are like directory for canal objects. Canal objects that are created inside this directory are protected by boundary descriptors. And those descriptors contain the security IDs for the users and the groups that are allowed to create objects inside this directory. Another important thing is that namespaces are identified by both the name, the string, and the boundary descriptor. This means that different namespaces can have the same name, but different boundary descriptors. So let's look at the example again. But this time the mutex is created under a namespace that allows only the administrator's group to create objects. The malware will try to create the exact same namespaces the EDI agent uses. To do that, it needs to have the same name, which is easy, but also the same boundary descriptor. The malware can't create it because it is running as a low-privilege process. So let's see what happens. It will try to do it, but then it will fail and exit. Then the EDI agent starts. It starts as a privileged process, so it is able to create the exact namespaces it needs, and then it is the first process to create this mutex. So there will be error success, and it will be able to protect the system. So basically, namespaces protect named objects from unauthorized access. And creating a private namespace enables applications and services to build a more secure environment. So let's see how we do that. The first step is calling create boundary descriptor. And then the security IDs will be added by calling add security ID to boundary descriptor. And the final step is calling create private namespace and send the boundary descriptor as a parameter. And this is exactly what the world service does. Let's look at the function create private namespace. It creates a boundary descriptor, which is called worst VC namespace boundary. Then it adds the security ID that represents the service to that boundary descriptor and creates the namespace worst VC. That means that events that are created under this namespace were 100% created by worst VC, by no one else. Then the event is created, and it is protected by two things. The first one is the namespace, and the second one is the secure descriptor, which specifies a generic read access only to the system user. So now we understand what is this event. So let's look at the validation checks that are performed by the service. The first one is comparing the idea of the process that sent the request to the idea of the process that is being reported on. In our first example, we reported on ourselves. So those two values were the same. But now we're trying to report on ELSAS. And the sender PID is set by the kernel. We have no control over that. So those two values are different, and this check fails. The second check is performed by the function check if system connecting to port. The function we already talked about. And it basically checks this client security ID. Initially, that check failed in our example. But eventually we were able to pass this validation check. So that made the third one a bit irrelevant, and I won't go into much details, but it compares the package name of the two processes, and package names are related to Windows apps. So let's see how we passed the second validation check. Check if system connecting to port basically checks if the sender runs as anti-authority system. Initially this is what happened. Like I said, the thread started as anti-authority system, then impersonated our user, and the event failed, opening the event failed. So all we needed to do is execute our tool as anti-authority system. And after the impersonation, the thread stayed as anti-authority system, and the event is opened. So to recap, this is the attack. We execute our tool as system. It creates two undocumented stocks. The first one will be written into the file mapping, and the second one represents the LPC message. Then we signal the service, and it starts initializing. It creates the namespace with the boundary descriptor, creates the event under the namespace, and also the LPC port. Then we send the message, and the service starts processing it. It compares the sender PID to the target PID that fails, and then it opens the event after the impersonation that works, and the request is marked as valid, and a dump is performed. So let's look at that. We launch our tool again, but this time, no error code is specified. Warfault spawns as a child process, and a memory dump of Elsas.exe is produced. So now that we understand what is this attack, let's talk about detection and prevention. This attack leaves several artifacts on the system. Let's talk about each one. The first one is in the event log. The event ID, an event ID with the ID of 1,000 is generated under the application log, and it specifies that an exception occurred inside Elsas. But the most important thing is that our tool isn't mentioned anywhere in this event. This event can't be used to trace the attack back to us, back to our process. The second artifact is the dump file itself. It is created under the crash dumps folder, and the existence of it is suspicious, but it is created by warfault.exe, and not our process. So the creation of the file can be traced directly back to us. Another log that is generated is under the war report archive. It is a different type of log that specifies the details of the exception, and again, the most important point is that the process that sends the request isn't mentioned anywhere there. One thing that can't be used to detect this attack is the command line of warfault.exe. It specifies the idea of the process that is being reported on, and also the process that sends the request. So if the target process is Elsas and the source process isn't, it is a strong indication of this attack. But let's also talk about the advantages of this attack. Warfault is doing the dump, and this is great, because it is a legitimate system process that exists on every version of Windows. The crash report doesn't specify anything about our process, and this tool can be compiled as both 32 or 64 bits. And the registry key we used, the dump type, has legitimate usages. So these are the suggested actions for the defenders. Try to look for event ID 1,000, which specifies an exception inside Elsas, but it isn't followed by a termination of Elsas. Also like I said, the command line of warfaults can be used to detect this attack, and also API monitoring. We can look for ALPC messages that will be sent to war with the process ID of Elsas, and also depends on the network we can set as Elsas as a PPL. Let's talk also about further research. And the first thing to do is look at other message types. The LPC message has, the function that processes the LPC message has a lot of message types, and other message types might be exploited as well. And also we are using undocumented structs, so that might change in the future, specifically the struct that represents the LPC message. It has a variable that is called message size, and we already saw that in previous versions of Windows, that's variable, the value of this variable differentiates. So it might also be changing the future. So these are the references for this research, and thank you very much.