• 浅谈EDR绕过


    前言

    我们知道一般EDR对可疑程序进行监控一般都会采用往程序里注入到检测的进程中,通过hook一些敏感的3环API来判断程序是否进行一些恶意操作,那么我们可以通过添加流程缓解措施和漏洞利用保护参考来实现保护,从而防止EDR的dll注入对进程进行检测。

    blockdlls

    在cs3.14版本过后引入了blockdlls命令,用于保护beacon生成的任何子进程不加载非 Microsoft 签名的 dll

    image-20220514200908639.png

    这里使用监听新增一个子会话

    image-20220514203519372.png

    可以看到rundll32.exe进程有了Signatures restricted (Microsoft only)标志

    image-20220514203515093.png

    UpdateProcThreadAttribute

    cs的实现在UpdateProcThreadAttribute函数,UpdateProcThreadAttributeAttribute参数0x20007实际上解析为PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,而0x100000000000解析为PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON。因此,cs 在这里所做的是使用CreateProcessAPI 调用以及STARTUPINFOEX包含缓解策略的结构,在这种情况下,用于阻止非 Microsoft签名的 DLL

    image-20220514200234928.png

    自己通过代码实现

    1. // Blockdlls.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    2. //
    3. #include <iostream>
    4. #include <windows.h>
    5. int main()
    6. {
    7.     STARTUPINFOEXA si;
    8.     PROCESS_INFORMATION pi;
    9.     SIZE_T size = 0;
    10.     BOOL ret;
    11.     ZeroMemory(&si, sizeof(si));
    12.     si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
    13.     si.StartupInfo.dwFlags = EXTENDED_STARTUPINFO_PRESENT;
    14.     InitializeProcThreadAttributeList(NULL10&size);
    15.     si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
    16.         GetProcessHeap(),
    17.         0,
    18.         size
    19.     );
    20.     InitializeProcThreadAttributeList(si.lpAttributeList, 10&size);
    21.     DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
    22.     UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULLNULL);
    23.     ret = CreateProcessA(
    24.         NULL,
    25.         (LPSTR)"C:\\Windows\\System32\\cmd.exe",
    26.         NULL,
    27.         NULL,
    28.         true,
    29.         EXTENDED_STARTUPINFO_PRESENT,
    30.         NULL,
    31.         NULL,
    32.         reinterpret_cast<LPSTARTUPINFOA>(&si),
    33.         &pi
    34.     );
    35. }

    实现效果如下

    image-20220514201702616.png

    直接进行注入则报错

    image-20220514201813898.png

    SetProcessMitigationPolicy

    这个api可以给当前线程添加 Signatures restricted (Microsoft only) 标识

    image-20220514213957237.png

    代码如下

    1. void blockdll_thread()
    2. {
    3.     PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY sp = {};
    4.     sp.MicrosoftSignedOnly = 1;
    5.     SetProcessMitigationPolicy(ProcessSignaturePolicy, &sp, sizeof(sp));
    6. }

    生成一下可以看到

    image-20220514202058247.png

    首先还是注入一下cs的dll失败

    image-20220514202841964.png

    然后注入user32.dll成功

    image-20220514202949912.png

    NtCreateUserProcess直接创建进程

    也可疑直接调用NtCreateUserProcess创建进程,通过设置参数为PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON来达到添加流程缓解措施的效果

    1. DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
    2. AttributeList->Attributes[0].Attribute = PS_ATTRIBUTE_MITIGATION_OPTIONS;
    3. AttributeList->Attributes[0].Size = sizeof(DWORD64);
    4. AttributeList->Attributes[0].ValuePtr = &policy;
    5. HANDLE hProcess, hThread = NULL;
    6. NtCreateUserProcess(&hProcess, &hThread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESSNULLNULLNULLNULL, ProcessParameters, &CreateInfo, AttributeList);

    image-20220514233952740.png

    检测

    使用powershell可以看到当前MicrosoftSignedOnly标志的进程

    get-process | select -exp processname -Unique | % { Get-ProcessMitigation -ErrorAction SilentlyContinue -RunningProcesses $_ | select processname, Id, @{l="Block non-MS Binaries"; e={$_.BinarySignature|select -exp MicrosoftSignedOnly} } }

    image-20220514203145571.png

    弊端

    有一些EDR拥有微软签名,其dll就能够注入到开启了blockdlls保护的进程,如@SEKTOR7 Institute发现的Crowdstrike Falcon就可以不受影响,那么我们还可以通过ACG来进行保护

    image-20220514222640449.png

    ACG

    ACG即漏洞利用保护参考,其作为一个可选功能添加进了Windows操作系统中,它可以用来检测和防止下列情况的出现

    1. 1. 现有代码被恶意修改

    2. 2. 向一个数据段中写入并执行代码

    为了实现这两个目标,ACG会强制执行这条规则:内存不能同时拥有写入权限和执行权限。更通俗点来说,开启了 ACG 保护的进程,就不能再用 VirtualProtectVirtualAlloc等来获得 PAGE_EXECUTE_READWRITE的内存,这里不赘述ACG的原理了,这里我们探究其实现

    要开启ACG,使用到的是SetProcessMitigationPolicy这个API,第一个参数指定要设定的缓解策略类型,第二个参数根据第一个参数指定不同的 Policy 数据,第三个参数指定第二个参数的长度

    1. BOOL SetProcessMitigationPolicy(
    2.   [in] PROCESS_MITIGATION_POLICY MitigationPolicy,
    3.   [in] PVOID                     lpBuffer,
    4.   [in] SIZE_T                    dwLength
    5. );

    支持的缓解策略如下

    1. typedef enum _PROCESS_MITIGATION_POLICY { 
    2.   ProcessDEPPolicy                    = 0,
    3.   ProcessASLRPolicy                   = 1,
    4.   ProcessDynamicCodePolicy            = 2,
    5.   ProcessStrictHandleCheckPolicy      = 3,
    6.   ProcessSystemCallDisablePolicy      = 4,
    7.   ProcessMitigationOptionsMask        = 5,
    8.   ProcessExtensionPointDisablePolicy  = 6,
    9.   ProcessControlFlowGuardPolicy       = 7,
    10.   ProcessSignaturePolicy              = 8,
    11.   ProcessFontDisablePolicy            = 9,
    12.   ProcessImageLoadPolicy              = 10,
    13.   MaxProcessMitigationPolicy          = 11
    14. } PROCESS_MITIGATION_POLICY, *PPROCESS_MITIGATION_POLICY;

    这里我们通过代码开启ACG

    1. PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy;
    2. ZeroMemory(&policy, sizeof(policy));
    3. policy.ProhibitDynamicCode = 1;
    4. SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &policy, sizeof(policy))

    我们首先在不开启ACG之前用VirtualAlloc申请一块RWX内存,然后再开启ACG,再使用VitualAlloc申请一块内存能否申请成功,再使用VirtualProtect看能否更改内存属性,实现代码如下

    1. BOOL ACG()
    2. {
    3.     STARTUPINFOEX si;
    4.     DWORD oldProtection;
    5.     PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy;
    6.     ZeroMemory(&policy, sizeof(policy));
    7.     policy.ProhibitDynamicCode = 1;
    8.     void* mem = VirtualAlloc(01024, MEM_RESERVE | MEM_COMMITPAGE_EXECUTE_READWRITE);
    9.     if (mem == NULL
    10.     {
    11.         printf("[!] RMX memory alloc failed!\n");
    12.     }
    13.     else 
    14.     {
    15.         printf("[*] RWX memory address : %p\n", mem);
    16.     }
    17.     printf("[*] Now running SetProcessMitigationPolicy to apply PROCESS_MITIGATION_DYNAMIC_CODE_POLICY\n");
    18.     if (SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &policy, sizeof(policy)) == false
    19.     {
    20.         printf("[!] SetProcessMitigationPolicy failed\n");
    21.         return FALSE;
    22.     }
    23.     mem = VirtualAlloc(01024, MEM_RESERVE | MEM_COMMITPAGE_EXECUTE_READWRITE);
    24.     if (mem == NULL
    25.     {
    26.         printf("[!] RMX memory alloc failed!\n");
    27.     }
    28.     else 
    29.     {
    30.         printf("[*] RWX memory address : %p\n", mem);
    31.     }
    32.     void* ntAllocateVirtualMemory = GetProcAddress(LoadLibraryA("ntdll.dll"), "NtAllocateVirtualMemory");
    33.     if (!VirtualProtect(ntAllocateVirtualMemory, 4096PAGE_EXECUTE_READWRITE, &oldProtection)) 
    34.     {
    35.         printf("[!] Failed change memory to RMX!\n");
    36.     }
    37.     else 
    38.     {
    39.         printf("[*] Changed memory to RMX successfully!\n");
    40.     }
    41. }

    可以看到在没有开启ACG的情况下内存可以申请成功,开启ACG之后申请内存失败,使用VirtualProtect也不能够更改内存属性

    image-20220514221816379.png

    我们知道一般EDR对可疑程序进行监控一般都会采用往程序里注入到想检测的进程中,通过hook一些敏感的3环API来判断程序是否进行一些恶意操作,我们知道一般内存不会拥有可执行权限,那么当EDR如果要想挂钩API函数,就需要通过VirtualProtect来更改内存属性,那么这时候如果将木马开启ACG保护,就可疑免受EDR的监控,即使EDR的dll拥有微软的签名

    检测

    这里用到GetProcessMitigationPolicy这个API

    1. BOOL GetProcessMitigationPolicy(
    2.   [in]  HANDLE                    hProcess,
    3.   [in]  PROCESS_MITIGATION_POLICY MitigationPolicy,
    4.   [out] PVOID                     lpBuffer,
    5.   [in]  SIZE_T                    dwLength
    6. );

    主要看第二个参数,我们这里检测ProcessDynamicCodePolicyProcessSignaturePolicy

    image-20220514231058690.png

    首先OpenProcess打开句柄

    HANDLE pHandle = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid);

    然后调用GetProcessMitigationPolicy检测策略

    1.     GetProcessMitigationPolicy(pHandle, ProcessDynamicCodePolicy, &dynamicCodePolicy, sizeof(dynamicCodePolicy));
    2.     if (dynamicCodePolicy.ProhibitDynamicCode) 
    3.     {
    4.         printf("[%s] - ProhibitDynamicCode\n", exe);
    5.     }
    6.     if (dynamicCodePolicy.AllowRemoteDowngrade) 
    7.     {
    8.         printf("[%s] - AllowRemoteDowngrade\n", exe);
    9.     }
    10.     if (dynamicCodePolicy.AllowThreadOptOut) 
    11.     {
    12.         printf("[%s] - AllowThreadOptOut\n", exe);
    13.     }

    检查DLL加载策略同理

    1.     GetProcessMitigationPolicy(pHandle, ProcessSignaturePolicy, &signaturePolicy, sizeof(signaturePolicy));
    2.     if (signaturePolicy.AuditMicrosoftSignedOnly) {
    3.         printf("[%s] AuditMicrosoftSignedOnly\n", exe);
    4.     }
    5.     if (signaturePolicy.AuditStoreSignedOnly) {
    6.         printf("[%s] - AuditStoreSignedOnly\n", exe);
    7.     }
    8.     if (signaturePolicy.MicrosoftSignedOnly) {
    9.         printf("[%s] - MicrosoftSignedOnly\n", exe);
    10.     }
    11.     if (signaturePolicy.MitigationOptIn) {
    12.         printf("[%s] - MitigationOptIn\n", exe);
    13.     }
    14.     if (signaturePolicy.StoreSignedOnly) {
    15.         printf("[%s] - StoreSignedOnly\n", exe);
    16.     }

    这里通过进程名获取PID、提权的函数在这里就不赘述了,看下实现效果,可以看到有一些进程启用了ProcessDynamicCodePolicy

    image-20220514224105140.png

    看一下我们之前写的ACG程序,也是开启了保护的

  • 相关阅读:
    SSM汽车出租管理系统
    Vue路由
    Camera2/HAL3 参考
    蓝牙核心规范(V5.4)10.2-BLE 入门笔记之CIS篇
    MYSQL之外键约束
    Kotlin 开发Android app(四):Kotlin 四大容器Set,Array,List,Map
    ATF启动(六):bl32(OP-TEE)-->bl33 ATF ending
    如何在 PC 机上测试移动端的网页?
    一致性哈希的简单认识
    【Unity】Unity坑的集锦之RenderTexture打包黑屏
  • 原文地址:https://blog.csdn.net/hongduilanjun/article/details/126850875