T1546.010@权限维持武器化

0x01 前言

​ 最近发现目标上线后,感觉不对劲就直接关机重启了。还是常规权限维持的话,稍不注意,内网没点了的话,那又得😭😭重新🎣。

​ 🫡为适配关机重启的场景,本文尝试对T1546.010进行武器化。

0x02 介绍

​ T1546.010,T1546的子技术,其描述了Windows的一个注册表特性。

image-20230331115307329

​ Windows操作系统的注册表中默认提供了AppInit_Dlls和LoadAppInit_Dlls两个注册表表项。如果LoadAppInit_Dlls的键值设置为1,同时在AppInit_DLLs值中指定动态链接库,那么当机器重启后,指定的动态链接库将由user32.dll加载到加载user32.dll的每个进程中。

image-20230331000628164

​ 依靠这一特性,除非重装系统,否则即便关机重启也可以实现再次上线。

0x03 测试

1、定位注册表表项

AppInit_Dlls 和 LoadAppInit_Dlls两个注册表表项路径:

1
2
计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_Dlls
计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\LoadAppInit_Dlls

image-20230331002558874

2、编辑Dll代码

​ “当机器重启后,指定的动态链接库将由user32.dll加载到加载user32.dll的每个进程中。”,也就是说所有调用到user32.dll的程序都会调用到指定的动态链接库。

​ 那么,为避免重复上线,需要精心设计Dll的限制条件:比如当检测到存在某个进程时(这个进程最好是Windows自带的,避免因机器的不同导致失去效果,同时也要注意尽量选择操作系统自启动类型的同时又不会影响到系统运行的进程),才触发执行。以弹窗子为例😁

​ ctfmon.exe 是Windows提供语音识别、手写识别、键盘、翻译和其它用户输入技术支持的程序。其加载了user32.dll,故可以由user32.dll加载指定的动态链接库到加载user32.dll的每个进程中。

image-20230331194149038

该段Dll代码的意思是在加载Dll的过程中,当检测到ctfmon.exe进程后,触发弹窗子。

image-20230331194933449

3、修改注册表表项

​ 修改AppInit_Dlls 表项,填充编译好的dll路径

image-20230331010645080

​ 修改LoadAppInit_Dlls的项目值,设置为1

image-20230331010716836

4、重启机器测试效果

​ 查看的Dll_Injection_AppInit_Dlls.dll加载情况,可以看到,Dll_Injection_AppInit_Dlls.dll注入到所有运行进程。

image-20230331200715259

​ 但只有ctfmon.exe进程执行时,加载的Dll_Injection_AppInit_Dlls.dll中的窗口才会弹出执行。

image-20230331200923169

0x04 实战

​ 实战环境下,武器化包括两个过程:@1、Dll的免杀和限制;@2、操作注册表表项。

1、Dll未做限制

​ 可以看到上线的进程中既有system*的也有普通用户的,既有上线即掉也有持续存活的,既有多个进程持续上线的也有只上线一次的,既有系统进程也有用户态进程,所以限制进程需要满足:@操作系统进程;@持续存活;@上线次数尽量少;@尽量为system。进程略😁

image-20230401143355121

2、Dll免杀处理

​ 免杀处理非常简单,只需过静态即可,如:@shellcode编码转换;@回调函数加载执行。代码略😁

image-20230402013135265

image-20230402013259692

image-20230402164910796

image-20230402164950098

image-20230402165236245

3、操作注册表

​ 很多时候,直接在主机内操作注册表都会引起AV或EDR的告警。如:监控reg是否被调用

1
2
reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /t REG_SZ /d "DLL路径" /f
reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t REG_DWORD /d 1 /f

​ 当然,也可以在cs中利用runshellpowershell或者进程注入到可信进程下,构造进程链尝试执行reg(有些EDR会区分常见进程和不常见进程)。

image-20230402173402094

​ 所以最好的方式是通过Windows API,实现操作注册表,绕过reg的监控。

image-20230402180744531

​ 不过,以Windows API的方式会带来一个不太优雅的问题:执行操作注册表的ConsoleApplication1.exe需要落地到目标机器内。

image-20230402181137558

​ 操作注册表的行为,如果针对性配置规则的话,也可以看到两个告警:

image-20230402184306390

​ Unusual Parent-Child Relationship:

image-20230402184654817

​ Registry Persistence via AppInit DLL:

image-20230402184510297

​ 优雅的实现无文件落地问题的方式有两种:

​ @1:c#程序+execute-assembly内存加载

​ 通过c#编写.net程序,在使用时通过cs的execute-assembly命令加载到内存中执行。

​ 但这种方式可能会依赖目标主机的.net版本环境,同时如果稍不注意忘记bypassETW,可能就被检测发现,参考跳跳糖社区《ETW的攻与防》。

​ @2: RDI+bdllspawn反射加载

​ RDI,也叫反射Dll注入,简单描述就是与传统的DLL注入方式不同,反射Dll注入不需要将Dll文件写入目标进程的地址空间中,而是利用目标进程中的某些函数,将Dll文件“反射”到目标进程的内存中,从而实现Dll文件的加载和执行。同时cs也提供了bdllspawn来进行反射Dll。

​ 以“RDI+bdllspawn反射加载”的方式既可实现无文件落地,也可避免环境的影响,同时在一定程度上绕过某些检测规则。

​ 编写cs插件代码:

1
2
3
4
alias appinit_dll {
$args = substr($0, 12);
bdllspawn($1, script_resource("reflective_dll.x64.dll"),$args, "AppInit_Dlls Injection", 5000, false);
}

​ RDI代码略😁

image-20230403001636444

​ 直接在cs上运行插件,输入Dll路径,即可完成权限维持。

image-20230403001733100

​ 至此,T1546.010武器化完成🤓。

image-20230403002159068