服务排查脚本完善 | Windows 应急响应

admin 2024年7月7日23:28:32评论18 views字数 6386阅读21分17秒阅读模式

0x01 简介

大家好,我们是 NOP Team,在之前的应急响应相关的文章中,我们提到了服务的隐藏与排查,还有如何验证可执行文件是可靠的,在 《Windows 应急响应手册》中我们给出了进阶性排查的脚本,大概的排查方式就是将所有的服务对应的命令中的启动程序拿出来,检查该程序的签名是否为微软官方的有效签名。

在后期应急响应过程中,发现一个问题: Windows Server 2016 中这个服务对应命令字符串格式比较宽泛,但开发者的使用过程中并不一定遵守什么规范,就导致可能出现一些奇怪的格式,例如存在被双引号包裹的命令,也有没有被双引号包裹的,这部分在之前的脚本中已经特别处理了,真正遇到的问题是文件名称里带空格的,举个例子

服务排查脚本完善 | Windows 应急响应

这还只是文件名存在空格,更有甚者如下

服务排查脚本完善 | Windows 应急响应

遇到这类的服务命令,之前的脚本就会报错,今天这篇文章就是测试一下服务的具体执行情况,完善脚本

0x02 问题展示

之前的脚本如下

$microsoftCNS = @('Microsoft Corporation', 'Microsoft Windows', 'Microsoft Windows Hardware Compatibility Publisher', 'Microsoft Update', 'Microsoft Windows Publisher')

# 定义函数来进行签名校验
function Verify-FileSignature {
param (
[Parameter(Mandatory=$true)]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$FilePath
)

if (Test-Path -Path $FilePath -PathType Leaf) {
$signature = Get-AuthenticodeSignature -FilePath $FilePath

if ($signature.Status -eq 'Valid') {
$publisher = $signature.SignerCertificate.Subject

# 解析发布者信息以提取 CN 字段的值
$cnValues = @(($publisher -split ', ' | Where-Object { $_ -like 'CN=*' }).Substring(3))

if ($cnValues.Count -eq 1) {
$cnValue = $cnValues[0]
# Write-Output "CN 字段的值: $cnValue"

# 判断 CN 字段是否为微软官方
if ($microsoftCNS -contains $cnValue) {
# Write-Output "CN 字段值为微软官方。"
return "Valid"
}
}
}

return "Invalid"

}

return "File Not Found"

}

$services = Get-WmiObject -Class Win32_Service | Where-Object { $_.PathName -ne $null }
foreach ($service in $services) {
$executablePath = $service.PathName
if ($executablePath.StartsWith('"')) {
$executablePath = $executablePath.Split('"')[1]
} else {
$executablePath = $executablePath.Split(' ')[0]
}

if ($executablePath -ne $null) {
$fileInfo = Get-Item -LiteralPath $executablePath
$result = Verify-FileSignature -FilePath $executablePath
if ($result -ne 'Valid') {
Write-Host "---------------------------------------"
Write-Host "Service Name: $($service.Name)"
Write-Host "Executable Path: $executablePath"
Write-Host "Signature Status: $result"
Write-Host ""
}
}
}

我们创建一个服务,服务对应的程序名称里放置一个空格,看看效果怎么样?

sc create BindService binPath= "C:UsershelperDesktopbi nd s.exe"
服务排查脚本完善 | Windows 应急响应
服务排查脚本完善 | Windows 应急响应

其中 bi nd s.exe 程序为 Metasploit Framework 生成的木马,传到测试服务器上并重命名为 bi nd s.exe

msfvenom -p windows/meterpreter/bind_tcp lport=4477 -f exe-service -o bind.exe

当程序以服务的形式启动的时候,会自动监听 4477 端口

服务排查脚本完善 | Windows 应急响应

当前服务未启动,所以此时没有监听相关端口,现在启动该服务

服务排查脚本完善 | Windows 应急响应
服务排查脚本完善 | Windows 应急响应
服务排查脚本完善 | Windows 应急响应

服务启动后,我们的木马程序成功启动,监听 4477 端口,所以 Windows 是可以正确识别 C:UsershelperDesktopbi nd s.exe 这种字符串的,并且可以正确找到要执行的程序

我们现在看一下原来的脚本检查过程中会发生什么?

服务排查脚本完善 | Windows 应急响应

