Tutorial Windows processes which are significantly important

W

Wave

Guest
#1
Hello everyone.

In this thread I will be discussing about some of the important Windows processes which come shipped with Windows (since at least Vista and on-wards). I will not be going through all of them of course, there are many important Windows processes which will not be discussed in this thread (such as smss.exe, svchost.exe), but some of them will be discussed.

Throughout this thread I do put in some code examples for some specific things and shift focus on discussion about security software development - hopefully this won't be a problem. Please do not attempt to use the code examples unless you know what you're doing to avoid any sort of problems - all code is clean though and not "harmful"/"dangerous", even if you did compile and run it.

Part 1 – lsass.exe
Lsass.exe is the Local Security Authority Subsystem Service and it serves many purposes; it is a very important process within Windows and the OS wouldn’t be able to function properly without it.

One of the most common jobs that lsass.exe is responsible for would be creating access tokens for executing processes on the systems – depending on the access token will depend on what the program can and cannot do. These access tokens are all related to the token privileges; programs can give themselves additional token privileges through a call to the native API function RtlAdjustPrivilege (exported by ntdll.dll), or alternatively they can use the standard Win32 API function AdjustTokenPrivileges (exported by advapi32.dll) – at the end of this part you will be able to find some example source code on using either of these functions from C++.

The Local Security Authority Subsystem Service is responsible for much more than access tokens. It is also responsible for: password changes for the user accounts; verifying the log-on to the user account; creating security logs (linked to the system audit policy – viewable under Event Viewer).

The Local Security Authority Subsystem Service process (lsass.exe) can actually be theoretically easily exploited since it is not a protected process – this means that any program with at least debugging rights can open a handle to the process, which opens up the opportunity to inject code into the process remotely and force-execute its functions to cause undesirable changes to the system (e.g. force-create an access token).

I will now show you an example of using either ntdll.dll!RtlAdjustPrivilege or advapi32.dll!AdjustTokenPrivileges to enable debugging rights. The following source code is written in C++:

Code:
#include <Windows.h>
#include <winternl.h>
#include <iostream>
using namespace std;

typedef NTSTATUS(NTAPI *pdef_RtlAdjustPrivilege)(ULONG Privilege, BOOLEAN bEnable, BOOLEAN bCurrentThread, PBOOLEAN pbEnabled);

bool enable_priv(int priv_method)
{
       BOOL bResult = FALSE;
       if (priv_method == 1) // use NTAPI
       {
              BOOLEAN bRes;
              LPVOID RtlAdjustPrivilege_addr = GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlAdjustPrivilege");
              if (!RtlAdjustPrivilege_addr)
              {
                     cout << "Unable to obtain the address of ntdll!RtlAdjustPrivilege!\n";
              }
              pdef_RtlAdjustPrivilege RtlHandle = (pdef_RtlAdjustPrivilege)RtlAdjustPrivilege_addr;
              if (NT_SUCCESS(RtlHandle(20, TRUE, FALSE, &bRes)))
              {
                     cout << "Successfully enabled Debugging Rights (SeDebugPrivilege) via ntdll!RtlAdjustPrivilege!\n";
                     bResult = TRUE;
              }
              else
              {
                     cout << "Failed to enable Debugging Rights (SeDebugPrivilege) via ntdll!RtlAdjustPrivilege: " << GetLastError() << endl;

                     bResult = FALSE;
              }
       }
       else if (priv_method == 2) // use Win32 API
       {
              HANDLE TokenHandle = { 0 };
              TOKEN_PRIVILEGES TokenPriv = { 0 };
              LUID lValueId = { 0 };
              if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
              {
                     cout << "Failed to open the process token: " << GetLastError() << endl;
                     bResult = FALSE;
              }
              if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &lValueId))
              {
                     cout << "Failed to lookup the privilege value: " << GetLastError() << endl;
                     bResult = FALSE;
              }
              TokenPriv.PrivilegeCount = 1;
              TokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
              TokenPriv.Privileges[0].Luid = lValueId;
              if (AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPriv, sizeof(TokenPriv), NULL, NULL))
              {
                     cout << "Successfully adjusted the token privileges via AdjustTokenPrivileges!\n";
                     bResult = TRUE
              }
              else
              {
                     cout << "Failed to adjust the token privileges: " << GetLastError() << endl;
                     bResult = FALSE;
              }
       }
       return bResult;
}

int main()
{
       BOOL bEnable = enable_priv(1);
       getchar();
       return 0;
}
I will note that the first method used in the enable_priv function (RtlAdjustPrivilege) will only work if the program has been run with administrative rights, whereas the second method (via AdjustTokenPrivilege) will work without running the program with administrative rights.

