In this post, I’m going to explain the process that led me to cause a crash in explorer.exe and disable Windows Defender.

Well, it turns out that I was reading about the types of access that can be requested when trying to open a handle to a process with the OpenProcess function from the Windows API. For those who don’t know, in Windows a handle is an identifier necessary to access an object.

Now, what is an object? Just as it’s said that in Linux everything is a file, in Windows, everything is an object. For example, a process in Windows is represented with the EPROCESS object. This would be the definition of an object in Windows, more information on what was mentioned at:

In summary, you cannot access an object directly without a handle. This is how a handle (identifier) is represented in the book Windows System Programming Part 1 by Pavel Yosifovich:

Handle representation in Windows

There are many ways to view the handles that a process has open, one would be with Process Explorer or Handle (tools from the Sysinternals suite), with WinDbg, etc.

Getting back to the topic, while reading about protected processes, I read this:

Access rights denied from normal processes to protected processes

Official documentation on process security and access rights

Of all the access rights that are denied from normal processes to protected processes, I saw that there were several that are not allowed. So, knowing all the types of access rights that exist, by simple omission the following should be allowed:

Both SYNCHRONIZE and PROCESS_QUERY_LIMITED_INFORMATION weren’t going to get us very far, so I focused on PROCESS_SUSPEND_RESUME.

This thing about protected processes essentially prevents you from touching what you shouldn’t even when running as administrator. Many system processes and almost all antiviruses and EDRs have their processes and services as protected, and Defender is no exception.

These are all the protected processes on a Windows virtual machine as seen from WinDbg with local kernel debugging:

Protected processes in Windows from WinDbg

And here we see how the Defender service and process are indeed protected objects:

Windows Defender service as a protected process

In the case of Windows Defender, the process is called MsMpEng.exe and the service that runs this process is windefend

Windows Defender protected process

So I started researching how to suspend a process programmatically and it turned out that it could be done with NtSuspendProcess. Since this function is not present in the Windows API, knowing that it starts with Nt we know it must be in ntdll.dll (this DLL has the Native API and is what all Windows processes use to communicate with the kernel).

Knowing this, we proceed to find out how to call this function, its arguments, etc. Using the link from the previous paragraph as a reference, we define the NtSuspendProcessFn function, requiring a handle to a process as an argument:

NtSuspendProcessFn function definition

NtSuspendProcess in NTDLL is just a wrapper for the real function, which is in the kernel (ntoskrnl.exe), which looks like this when opened in IDA:

NtSuspendProcess function in IDA

Functions in Windows normally end up needing DLLs like kernel32.dll or advapi32.dll, which in turn use the Native API functions (in ntdll), and finally from those functions the syscalls are made that allow code execution in kernel mode:

Flow of calls from user mode to kernel mode

Note: this drawing is a simplification of the process, I leave a link in the references to a post that details the entire process.

Continuing with the topic, the function to suspend processes ended up like this:

Implementation of the function to suspend processes

Essentially, what is done is opening a handle to the ntdll.dll module that this process will have in memory when executed (all processes have it, as I mentioned before) and with GetProcAddress the memory address of the NtSuspendProcess function will be searched for in the EAT (Export Address Table) of ntdll.dll.

You’ll also need to include these headers:

Headers needed for the code

Differences between headers and libraries

And use this function to find the PID of the process whose name we give as an argument to the function. The function creates a snapshot of all processes using CreateToolhelp32Snapshot and iterates over the structure that this function returns, comparing the szExeFile field of each entry corresponding to each process with the process name we’ve passed. And finally, if the executable name from the snapshot matches the one we want, the PID of the process we’re interested in is returned:

Function to find PID by process name

When trying to do a test, I got access denied (error 5):

Access denied error

So I added a function to enable the SeDebugPrivilege privilege in the process’s access token (yes, that privilege must already be there, meaning this only works if we launch our PoC with administrator permissions).

For those who don’t know what an access token is, it’s a structure that contains information about the privileges that a process or thread has and is used to access a series of resources. To put it more simply, we can see the privileges that are included in the access token of cmd.exe when we run whoami /priv (since the whoami.exe process is created with the same privileges as cmd.exe). The SeDebugPrivilege in particular is used by both debuggers and even offensive tools such as mimikatz when we run the famous privilege::debug.

The complete function to enable this privilege is a bit long, so let’s skip it to go directly to the main, which looks like this:

Main function of the program

So, to recap, what we’re going to do is:

  1. Identify the PID of the Defender process
  2. Open a handle to our process’s access token
  3. Enable the SeDebugPrivilege privilege
  4. Open a handle to the Defender process with PROCESS_SUSPEND_RESUME access
  5. Call NtSuspendProcess to see what happens

And once launched, the Defender process becomes suspended and to further surprise, it turns out that the graphical environment hangs (explorer.exe), the only window that works is the cmd itself. I wanted to verify that it was really suspended, but since I didn’t have graphical tools, I used a tool called DTrace. It’s an open-source tool that has a version for Windows and has this architecture:

DTrace architecture in Windows

Writing scripts in D, you can do things like what we’re interested in now, logging the syscalls made by the process, and curiously after a while without making syscalls (which is to be expected in a suspended process), suddenly MsMpEng.exe started making syscalls, it’s not clear why, although it could be that this is due to some driver doing something with the Defender process that we don’t see.

This is the D script I used to log the syscalls of that process:

D script to log syscalls

This is what it looks like before suspending the process:

Process syscalls before suspending

And this is what it looks like a while later (at first it doesn’t make any syscalls):

Process syscalls after suspending

After rebooting the machine, in Eventviewer while reviewing recent events we see that a 1002 event (application hang) occurred in explorer.exe:

Event 1002 in Eventviewer showing explorer.exe crash

Initially I thought there might be some handle open from MsMpEng to explorer, however, when looking at the handles of MsMpEng I didn’t see any handles to explorer.exe

Note: This PID (5004) is on my host machine, on the virtual machine it’s 3068, or bfc in hexadecimal

MsMpEng process handles

There were only handles to itself, so it may not be because of that. I spent some time trying to figure out the reason for the explorer crash, although I didn’t get anything clear. So for the moment I’ll leave it here in case someone wants to dig deeper.

And in conclusion, this is how we break Defender :D (but yes, with admin privs).

Note: when I have some time, I’ll publish the tool so you can mess around with it.

References