可以看到,创建新的服务后,检查脚本会报错,报错为 Get-Item : 找不到路径“C:UsershelperDesktopbi”,因为该路径不存在。

这显然是我们的脚本写的时候没有想到会有开发者设置服务的时候,文件名竟然会有空格,所以导致报错,我们直接修改一下,让其匹配完整路径就好了

0x03 问题分析

想让脚本正确匹配到完整路径并不容易,服务对应的命令字符串可能是如下格式

C:Windowssystem32lsass.exe
C:Windowssystem32svchost.exe -k netsvcs
C:Program Files (x86)ParallelsParallels ToolsServicesprl_tools_service.exe
C:UsershelperDesktopbi nd s.exe

之前我们对路径做了处理,所以主要问题出现在文件名称以及参数上,如果是单文件名,那么很好办,直接用就可以了;如果遇到第二个这种带参数的,就比较难办了,所以之前是用空格做分隔,取第一个值,但现在出现了第四个这种,名称里带空格的,这种方法明显就有错误了,怎么办呢?

要不遇到空格就分组,之后不断拼接,直到找到程序?

例如下面的顺序寻找 C:UsershelperDesktopbi nd s.exe ,直到找到一个有效可执行文件

  • C:UsershelperDesktopbi
  • C:UsershelperDesktopbi nd
  • C:UsershelperDesktopbi nd s.exe

但这有一个问题,如果要执行的是 bi nd s.exe ,好巧不巧,该路径下刚好有一个叫做 bi 的文件,这种情况下是不是就会导致错误匹配,导致检查不准确呢?

等等,Windows 本身是如何识别包容性这么高的命令字符串的呢?我应该和 Windows 保持一致啊!

0x04 Windows 服务路径解析

说到 Windows 路径解析,大家可能一下子就想到了解析路径导致 DLL 劫持相关的内容,之后大家可能会想起 Windows 路径解析规则,但是我还是喜欢手动测试一遍

测试过程就不给大家展示了,直接说结论吧

当服务路径为  C:UsershelperDesktopbi nd s.exe 时,Windows 服务查找的顺序为

  • C:UsershelperDesktopbi
  • C:UsershelperDesktopbi.exe
  • C:UsershelperDesktopbi nd
  • C:UsershelperDesktopbi nd.exe
  • C:UsershelperDesktopbi nd s.exe
  • C:UsershelperDesktopbi nd s.exe.exe

大家没有看错,Windows 并不是直接找完整路径,而是一点一点来的,而且对于服务程序来说,不需要后缀为 exe 也是可以执行的,而且 Windows 还会自动在文件名称后面加入 .exe 来匹配,也就是上面的 C:UsershelperDesktopbi.exeC:UsershelperDesktopbi nd.exeC:UsershelperDesktopbi nd s.exe.exe

当服务路径为 C:UsershelperDesktopt m pbi nd s.exe 时的查找顺序如下:

  • C:UsershelperDesktopt
  • C:UsershelperDesktopt.exe
  • C:UsershelperDesktopt m
  • C:UsershelperDesktopt m.exe
  • C:UsershelperDesktopt m pbi
  • C:UsershelperDesktopt m pbi.exe
  • C:UsershelperDesktopt m pbi nd
  • C:UsershelperDesktopt m pbi nd.exe
  • C:UsershelperDesktopt m pbi nd s.exe
  • C:UsershelperDesktopt m pbi nd s.exe.exe

当目录中存在空格时,解析规则也是类似的,只不过目录名字以及目录名字.exe 不会解析

对于常规来说,上面的情况已经足够了,但是我们面对的是攻击者,一群想方设法逃避检测的人,我们需要再多探究一些,如果路径空格不只一个会怎么样?

C:UsershelperDesktopbi   nd   s.exe 为例,这其中都是三个空格,首先看看能不能创建成功

服务排查脚本完善 | Windows 应急响应
服务排查脚本完善 | Windows 应急响应

看来创建没有问题,如果放置一个 bi   nd   s.exe 能够正常启动吗?

服务排查脚本完善 | Windows 应急响应

能够正常启动,功能没问题,现在问题来了,现在匹配的时候最先匹配的是 bi 还是 bi ,Windows图形化修改文件名称最后面添加空格是没用的,试试能不能通过命令行修改

服务排查脚本完善 | Windows 应急响应

通过命令行 ren 命令无法在文件名称后面加空格,试试 PowerShell

