绿盟科技-每周蓝军技术推送(2022.5.14-5.20)学习

0x00 每周蓝军技术推送(2022.5.14-5.20)

  • 这一周的推送,主要学习了三部分内容:
  • 篡改注册表与ETW,隐匿执行计划任务
  • 使用NtCreateUserProcess进行PPID欺骗 和BlockDLL
  • Windows环境下的自保护探究

0x01 PPID Spoofing & BlockDLLs with NtCreateUserProcess

  • 这篇文章中,作者介绍了如何使用NtCreateUserProcess这一个未被官方文档化的API函数,NtCreateUserProcess函数是CreateProcessA(W)的底层实现。可以规避部分EDR的检测。

  • 作者的灵感来源是来自Capt. Meelo的Making NtCreateUserProcess Work一文,NtCreateUserProcess的函数原型如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    NTSTATUS
    NTAPI
    NtCreateUserProcess(
    _Out_ PHANDLE ProcessHandle,
    _Out_ PHANDLE ThreadHandle,
    _In_ ACCESS_MASK ProcessDesiredAccess,
    _In_ ACCESS_MASK ThreadDesiredAccess,
    _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes,
    _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes,
    _In_ ULONG ProcessFlags,
    _In_ ULONG ThreadFlags,
    _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    _Inout_ PPS_CREATE_INFO CreateInfo,
    _In_ PPS_ATTRIBUTE_LIST AttributeList
    );
  • ProcessHandleThreadHandle分别是需要传出的进程和线程句柄,可以为NULL。

  • ProcessDesiredAccessThreadDesiredAccess是进程和线程访问权限掩码。可以直接为PROCESS_ALL_ACCESS和THREAD_ALL_ACCESS,具体可以参见以下文档,

  • ProcessObjectAttributesThreadObjectAttributes是进程和线程对象属性,指向OBJECT_ATTRIBUTES结构,此处可以为NULL

  • ProcessFlagsThreadFlags是进程线程标志,Meelo是查看ProcessHack源码获得的,此处可以为NULL

  • ProcessParameters是进程参数信息,指向的是RTL_USER_PROCESS_PARAMETERS结构,通过逆向CreateProcessA函数,可以发现使用RtlCreateProcessParametersEx进行初始化

    1
    2
    3
    4
    UNICODE_STRING NtImagePath;
    RtlInitUnicodeString(&NtImagePath, (PWSTR)L"\\??\\C:\\Windows\\System32\\mmc.exe");
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
    RtlCreateProcessParametersEx(&ProcessParameters, &NtImagePath, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, RTL_USER_PROCESS_PARAMETERS_NORMALIZED);
  • CreateInfo是一个指向PS_CREATE_INFO结构的指针,对于PS_CREATE_INFO结构的初始化也很简单。

    1
    2
    3
    4
    // process create info
    PS_CREATE_INFO CreateInfo = { 0 };
    CreateInfo.Size = sizeof(CreateInfo);
    CreateInfo.State = PsCreateInitialState;
  • 最后一个参数是AttributeList,AttributeList指向的是PPS_ATTRIBUTE_LIST结构体,这是一个链表结构,可以通过RtlAllocateHeap函数自主申请链表的大小。在第一个节点中,必须要添加PS_ATTRIBUTE_IMAGE_NAME(进程映像名)这个属性。

    1
    2
    3
    4
    5
    typedef struct _PS_ATTRIBUTE_LIST
    {
    SIZE_T TotalLength; // sizeof(PS_ATTRIBUTE_LIST)
    PS_ATTRIBUTE Attributes[2]; // Depends on how many attribute entries should be supplied to NtCreateUserProcess
    } PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST;
1
2
3
4
5
6
7
// initialise attribute list
PPS_ATTRIBUTE_LIST AttributeList = (PS_ATTRIBUTE_LIST*)RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PS_ATTRIBUTE) * 3);
AttributeList->TotalLength = sizeof(PS_ATTRIBUTE_LIST);
// set image name
AttributeList->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
AttributeList->Attributes[0].Size = NtImagePath.Length;
AttributeList->Attributes[0].Value = (ULONG_PTR)NtImagePath.Buffer;
  • 作者在这篇文章中主要实现了两个功能,一个是PPID Spoofing,也就是父进程欺骗,另外一个是BlockDLLs,BlockDLLs简单的来说就是阻止一些非可信的DLL模块加载到进程中。

  • 进程隐藏可以通过设置进程的Attribute即可,具体操作如下,将进程的PS_ATTRIBUTE_PARENT_PROCESS(父进程)属性设置为指定的父进程的Handle即可。:

    1
    2
    3
    4
    // add parent process attribute
    AttributeList->Attributes[1].Attribute = PS_ATTRIBUTE_PARENT_PROCESS;
    AttributeList->Attributes[1].Size = sizeof(HANDLE);
    AttributeList->Attributes[1].ValuePtr = hParent;
  • BlockDLLs允许系统根据不同的策略加载不同安全等级的Dll文件,因为一些安全软件会通过往进程中加载dll来进行行为监控,利用这个特性就可以阻止非windows的dll加载,包括安全软件的dll。这里可以看到完整的BlockDlls的介绍,主要有两种方法。

    • 通过SetProcessMitigationPolicy函数设置阻止策略。

      1
      2
      3
      PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY policy;
      policy.MitigationOptIn = 1;
      SetProcessMitigationPolicy(ProcessSignaturePolicy, &policy, sizeof(policy))
    • 通过UpdateProcThreadAttribute修改线程属性。

      1
      2
      DWORD64 ProtectionLevel = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON; //policy.MitigationOptIn
      UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &ProtectionLevel, sizeof(ProtectionLevel), NULL, NULL)
1
2
3
4
5
6
// blockdlls policy
DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
// add process mitigation atribute
AttributeList->Attributes[2].Attribute = PS_ATTRIBUTE_MITIGATION_OPTIONS_2;
AttributeList->Attributes[2].Size = sizeof(DWORD64);
AttributeList->Attributes[2].ValuePtr = &policy;

0x02 Windows环境下的自保护探究

  • 这篇文章作者的思路是这样的,在kill 杀软进程的时候,会使用OpenProcess打开杀软进程,在OPenProcessAPI函数底层呢,会调用ObRegisterCallbacks注册回调函数,所以作者的目的就是通过注册回调函数,首先判断当前进程ID是否是杀软自身的PID,如果是的话,则去除Kill进程的权限。
    1
    OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;