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

发布于 2024-11-12 17:26:43 字数 7357 浏览 2 评论 0

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

情愿

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

我们的影子

文章 0 评论 0

素年丶

文章 0 评论 0

南笙

文章 0 评论 0

18215568913

文章 0 评论 0

qq_xk7Ean

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文