Welcome to track 3 and our 3 o'clock is a new speaker. So first time speaking. What does that mean? So let's start off with saying L'chaim to Ron and L'chaim. Hello everyone. Today I will talk with you about a new method to dump the memory of Elsas. Which is called Elsas Stinkering. In case you don't know, stinker is the Hebrew word for snitch. And this is the reason behind the name of this method. Sorry. We are going to snitch on Elsas. And we all know the phrase, 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 Yitzchak. I'm a security researcher at Deep Instinct. And a fun fact about me, last night I lost $300 at the casino. So this is the agenda for this talk. I'll start with an overview. First of all, I'll talk about credential dumping 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 ELSAS 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 into other systems. It doesn't require exploiting vulnerabilities. And the holy grail for attackers is the domain controller. Credentials can be used for any type of attack. 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 Conti, Black Cat, Lockbit, and many more. But how does a credential dumping attack go? So once a user has logged into the system, their credentials are stored in the memory of ELSAS. This memory can be read and written to the network, then passed by tools like Mimikatz, the credentials are extracted and used for lateral movement. So a little bit about ELSAS. The local security authority subsystem service. It is a system process that is responsible for authenticating users and verifying logons. And the problem with it 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 the service and up to disk by other process. With APIs like mini damp write dump. Another thing we should focus on 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 every 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 is that this от thehovesta app, we should be was to find a new way to perform a credential dumping attack. We wanted to force the service to dump the memory of ELSAS 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 ProcDump, which is part of Sysinternals. It can dump the memory of ELSAS with the following command line. Here is the example for that. Another way to do that is by using the DLL. It has an exported function which is called mini dump. You can supply the process ID of ELSAS to this function and it will do the work for us. Here is an example for that as well. Another easy way is to just use the task manager. We can right click on the process and select create dump file. Now another method we should talk about. It is silent process exit, which was also discovered by us. 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 exit. You can also use the DLL. This is the research I mentioned earlier. Behind the scenes it communicates with the Windows reporting service. And also for the rest of this talk I will refer to the service as the well 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 completely bypassed it. Okay. But there are protections against dumping the memory of Alsace, such as protected process lights 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. Alsace can be set as a PPL with a single register value and that will prevent other processes from gaining a handle with the permissions. And also, the PPL is 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 Alsace. That means that benign authentication packages and plug-ins 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 Alsace tinkering. Like I said, it is a new method to dump the memory of Alsace 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 the service that will make it think that an exception occurred inside Alsace. Then it will produce a memory dump for us without terminating it. This will bypass security products that allow processes like to dump the memory of Alsace. 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. 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 address zero. Where fault spawns the child process and produces a memory dump. But what happens behind the scenes? Every process has exception handlers. And the last one is called C specific handler. It is implemented inside NTDLL. LL and it is responsible for two things. The first one is reporting the exception details to the world service. It does that by calling NTLPC send wait receive ports. And the second thing is terminating the process. So that raises the question, can we report an exception on our own process? And turns out the service won't terminate our process. The responsibility for terminating a 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 world.txt is a function that is used to send a message to the client. It is a function that 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 rights. This mapping is then opened into a view. The step after that is duplicating the pseudo handles for the process and the thread. Then all those values are sent to the client. And then the client is sent to the server. The values are then written into the file mapping as an undocumented structs. Those values are also sent to the function report exception internal, which stores them in another undocumented struct and send it to the function send message to words service. But before we send the message, let's understand how the communication between the client and the server works. So the communication is done with the advanced local procedure call or the final procedure call. So the 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 returns a port. The second function is called LPC send way to receive ports and it uses the port to send a message to the service and receive a message back. The next function we're going to talk about is send message to the service. 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 WNF where service starts. Then we signal the service, it starts initializing and once the event system error port 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. Finally, we can send a message. So, let's try to do that. We're reporting an exception on our own process. The POC tool is launched. 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 case. When the service receives a request, it duplicates the file mapping handle to access the undocumented stock that was written into it. And also, two instances of where fault 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 where fault is spawned under the process that sent the request by calling create process user. And this will be the process that eventually calls mini dump and report the exception details to the event log. So, now we know how to report an exception. So, let's try to report on ELSAS. 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 server side of well. 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 work service is implemented inside where SVC.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 start LPC server. And we can see this function uses a string. You already saw. Windows error reporting service ports. This string will be part of a struct called object attributes and this struct will be sent to LPC create ports. And also the next step in the initialization is creating a thread for the function static LPC server 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 the code for this value. We placed a break point on each reference and executed the service. The break point that hits is inside the function check if system connecting to ports. So, what is this function? The first thing it does is calling a person it logged on user. The thread that enters our request is executed under the same user as the service, which is anti-authority system. But after the impersonation, the user will not be able to access the information. 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 permissions 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 LPC server. So, 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 a 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. Private 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 object. So, this is a denial of service attack where one program interferes with the legitimate one. And here is an example for that. Let's say we have a malware and an EDR agent executing on the same system. The malware executes first as a low privilege process and then the EDR 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 EDR 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 kernel objects. Kernel 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 EDR 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 EDR agent starts. It starts as a privilege 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. So, let's look at the function create private namespace. It creates a boundary descriptor which is called where we see namespace boundary. Then it adds the security ID that represents the service to that boundary descriptor and creates the namespace where we see. That means that events that are created under this namespace were 100% created by where we see. 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 ID of the process that sends the request to the ID of the process that is being reported on. It is a process that is being effectively sent away or it's being 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 the client's 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 ports basically checks if system is connected to port. Check 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. Then, after the impersonation, the thread stayed as anti-authority system, and the event is is opened. So to recap, this is the attack. We execute our tool as system. It creates two undocumented structs. 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 server, starts processing it. It compures 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 code is specified. Well, as a child process, and a memory dump of Alsace.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 current event log. This event is generated under the current crash dumps folder. And the existence of it is suspicious. But it is created by wearful.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 wear report archive. It is a different type of log that specifies the details of the exception. And, again, the most important point is that this 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 wearful.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. The advantage of this attack is that it can be used as a 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 some of the advantages of this attack. Here are the suggested actions for the defenders. Try to look for event ID 1000, which specifies an exception inside Elsas. But it isn't followed by a termination of Elsas. Also, like I said, the command line of wearfuls can be used to detect this attack. And also API monitoring. We can look for LPC messages that will be sent to wear with the process ID of Elsas. And also depends on the network. We can look for the process ID of Elsas. And also depends on the network. We can set 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 stocks. So, that might change in the future. Specifically, the stock 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 variable, the value of this variable differentiates. So, it might also be changed in the future. So, these are the references for this research. And thank you very much. Thank you.