Part 2 – csrss.exe
Csrss.exe is the Client Service Runtime Subsystem Service, and its commonly known for being responsible for providing important functions to provide functionality to the Windows OS, and managing threading/console windows. As well as this, csrss.exe is marked as a critical process, therefore termination of this process will result in a BSOD crash with the error message CRITICAL_PROCESS_DIED.

Csrss.exe can have a good use when it comes to detecting hidden malicious processes being protected by rootkits, and also for process monitoring purposes (and this can be tweaked for another rootkit-protected process detection method also).

Process monitoring method via csrss.exe utilisation:
There are some interesting functions which are exported by a Windows Dynamic Link Library (*.DLL) called csrsrv.dll; csrss.exe imports this module and utilises some functions exported by this library. The two interesting functions which become exported by this library would be: CsrCreateProcess and CsrTerminateProcess.

If you are able to obtain a handle to csrss.exe and then utilise this handle to inject code into it (e.g. you can perform stealth code injection or you can work with standard DLL injection techniques to get your code running within the address space of csrss.exe on its own thread) then you can place a hook on those two interesting functions (CsrTerminateProcess and CsrTerminateProcess) which will allow you to log when a new process is created or when a process becomes terminated; through these hooks you will be able to essentially monitor all user-mode process execution attempts (at the least), and when a new process is created and your CsrTerminateProcess hook callback function becomes invoked, you will be greeted with access to a working and usable HANDLE to the newly starting up process, which you can use for whatever you want (terminate the process if you do not want to allow the execution, inject into it to control it, etc).

In a way, hooking CsrCreateProcess and CsrTerminateProcess would create similar functionality in user-mode of using the kernel-mode callback PsSetCreateProcessNotifyRoutine/Ex. The good thing about this method is that you will only need to inject into csrss.exe and hook CsrCreateProcess/CsrTerminateProcess once, you won’t need to inject into any other programs except csrss.exe for it to work.

However, this option may be good mainly for Windows Vista and Windows 7 only, and not for Windows 8/8.1 or Windows 10 – on Windows Vista and Windows 7, csrss.exe is not a protected process, and therefore you can obtain a handle to the SYSTEM process as long as you have enabled debugging rights, however on newer OS editions of Windows, csrss.exe will be a protected process and you will be unable to obtain a handle to it from user-mode. Of course, if you are developing software for Windows Vista and Windows 7 and you do not have experience with device driver development to use kernel-mode callbacks then this can be a good alternate from user-mode, however of course using a kernel-mode callback for process monitoring would be much more secure.

In terms of anti-rootkit development, this process monitoring method could be utilised; you could log all the process start-up notifications passing through the callback being invoked from the CsrCreateProcess hook (and obviously remove processes which were recorded after they become terminated via the callback invoke from the CsrTerminateProcess hook), and then you can regularly scan through the running processes from a normal program running as admin (not csrss.exe – you could work with IPC between csrss.exe from your injected code and another process running on the system which you own), and then you can compare if you logged any process creations which have not yet been terminated but cannot be found by the other process – this would signify a process is being hidden by a rootkit, most likely more useful for user-mode processes, since not all user-mode rootkits will intercept for csrss.exe also, but probably for normal typical applications such as Task Manager).

That being said, csrss.exe can be used for detection of hidden processes by enumerating all the running handles from code executing within csrss.exe itself. There are tools which have utilised csrss.exe for enumerating through handles to detect hidden rootkit processes before, such as CsrWalker (which can still detect some rootkit-protected processes).


Part 3 - winlogon.exe
Winlogon.exe is a critical Windows process and it is mainly responsible for logging in/out of the user accounts and the lock screen (working with the SAK, which stands for Secure Attention Key). Since winlogon.exe is a critical process, should the process be terminated, it will result in a system-wide crash (BSOD – the error message will be CRITICAL_PROCESS_DIED). That being said, winlogon.exe itself does not contain the user login credential information in its memory – this is sorted out by other external components within the OS.

Of course winlogon.exe can be a victim of malicious attacks, however based on my experience in malware analysis I tend to find explorer.exe and csrss.exe attacked more commonly than winlogon.exe.

Part 4 – explorer.exe
Explorer.exe is a very important process and heavily evolves around GUI aspects of the Windows OS – it is essentially the shell which provides the start menu, desktop items, taskbar, tray menu, and all the other GUI components shown in Windows by default like this. That being said, it is also responsible as being the primary main file manager software embedded within the OS; without explorer.exe there would be no GUI file explorer by default in Windows.

You may not expect it, however explorer.exe is not actually a critical process, regardless of its importance and binding to the Windows OS – you can freely terminate/restart it at any time without the system crashing, however without explorer.exe running you may not be able to use your system properly since you’ll lose the main GUI components such as the task bar and the such – although currently active running programs will still be operational as long as you don’t minimise them/lose their focus.

