红队技术:对 Sysmon 的可靠对抗技巧-第一部分

7 月 23, 2023 技术分享

Sysmon 是什么

Sysmon 是一款可以全面记录系统行为日志的工具,全称为 System Monitor(系统监视),最初由美国 Winternals 软件有限公司的 Mark Russinovich 编写而成,作为 Sysinternals 实用工具套件的一部分,现在的所有者为微软。

截止至本文发布时间,Sysmon 已经更新至 15.0 版本,且已经支持了 Linux 系统,在大多数国产操作系统中也可以正常工作。

在第一部分中,我们只讨论 Sysmon 的 Windows 版本。

保持敬畏

很多从事红队或渗透测试工作的朋友,在进程列表中遭遇 Sysmon 的第一反应可能是:

  • A:它没有任何自身保护功能,Kill 掉它就万事大吉了;
  • B:它又不会阻拦我继续进行渗透测试,是无关紧要的;
  • C:拜托,很弱的啦。

可事实并非如此,在绝大多数已经部署 Sysmon 的企业或机构网络中,Sysmon 往往不是独立存在的。

Sysmon 可以收集的系统行为日志如下:

  • 进程创建
  • 进程退出
  • 文件的创建时间被修改
  • 网络连接
  • Sysmon 服务状态更改
  • Sysmon 配置更改
  • 驱动加载
  • 模块加载
  • DNS 查询
    ...

篇幅有限,详细的事件记录请查阅 官方文档

将各类行为日志提取后,后续的安全日志分析工具就开始发挥作用了,例如全球最流行的开源 SIEM 项目 Wazuh 和全球最大的日志分析商业平台 Splunk,它们采集到 Sysmon 的行为日志后,会通过内置的安全策略对行为日志进行筛选,找出可能对安全存在威胁的系统行为。

这种 日志收集 ->日志筛选 ->安全响应 模式,在安全运维机制良好的网络环境中是长期存在的,入侵者在系统中产生的行为数量,在广泛的行为日志中如沧海一粟。

所以,红队从一开始就处于完全监视之下,对上述模式采取不管不顾甚至是轻视的做法,最终会招致渗透测试完全失败的恶果,这是必然事件。

我们认为,以下做法是完全错误且十分不专业的,且可能会迅速吸引蓝队的注意:

  • 尝试破坏 Sysmon(这是最危险的行为)
  • 无视 Sysmon

从红队角度看,对行为事件采集源头的 Sysmon 保持敬畏之心,是十分有必要的。

定位 Sysmon

在准备应对 Sysmon 之前,红队必须确定当前系统中是否存在它,我们提供了一些方案用于定位 Sysmon。

Sysmon 由以下部分组成:

  • Sysmon 服务程序
  • Sysmon 驱动程序

使用 -i 参数可以将 Sysmon 以默认配置部署至系统中,如下图所示:

我们可以在系统服务和进程列表中观察到 Sysmon64,如下图所示:

该服务进程程序的路径默认为:

  • C:\Windows\Sysmon64.exe

驱动程序为:

  • C:\Windows\SysmonDrv.sys

注册表项路径:

  • 服务:HKLM\SYSTEM\ControlSet001\Services\Sysmon64
  • 驱动:HKLM\SYSTEM\ControlSet001\Services\SysmonDrv

过滤器实例信息:

  • 过滤器名:SysmonDrv
  • 实例名:Sysmon Instance
  • 过滤器高度:385201

想了解更多有关文件系统微型过滤器的知识,请参考微软 官方文档

通过查找以上信息,红队可以发现默认配置下的 Sysmon 部署情况,然而,不知出于有意或无意,Sysmon 允许用户通过改变安装参数和信息,避开上述所有的默认特征。

例如,使用如下安装操作,改变服务与进程名:

效果如下:

更多操作可以参考文章:Sysmon hide and seek

红队怎样才能定位到被彻底隐藏的 Sysmon?Sysmon 行为日志收集功能的核心是它的驱动程序,通过向系统注册上面提到的过滤器实例,Sysmon 才得以正常工作,我们可以先尝试枚举出所有的过滤器,然后找到它们对应的驱动程序路径:

