前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RunAsPPL的对抗

RunAsPPL的对抗

作者头像
Gamma实验室
发布2022-01-18 15:41:49
1.4K0
发布2022-01-18 15:41:49
举报

启用LSA进程的保护

LSA 保护又名 RunAsPPL

这里直接引用官网的官方文档:https://docs.microsoft.com/en-us/windowsserver/security/credentials-protection-and-management/configuringadditional-lsa-protection#to-disable-lsa-protection

开启RunAsPPL 一般有两种方法

1.在单台计算机上启用 LSA 保护

1. 打开注册表编辑器 (RegEdit.exe),然后导航到位于以下位置的注册表项:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa。

2. 将注册表项的值设置为:“RunAsPPL”=dword:00000001。

3. 重新启动计算机。

2.使用组策略启用 LSA 保护

1. 打开组策略管理控制台 (GPMC)。

2. 创建在域级别链接或链接到包含您的计算机帐户的组织单位的新 GPO。或者,您可以选择已部署的 GPO。

3. 右键单击 GPO,然后单击编辑以打开组策略管理编辑器。

4. 展开计算机配置,展开首选项,然后展开Windows 设置

5. 右键单击“注册表”,指向“新建”,然后单击“注册表项”。出现“新建注册表属性”对话框。

6. 在Hive列表中,单击HKEY_LOCAL_MACHINE

7. 在Key Path列表中,浏览到SYSTEM\CurrentControlSet\Control\Lsa

8. 在值名称框中,键入RunAsPPL

9. 在值类型框中,单击REG_DWORD

10. 在数值数据框中,键入00000001

11. 单击“确定”

然后重启

RunAsPPL的作用

开启了RunAsPPL,可以看到就算有debug权限,也无法对lsa进程进行操作

而在minikatz实现的代码上来看,通过调试,错误代码定位到这一段:

modules/sekurlsa/kuhl_m_sekurlsa.c

HANDLE hData = NULL;
DWORD pid;
DWORD processRights = PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;

kull_m_process_getProcessIdForName(L"lsass.exe", &pid); 
hData = OpenProcess(processRights, FALSE, pid);

if (hData && hData != INVALID_HANDLE_VALUE)#报错地方
{
   打开进程具柄
} else {
   PRINT_ERROR_AUTO(L"Handle on memory");
}

该代码首先获取了lsass.exe的进程具柄,然后去尝试打开它,结果被拒绝,结果出错了,从报错信息来看0X0000005一般就是没有权限的意思,在这里,lsass进程被保护了,而minikatz进程是没有签名的,是不被信任的,所以无法打开lsass进程的句柄。

而RunAsPPL本身的特点就是:”只有经过数字签名的二进制文件才能访问受保护的进程“

可以对比一下开启RunAsPPL前后lsass.exe进程的保护级别变化

开启之前,没有保护级别:

开启之后,保护级别为PS_PROTECTED_LSA_LIGHT:

了解保护级别,还得知道PPL

PPL(Protected Process Light),是在Windows 8.1/ Server 2012 R2 开始引入这个概念的,而PPL实际上是对之前Protected Process模型的扩展,增加了“Protection level”的概念,基本上就是说一些PP(L)进程可以比其他进程受到更多的保护。

从微软的官方文档可以看到,

https://docs.microsoft.com/en-us/windows/win32/procthread/zwqueryinformationprocess

进程的保护级别存储在其Protection成员中

结构体如下:

typedef struct _PS_PROTECTION {
   union {
       UCHAR Level;
       struct {
           UCHAR Type   : 3;
           UCHAR Audit : 1;                  // Reserved
           UCHAR Signer : 4;
      };
  };
} PS_PROTECTION, *PPS_PROTECTION;

尽管它表示为一个结构,但所有信息都存储在单个字节的两个半字节中。

例如:前 3 位代表保护Type,它定义了进程是 PP 还是 PPL。

typedef enum _PS_PROTECTED_TYPE {
   PsProtectedTypeNone = 0,
   PsProtectedTypeProtectedLight = 1,
   PsProtectedTypeProtected = 2
} PS_PROTECTED_TYPE, *PPS_PROTECTED_TYPE;

最后 4 位代表Signer类型,即实际的保护级别。

typedef enum _PS_PROTECTED_SIGNER {
  PsProtectedSignerNone = 0,     // 0
  PsProtectedSignerAuthenticode, // 1
  PsProtectedSignerCodeGen,       // 2
  PsProtectedSignerAntimalware,   // 3
  PsProtectedSignerLsa,           // 4
  PsProtectedSignerWindows,       // 5
  PsProtectedSignerWinTcb,       // 6
  PsProtectedSignerWinSystem,     // 7
  PsProtectedSignerApp,           // 8
  PsProtectedSignerMax           // 9
} PS_PROTECTED_SIGNER, *PPS_PROTECTED_SIGNER;