Explorer.exe is one of the most commonly attacked Windows processes when it comes to malicious software and while it less common these days, it used to be extremely common to regularly find malicious software attempting to pretend to be a genuine version of explorer.exe, as a method of tricking the user into believing the process was safe. Without that being said, the same applies to many other Windows processes of course, such as: csrss.exe, winlogon.exe, svchost.exe, smss.exe, etc.

Since explorer.exe runs under the standard user account and is a non-administrative process (not elevated), any standard running program can freely open up a handle to it and inject code into it. An example of opening a handle to the process from a standard-running program would be the following sample (C++):

Code:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
using namespace std;

DWORD retProcessId(std::string targetProcessName)
{
       HANDLE hProcess;
       PROCESSENTRY32 processEntry32;
       processEntry32.dwSize = sizeof(PROCESSENTRY32);
       hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
       do {
              if (!strcmp(processEntry32.szExeFile, targetProcessName.c_str()))
              {
                     CloseHandle(hProcess);
                     return processEntry32.th32ProcessID;
              }
       } while (Process32Next(hProcess, &processEntry32));
       CloseHandle(hProcess);
       return 0;
}

int main()
{
HANDLE ProcessHandle = OpenProcess(PROCESS_VM_OPERATION, FALSE, retProcessId("explorer.exe"));
       getchar();
       return 0;
}
In theory the code should be successful since the process is not elevated therefore you do not need to be elevated to obtain a handle to it, either. Once you have obtained a handle to the process, you can inject code into it, regardless of your process being elevated or not – another reason why it is important for security software to monitor unknown programs and prevent them from opening handles to sensitive processes which should be protected but are not protected by Windows by default, such as explorer.exe.
-------------------------------------------------

Hopefully this thread will be found useful by someone out there!

Stay safe,
Wave. ;)
 
Last edited by a moderator:

AtlBo

Level 24
Joined
Dec 29, 2014
Messages
1,390
Antivirus
Qihoo 360
#8
Lsass.exe is the Local Security Authority Subsystem Service and it serves many purposes; it is a very important process within Windows and the OS wouldn’t be able to function properly without it.
Wave was prophetic with this part. LSASS.exe played a big part in the spread of wannacry. There is so much to know about Windows, and Wave's posts are a good way to get inside the deeper things a little bit. Thanks :)
 

Visa

Level 1
Joined
May 31, 2017
Messages
42
OS
Windows 10
Antivirus
Microsoft
#9
Wave was prophetic with this part. LSASS.exe played a big part in the spread of wannacry. There is so much to know about Windows, and Wave's posts are a good way to get inside the deeper things a little bit. Thanks :)
Ty! :)

As an addition to the info posted about lsass.exe, if you can gain code execution within that Windows process you can actually use it as an advantage to bypass AV self-defense mechanisms, or alternatively bypass anti-cheat mechanisms. In theory at least.

There is something called "handle hijacking", similar to the situation with csrss.exe (which no longer works so well since csrss.exe is now a protected process therefore you cannot open a handle to it even with debugging rights from user-mode). If you can inject code into lsass.exe you can use handle hijacking to get access to an open handle for an AV process, or any protected process, and as long as it has sufficient rights to do what you need to do then you can use that hijacked handle to terminate/inject/suspend.

Bear in mind that you would still need administrator rights and SeDebugPrivilege (aka. debugging rights) since lsass.exe is running under the SYSTEM account. Some AVs might even try to lower the access rights which can be obtained through handle hijacking within lsass.exe so it cannot be used to do much damage although I am not entirely sure.

It can be quite a complex topic... I am not an expert on handle hijacking tbh. I didn't even know you could do that with lsass.exe when I made this thread haha

---
You might even be able to abuse code execution within lsass.exe to spawn other processes under SYSTEM, potentially. I haven't tested this idea but I will do soon for sure... My idea is that you would allocate some memory within lsass.exe (e.g. NtAllocateVirtualMemory) and then write to that allocated memory to store a loader function (e.g. NtWriteVirtualMemory), and then create a remote thread for lsass.exe to start via NtCreateThreadEx - make the newly created remote thread be responsible for executing the loader code you had put inside the process! Then the loader code steal the access tokens from lsass.exe (token for SYSTEM) or steal it from another windows process running under SYSTEM like winlogon.exe, and then create a new process which has the same tokens which you stole. If it works right, then the new process will also be under SYSTEM due to having the stolen SYSTEM token. It definitely used to work on older versions of Windows like Windows 2000/XP without needing to inject into windows process, and it still works on newer versions as Windows as long as you do it within a genuine service (as opposed to a process), but I've never tested it while executing from a genuine process under SYSTEM (since lsass.exe is a genuine process which is just running under the NT Authority account, it would've been started by an existent service to be running under SYSTEM instead of just spawning under it for sure, or I think at least). I'll probably go through ReactOS a bit to learn a bit on the spawning start-up of lsass.exe on older OS like Vista and 7 soon and see if that provides any more insight for me to report back on, but this is just a theory idea for me to test soon. :)