Function Select-Column {
  [cmdletbinding(PositionalBinding = $False)]
  param(
    [Parameter(ValueFromPipeline, Mandatory)]
    $InputObject,

    [Parameter(Mandatory, Position = 0)]
    [int[]] $Index,

    [Parameter(Position = 1)]
    [int] $RequiredCount,

    [Parameter(Position = 2)]
    [string] $OutFieldSeparator = "`t"
  )

  process {
    if (($fields = -split $InputObject) -and ($RequiredCount -eq 0 -or $RequiredCount -eq $fields.Count)) {
      $fields[$Index] -join $OutFieldSeparator
    }
  }
}

$filterList = & "fltMC.exe" filters
$serviceList = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\*'

$filterList | Select-Column -Index 0 -RequiredCount 4 | Select-Object -Skip 1 | ForEach-Object {
  $__ = $_
  $serviceList | ForEach-Object {if($_.ImagePath -like "*$__.sys") { $_.ImagePath }}
}

遍历得到的驱动程序,获取它们的附加信息,并检索其中是否包含 Sysmon 关键字,随后,我们成功找到被隐藏起来的 Sysmon 驱动程序,如下图所示:

使用以上过程确定原版 Sysmon 是否部署,是非常准确的,因为,如果蓝队尝试修改掉 Sysmon 驱动程序的附加信息,就会使驱动程序二进制签名校验失败;如果蓝队重新对驱动程序进行签名,那就是另一个痛苦的故事了 🙂

* 如果你一定想破坏掉 Sysmon,较安全的办法已经在前面提到了,请仔细阅读并理解所有内容。

规则提取

以上步骤只是确定 Sysmon 是否部署,我们不建议红队对 Sysmon 功能进行任何形式的更改。

Sysmon 提取的特定行为类型,全部由配置文件定义,配置文件可以在 Sysmon 部署时指定并导入,也可以后续导入或更新,以下内容是一个简单的 Sysmon 配置,它允许 Sysmon 记录 cmd.exe 进程创建事件:

<Sysmon schemaversion="4.1">
    <HashAlgorithms>*</HashAlgorithms>
    <CheckRevocation/>
    <EventFiltering>
        <ProcessCreate onmatch="include">
            <Image condition="image">cmd.exe</Image>
        </ProcessCreate>
    </EventFiltering>
</Sysmon>

蓝队通常情况下,会在导入配置文件后,将配置文件删除,这不会影响 Sysmon 的正常工作。Sysmon 配置文件的内容以二进制形式保存在以下注册表值项中:

  • HKLM\SYSTEM\CurrentControlSet\Services\sysmonDrv\Parameters\Rules

正常情况下,蓝队或者管理员通过 -c 参数运行 Sysmon,可以将该二进制形式的配置转换为可读格式并打印,如下图所示:

但从红队角度出发,这是一个不太安全的操作,因为蓝队很可能提前准备了针对该命令执行的检测方案。

红队可以尝试使用注册表相关的 WIN32 API 对配置值项二进制进行转储,例如 RegQueryValueExW,然后将转储后的值项写入红队本地的对应注册表值项中,并通过在本地运行 Sysmon 的 -c 参数得到可读配置内容。

在 2018 年的 Black Hat(黑帽大会)中,Matt Graeber 和 Lee Christensen 分享了针对 Sysmon 的议题,并开源了他们的工作成果,链接如下:

其中我们认为非常有意思的部分,是对 Sysmon 二进制配置内容进行逆向的工作,你可以在 PSSysmonTools 项目中找到它,但是它已经停止维护了,对新版本的 Sysmon 配置无效,感兴趣的朋友可以自行学习。

小结

在本文中,我们简单的介绍了 Sysmon,描述了它在实际场景中的应用和十分有效的防御策略,并从红队角度出发,描述了准确的在 Windows 系统中找到 Sysmon 并获取可读配置内容的方法。

在第二部分中,我们还将会介绍 Sysmon 在 Linux 系统中使用的先进技术和优秀表现,并提出在 Linux 下的可靠对抗技巧,敬请期待。