服务排查脚本完善 | Windows 应急响应

发现 ren 和 PowerShell 修改也没有用,在 Windows 中似乎文件名后面可以随便加空格

服务排查脚本完善 | Windows 应急响应

看起来这样似乎就与之前单空格的时候一样了,是这样吗?

还是有不少场景需要我们测试一下的

C:UsershelperDesktopbiC:UsershelperDesktopbi.exe 是否可以执行?

经过测试,可以执行,顺序与之前一致

C:UsershelperDesktopbi .exeC:UsershelperDesktopbi  .exeC:UsershelperDesktopbi   .exe 是否可以执行?

经过测试,均不可以执行

C:UsershelperDesktopbi ndC:UsershelperDesktopbi  ndC:UsershelperDesktopbi   nd 是否可以执行?

经过测试,只有 C:UsershelperDesktopbi   nd  (三个空格) 可以执行

最终测试查找顺序如下

  • C:UsershelperDesktopbi
  • C:UsershelperDesktopbi.exe
  • C:UsershelperDesktopbi   nd
  • C:UsershelperDesktopbi   nd.exe
  • C:UsershelperDesktopbi   nd   s.exe
  • C:UsershelperDesktopbi   nd   s.exe.exe

与一个空格顺序基本一致

0x05 检测脚本

经过测试,我们基本上已经搞清楚了 Windows 服务路径解析顺序,我们修改脚本,新的脚本如下:

$microsoftCNS = @('Microsoft Corporation', 'Microsoft Windows', 'Microsoft Windows Hardware Compatibility Publisher', 'Microsoft Update', 'Microsoft Windows Publisher')

# 定义函数来进行签名校验
function Verify-FileSignature {
param (
[Parameter(Mandatory=$true)]
[string]$FilePath
)

if (Test-Path -Path $FilePath -PathType Leaf) {
$signature = Get-AuthenticodeSignature -FilePath $FilePath

if ($signature.Status -eq 'Valid') {
$publisher = $signature.SignerCertificate.Subject

# 解析发布者信息以提取 CN 字段的值
$cnValues = @(($publisher -split ', ' | Where-Object { $_ -like 'CN=*' }).Substring(3))

if ($cnValues.Count -eq 1) {
$cnValue = $cnValues[0]

# 判断 CN 字段是否为微软官方
if ($microsoftCNS -contains $cnValue) {
return "Valid"
}
}
}

return "Invalid"
}

return "File Not Found"
}

# 获取所有服务
$services = Get-WmiObject -Class Win32_Service | Where-Object { $_.PathName -ne $null }
foreach ($service in $services) {
$path = $service.PathName

# 去掉双引号
if ($path.StartsWith('"') -and $path.EndsWith('"')) {
$path = $path.Trim('"')
}

# 处理路径中包含空格的情况
$potentialPaths = @()
$parts = $path -split ' '
for ($i = 0; $i -lt $parts.Length; $i++) {
$potentialPath = ($parts[0..$i] -join ' ')

if (Test-Path -Path $potentialPath -PathType Leaf) {
$potentialPaths += $potentialPath
} elseif (Test-Path -Path "$potentialPath.exe" -PathType Leaf) {
$potentialPaths += "$potentialPath.exe"
}

if ($potentialPaths.Length -ge 1) {
break
}
}

# 逐个验证找到的可执行文件路径
foreach ($potentialPath in $potentialPaths) {
$result = Verify-FileSignature -FilePath $potentialPath
if ($result -ne 'Valid') {
Write-Host "---------------------------------------"
Write-Host "Service Name: $($service.Name)"
Write-Host "Executable Path: $potentialPath"
Write-Host "Signature Status: $result"
Write-Host ""
}
}
}
服务排查脚本完善 | Windows 应急响应

新的脚本可以成功帮我们找到 Windows 服务解析顺序下的第一个文件,并检测其签名

当然,脚本检测没问题不代表真的没问题,毕竟可以白加黑嘛,如果攻击者利用微软签名的程序进行白加黑,那么检测签名也不会检测出来,而且微软官方的 DLL 文件也没有签名,不是很容易判断,如果后续有其他好方法,会再次完善脚本

原文始发于微信公众号(NOP Team):服务排查脚本完善 | Windows 应急响应

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月7日23:28:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   服务排查脚本完善 | Windows 应急响应https://cn-sec.com/archives/2928811.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息