结束进程导致 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
如下图
2、NtSetInformationProcess
关键代码:
ULONG A = 1;
NtSetInformationProcess(GetCurrentProcess(), ProcessBreakOnTermination, &A, sizeof(ULONG));
函数原型:
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);
函数原型:
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
如下图
注:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论