所以进程的保护级别是由type和Signer共同决定的

RunAsPPL绕过

其实RunAsPPl绕过,基本上都是靠加载驱动数字签名程序,因为在内核执行代码是真的可以为所欲为,完全可以禁用这种保护,但也有另辟蹊径的办法,办法总是比困难多不是。

1.minikatz bypass

minikatz提供通过数字签名驱动程序来删除内核中 Process 对象的保护标志的功能,只要把那个标志删除,lsass进程就不会被保护了,具体得使用mimidrv.sys这个驱动文件,这个文件可以在github上面下载,也可以自己编译。

mimikatz # !+                                               #安装驱动,启动服务
mimikatz # !processprotect /process:lsass.exe /remove       #删除标志
mimikatz # privilege::debug
mimikatz # sekurlsa::logonpasswords

停止服务

mimikatz # !-

2.自带驱动程序bypass

这个bypass的点就是加载一个官方的易受攻击的驱动程序,可以利用它在内核中运行任意代码,在我们加载官方驱动程序后,可以继续利用它来加载我们自己的未签名的驱动程序,这种技术不仅在此对抗lsa进程保护有出现,之前通过该相同原理,也实现了直接关杀软的实际案例。

github项目参考:

https://github.com/RedCursorSecurityConsulting/PPLKiller

这个项目用的是RTCore32.sys和RTCore64.sys 的驱动

PPL好像禁止不了,但是lsa的保护可以直接去掉。

3.PyPyKatz bypass

GitHub 项目:

https://github.com/skelsec/pypykatz

python实现的minikatz的部分功能

其中实现的主要bypass原理,是不采用传统的解析lsass.exe的方式

传统的流程如下:

1. 获取调试权限。

2. 找到 LSASS 进程的 PID。

3. 通过调用OpenProcess方法打开 LSASS 进程。

4. 初始化一个虚拟读取器并将进程句柄传递给它。

5. 使用此阅读器开始解析 VAS 并提取凭据。

这很容易被杀软,edr和杀软检测到的,因为OpenProcess这个api调用太明显了。

其pypykatz实现了在不打开 LSASS 的情况下获得 LSASS 的句柄的技术,实现流程如下:

1. 获得调试权限。

2. 从NtQuerySystemInformation 获取所有的进程句柄

3. 具有PROCESS_DUP_HANDLE特权的OpenProcess这允许我们复制句柄,我们直接复制进程句柄。

4. NtDuplicateObject将获取远程进程句柄的副本到我们的进程,建议至少PROCESS_VM_READ通过DesiredAccess。

5. NtQueryObject 过滤不是进程的句柄(NtQueryObject相当于一个进程具柄过滤器)

6. 如果是进程句柄,则使用该句柄调用的QueryFullProcessImageName将显示进程可执行路径,以此我们找到lsass.exe的进程具柄。

7. 然后直接解析lsass.exe

在实现的方面,避免了OpenProcess的调用,也避免使用lsass.exe的本身句柄,而是采用的复制的句柄的方式。

4.Userland bypass

Userland 早先是一个提权漏洞,利用任意对象目录创建实现本地特权提升

Github参考项目:https://github.com/itm4n/PPLdump

这里拿来用做PPL绕过是很巧妙的。

我们要知道,当一个进程被创建时,它首先会通过“已知 DLL”列表(为了提高效率)去搜索dll,然后在应用程序的目录,系统目录等等......在这个搜索顺序中,“已知 DLL”是最高优先级的。

“已知 DLL” 是 Windows 应用程序最常加载的 DLL,它们被预加载到内存中(即它们被缓存),可以通过查看\KnownDlls对象管理器中目录的内容来查看缓存的dll

关键点来了,在正常的程序启动时,程序加载dll,仅在映射文件时进行验证,即创建节的时候,相比之下PP进程是会进行dll的数字签名验证的过后才能加载,而PPL又和正常程序一样一样,这就是漏洞利用点,因为 DLL 的数字签名仅在映射文件时进行验证,即在创建节时,所以如果能够向\KnownDlls目录中添加任意条目,那么您就可以注入任意 DLL 并在 PPL 中执行未签名的代码。

利用过程:

1.利用 CSRSS 服务创建目标路径符号链接(这个路径是我们进行控制的,例如\KnownDlls\FOO.dll),在实际的利用过程中,该目标路径必须是一个 Section 对象,而不是 DLL 文件路径。

2.劫持services.exe的dll(因为第一步需要Section节对象,所以这里就要先嵌入一个我们自己的 DLL,将其写入磁盘,打开它CreateFile以获取文件的句柄,最后调用NtCreateSection来创建一个Section)。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Gamma安全实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开启RunAsPPL 一般有两种方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档