But I recon MS probably patched that old method even for if you are executing the code within lsass.exe. But I will test it for sure soon :)
 
Joined
Jun 23, 2017
Messages
10
OS
Arch Linux
Antivirus
Tencent
#10
Very good write up, hope to see more high quality content like this coming from you.
In case anyone noticed "(CsrTerminateProcess and CsrTerminateProcess)" it was meant to be CsrTerminateProcess and CsrCreateProcess
 

Visa

Level 1
Joined
May 31, 2017
Messages
42
OS
Windows 10
Antivirus
Microsoft
#11
Very good write up, hope to see more high quality content like this coming from you.
In case anyone noticed "(CsrTerminateProcess and CsrTerminateProcess)" it was meant to be CsrTerminateProcess and CsrCreateProcess
Thank you foe your words, and yes you are totally right, it was supposed to be that! :)
 
D

Deleted member 65228

Guest
#13
why `lsass.exe` is not protected process?
I am not sure why, I was thinking this too when I read this thread today. I know you can enable it as a protected process on modern versions of Windows... Maybe it isn't protected by default because it is harder to abuse by default (for example it is under SYSTEM therefore without a zero-day RCE exploit you cannot inject code into it unless you're elevated and have debugging rights anyway). And malware with admin rights doesn't need to care for lsass.exe, it can do other things. That could be the reason why...

Csrss.exe is a protected process now though and same circumstance as the above, interesting.

You can reverse csrss.exe, lsass.exe and their exclusive modules in IDA to learn more about it. You can get the debugging symbols (IDA should do it automatically by connecting and retrieving for you) so you'll be able to see the function names properly and the such. :)
 
Joined
Dec 23, 2014
Messages
1,583
OS
Windows 10
Antivirus
Microsoft
#14
why `lsass.exe` is not protected process?
This additional LSA protection can break LSA plug-ins and drivers. I read somewhere, that even after checking this feature in Audit mode, some drivers could (rarely) crash the system.
.
From technet.microsoft.com paper - Recommended practices.
.
Use the following list to thoroughly test that LSA protection is enabled before you broadly deploy the feature:
  • Identify all of the LSA plug-ins and drivers that are in use within your organization. This includes non-Microsoft drivers or plug-ins such as smart card drivers and cryptographic plug-ins, and any internally developed software that is used to enforce password filters or password change notifications.
  • Ensure that all of the LSA plug-ins are digitally signed with a Microsoft certificate so that the plug-in will not fail to load.
  • Ensure that all of the correctly signed plug-ins can successfully load into LSA and that they perform as expected.
  • Use the audit logs to identify LSA plug-ins and drivers that fail to run as a protected process.
Configuring Additional LSA Protection
 
D

Deleted member 65228

Guest
#15
Makes sense IMO. They made csrss.exe a protected process but I am pretty sure when they did this, they adapted lsass.exe to be more responsible with some things probably. I am not sure about older versions of Windows, but lsass.exe now has open handles to running processes just like csrss.exe originally did with sufficient access rights for virtual memory operations.



That can be exploited if you can inject into lsass.exe (under circumstances I mentioned earlier you can do it freely) for shell-code injection, no thread creation needed (the handles don't have PROCESS_CREATE_THREAD rights anyway).

1. NtAllocateVirtualMemory - allocate memory for shell-code.
2. NtWriteVirtualMemory - write to the allocated memory to store the shell-code.

The injected shell-code would need to:
1. Execute whatever you needed to execute (instructions).
2. Return with a trampoline.

"Trampoline"? Remotely hook an API. You can find the address of a target API which would be called frequently by lsass.exe -> remotely hook it by pointing execution flow to the address of your shell-code (JMP shellcode_address) -> return for the original call afterwards. The shell-code would handle the memory allocation and byte copy for the trampoline.

Targeting NtOpenProcess (NTDLL) would be sufficient because lsass.exe will call it anyway to open handles to processes. It has an open handle to my IDA process and a VMWare process right now (which are active processes of course).

No Data Execution Prevention (DEP) exploitation required because you are doing it all remotely, Windows will handle the memory allocation for you with the PAGE_EXECUTE_READWRITE (specify in NtAllocateVirtualMemory).

I think this would work. This is just estimation but I think it is interesting and don't see why there'd be an issue with it IMHO.
 

Similar Threads

Similar Threads