0x00 Preface

---

BSOD, short for Blue Screen of Death, refers to the system crash screen.

It is typically caused by errors in Ring0-level kernel programs and is frequently encountered in privilege escalation vulnerabilities.

During penetration testing, certain scenarios require system reboots, such as configuring Password Filter DLL, enabling Wdigest authentication, or restarting domain controller servers.

Under specific conditions, triggering a BSOD can be chosen to force a system restart.

So, is there a reliable method to trigger a BSOD? What are further exploitation ideas? How can it be defended against?

0x01 Introduction

---

This article will cover the following topics:

  • Testing several methods to trigger BSOD by terminating the current process
  • Modifying a specified process to cause BSOD upon its termination
  • How to defend against such attacks

0x02 Methods to Trigger BSOD by Terminating the Current Process

---

Found the following reference materials:

https://blog.csdn.net/qq125096885/article/details/52911870

Provides multiple methods to cause a BSOD by terminating the current process

After testing, the methods applicable to the Win7 system are as follows:

  • CallRtlSetProcessIsCritical
  • CallNtSetInformationThread
  • CallNtRaiseHardError

1. CallRtlSetProcessIsCritical

Key code:

RtlSetProcessIsCritical(TRUE, NULL, FALSE);

Reference materials:

https://www.codeproject.com/Articles/43405/Protecting-Your-Process-with-RtlSetProcessIsCriti

Function prototype:

NTSTATUS
RtlSetProcessIsCritical (
BOOLEAN bNew, // new setting for process
BOOLEAN *pbOld, // pointer which receives old setting (can be null)
BOOLEAN bNeedScb); // need system critical breaks

The first parameter, when set to TRUE, marks the current process as a critical process; when set to FALSE, the current process is not a critical process

critical process:

Specific to system processes, known system processes that are critical include:

  • csrss.exe
  • lsass.exe
  • services.exe
  • smss.exe
  • svchost.exe
  • wininit.exe

When a critical process exits, it causes a system BSOD, so if we also set the current process as a critical process, it will similarly cause a BSOD upon process exit

As shown in the figure below

Alt text

2. NtSetInformationProcess

Key code:

ULONG A = 1;
NtSetInformationProcess(GetCurrentProcess(), ProcessBreakOnTermination, &A, sizeof(ULONG));

References:

http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FProcess%2FNtSetInformationProcess.html

Function prototype:

NtSetInformationProcess(

IN HANDLE ProcessHandle,
IN PROCESS_INFORMATION_CLASS ProcessInformationClass,
IN PVOID ProcessInformation,
IN ULONG ProcessInformationLength );

The first parameter represents the process handle

The second parameter ProcessInformationClass, I found a reference in the description of NtQueryInformationProcess, the address is as follows:

https://docs.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntqueryinformationprocess

ProcessBreakOnTermination: 29, Retrieves a ULONG value indicating whether the process is considered critical.

Therefore, set ProcessInformationClass to 29

The third parameter, ProcessInformation, when set to TRUE, marks the current process as a critical process; when set to FALSE, the current process is not a critical process

The fourth parameter is the length, i.e., sizeof(ULONG)

3. CallNtRaiseHardError

Key code:

typedef enum _HARDERROR_RESPONSE_OPTION {
OptionAbortRetryIgnore,
OptionOk,
OptionOkCancel,
OptionRetryCancel,
OptionYesNo,
OptionYesNoCancel,
OptionShutdownSystem
} HARDERROR_RESPONSE_OPTION, *PHARDERROR_RESPONSE_OPTION;

typedef enum _HARDERROR_RESPONSE {
ResponseReturnToCaller,
ResponseNotHandled,
ResponseAbort,
ResponseCancel,
ResponseIgnore,
ResponseNo,
ResponseOk,
ResponseRetry,
ResponseYes
} HARDERROR_RESPONSE, *PHARDERROR_RESPONSE;

HARDERROR_RESPONSE OR;
HARDERROR_RESPONSE_OPTION OP;
OR = ResponseYes;
OP = OptionShutdownSystem;
NtRaiseHardError(0xC0000217, 0, 0, 0, OptionShutdownSystem, &OR);

Reference:

http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FError%2FNtRaiseHardError.html

Function prototype:

NtRaiseHardError(

IN NTSTATUS ErrorStatus,
IN ULONG NumberOfParameters,
IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL,
IN PVOID *Parameters,
IN HARDERROR_RESPONSE_OPTION ResponseOption,
OUT PHARDERROR_RESPONSE Response );

This function is used to generate an application error dialog when handling exceptions. The typical usage is to pop up a dialog asking the user whether to terminate the process. However, if we set the parameters to 0xC0000217, OptionShutdownSystem, and ResponseYes, it will cause a BSOD with error code 0xC0000217.

As shown in the figure below

Alt text

Note:

ErrorStatus can also be other values. Refer to the NTSTATUS description at the following address:

https://msdn.microsoft.com/en-us/library/cc704588.aspx

Simply choose values representing failure functions, such as 0xC000000C(STATUS_TIMER_NOT_CANCELED), 0xC0000216(STATUS_NOT_SERVER_SESSION), 0xC0000219(STATUS_DEBUG_ATTACH_FAILED)

0x03 Method to cause BSOD by terminating a specified process

---

Among the three functions above, only NtSetInformationProcess supports passing a process handle

Next, as long as we can obtain the handle of the specified process and pass it to NtSetInformationProcess, we can achieve terminating the specified process to cause BSOD

The approach is as follows:

  • Elevate to Debug privilege
  • Open the specified process via OpenProcess to obtain the process handle
  • Call CallNtSetInformationProcess to set the specified process as a critical process

Refer to the following link for the complete code:

An open-source project

The code also supports reverting a specified process from critical process to normal process

0x04 Defense Strategy

---

To avoid this situation, when terminating a process, we first need to check whether the process is a critical process. If it is a critical process, it must be set to a normal process before termination.

This involves checking whether the process is a critical process.

The kernel API NtQueryInformationProcess must be used to query ProcessBreakOnTermination and obtain process information.

The key code is as follows:

status = NtQueryInformationProcess(hProcess, ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL);
if(status<0)
printf("[!]NtQueryInformationProcess error\n");
if(breakOnTermination ==1)
printf("[+]The process is critical");
else
printf("[!]The process is not critical");

For the complete code, please refer to the following link:

An open-source project

The code implements querying whether a specified process is a critical process

In practical applications, it typically queries all processes in the current system to check for the existence of critical processes

In code implementation, one can enumerate all process PIDs via EnumProcesses and then perform further queries

Complete code can be referenced at the following link:

An open-source project

The code implements querying all processes in the current system, filtering out system processes, and marking critical processes

0x05 Summary

---

This article tested three methods to cause a BSOD by terminating the current process, further introduced methods to cause a BSOD by terminating specified processes, combined exploitation ideas, analyzed defense methods, and developed a program that queries all processes in the current system and marks critical processes, allowing them to be set as normal processes before termination to avoid system BSOD