结束进程导致BSOD的利用分析

0x00 前言


BSOD,全称Blue Screen of Death,即蓝屏死机。 通常是Ring0级的内核程序出错导致,在提权漏洞中经常遇到。 而在渗透测试中,某些情况下需要重启系统,例如配置Password Filter DLL,启用Wdigest Auth,重启域控服务器等。

某些条件下,可以选择触发BSOD导致系统重新启动。

那么,是否存在一个稳定的方法触发BSOD呢?更进一步的利用思路呢?如何防御?

0x01 简介


本文将要介绍以下内容:

  • 测试几种结束当前进程导致BSOD的方法
  • 修改指定进程,当进程退出后,导致BSOD
  • 如何防御

0x02 结束当前进程导致BSOD的方法


找到如下参考资料:

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

提供多种结束当前进程导致BSOD的方法

经测试,适用Win7系统的方法有以下三种:

  • CallRtlSetProcessIsCritical
  • CallNtSetInformationThread
  • CallNtRaiseHardError

1、CallRtlSetProcessIsCritical

关键代码:

RtlSetProcessIsCritical(TRUE, NULL, FALSE);

参考资料:

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

函数原型:

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

第一个参数,设置为TRUE时,表示将当前进程标记为critical process;设置为FALSE时,当前进程不是critical process

critical process:

系统进程特有,已知以下系统进程为critical process:

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

当critical process退出时,会导致系统BSOD,所以如果我们将当前进程也设置为critical process,那么在进程退出时同样会导致BSOD

如下图

Alt text

2、NtSetInformationProcess

关键代码:

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

参考资料:

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

函数原型:

NtSetInformationProcess(

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

第一个参数表示进程句柄

第二个参数ProcessInformationClass,我在NtQueryInformationProcess的说明中找到了参考,地址如下:

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.

所以ProcessInformationClass设置为29

第三个参数ProcessInformation,设置为TRUE时,表示将当前进程标记为critical process;设置为FALSE时,当前进程不是critical process

第四个参数为长度,即sizeof(ULONG)

3、CallNtRaiseHardError

关键代码:

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);

参考资料:

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

函数原型:

NtRaiseHardError(

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

这个函数在处理异常时用于产生应用程序错误对话框,通常用法是弹出对话框提示用户是否要终止进程,但我们如果把参数设置为0xC0000217,OptionShutdownSystem和ResponseYes,那么会导致BSOD,提示0xC0000217

如下图

Alt text

注:

ErrorStatus也可以为其他值,可参考NTSTATUS的说明,地址如下:

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

选择代表失败函数的值即可,例如0xC000000C(STATUS_TIMER_NOT_CANCELED)、0xC0000216(STATUS_NOT_SERVER_SESSION)、0xC0000219(STATUS_DEBUG_ATTACH_FAILED)

0x03 结束指定进程导致BSOD的方法


以上三个函数,只有NtSetInformationProcess支持传入进程句柄

接下来,我们只要能够获得指定进程的句柄,传入NtSetInformationProcess即可实现结束指定进程导致BSOD

思路如下:

  • 提升至Debug权限
  • 通过OpenProcess打开指定的进程,获得进程句柄
  • 调用CallNtSetInformationProcess将指定进程设置为critical process

完整代码可参考如下链接:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/SetProcessCritical.cpp

代码还支持将指定进程从critical process设置为正常进程

0x04 防御思路


为了避免这种情况的发生,我们在结束进程时,需要先查看该进程是否为critical process,如果是critical process,需要设置为正常进程后再结束

这里就涉及到查询进程是否为critical process

需要使用内核API NtQueryInformationProcess查询ProcessBreakOnTermination,获得进程信息

关键代码如下:

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");

完整代码可参考如下链接:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/CheckCriticalProess.cpp

代码实现了查询指定进程是否为critical process

在实际应用上,通过会查询当前系统的所有进程是否存在critical process

在代码实现上,可通过EnumProcesses所有进程PID,接着做进一步查询

完整代码可参考如下链接:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/FindCriticalProcess.cpp

代码实现了查询当前系统的所有进程,过滤掉系统进程,标记出critical process

0x05 小结


本文测试了三种结束当前进程导致BSOD的方法,进一步介绍了结束指定进程导致BSOD的方法,结合利用思路,分析防御方法,编写程序实现了查询当前系统所有进程并标记出critical process,在结束critical process前将其设置为正常进程,能够避免系统出现BOSD


LEAVE A REPLY

Written on July 2, 2018