服务排查脚本完善 | Windows 应急响应
2024-7-7 16:51:48 Author: mp.weixin.qq.com(查看原文) 阅读量:0 收藏

0x01 简介

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

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

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

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

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:\Users\helper\Desktop\bi nd s.exe"

其中 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 端口

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

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

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

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

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

0x03 问题分析

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

C:\Windows\system32\lsass.exe
C:\Windows\system32\svchost.exe -k netsvcs
C:\Program Files (x86)\Parallels\Parallels Tools\Services\prl_tools_service.exe
C:\Users\helper\Desktop\bi nd s.exe

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

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

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

  • C:\Users\helper\Desktop\bi
  • C:\Users\helper\Desktop\bi nd
  • C:\Users\helper\Desktop\bi nd s.exe

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

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

0x04 Windows 服务路径解析

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

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

当服务路径为  C:\Users\helper\Desktop\bi nd s.exe 时,Windows 服务查找的顺序为

  • C:\Users\helper\Desktop\bi
  • C:\Users\helper\Desktop\bi.exe
  • C:\Users\helper\Desktop\bi nd
  • C:\Users\helper\Desktop\bi nd.exe
  • C:\Users\helper\Desktop\bi nd s.exe
  • C:\Users\helper\Desktop\bi nd s.exe.exe

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

当服务路径为 C:\Users\helper\Desktop\t m p\bi nd s.exe 时的查找顺序如下:

  • C:\Users\helper\Desktop\t
  • C:\Users\helper\Desktop\t.exe
  • C:\Users\helper\Desktop\t m
  • C:\Users\helper\Desktop\t m.exe
  • C:\Users\helper\Desktop\t m p\bi
  • C:\Users\helper\Desktop\t m p\bi.exe
  • C:\Users\helper\Desktop\t m p\bi nd
  • C:\Users\helper\Desktop\t m p\bi nd.exe
  • C:\Users\helper\Desktop\t m p\bi nd s.exe
  • C:\Users\helper\Desktop\t m p\bi nd s.exe.exe

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

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

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

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

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

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

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

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

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

C:\Users\helper\Desktop\biC:\Users\helper\Desktop\bi.exe 是否可以执行?

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

C:\Users\helper\Desktop\bi .exeC:\Users\helper\Desktop\bi  .exeC:\Users\helper\Desktop\bi   .exe 是否可以执行?

经过测试,均不可以执行

C:\Users\helper\Desktop\bi ndC:\Users\helper\Desktop\bi  ndC:\Users\helper\Desktop\bi   nd 是否可以执行?

经过测试,只有 C:\Users\helper\Desktop\bi   nd  (三个空格) 可以执行

最终测试查找顺序如下

  • C:\Users\helper\Desktop\bi
  • C:\Users\helper\Desktop\bi.exe
  • C:\Users\helper\Desktop\bi   nd
  • C:\Users\helper\Desktop\bi   nd.exe
  • C:\Users\helper\Desktop\bi   nd   s.exe
  • C:\Users\helper\Desktop\bi   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 服务解析顺序下的第一个文件,并检测其签名

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

往期文章

有态度,不苟同

文章来源: https://mp.weixin.qq.com/s?__biz=MzU1NDkwMzAyMg==&mid=2247502017&idx=1&sn=9e3bd65ccd0aaa0e27004074d28ad6b4&chksm=fbdefc40cca97556bec06b6c2c3ba6126a43dafd21cfc6290adabc0f25182c68781f8d9e7ea1&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh