我们的 .NET Framework C# 应用程序有两个部分:客户端(未提升)和服务(提升)。客户端和服务之间的通信通过命名管道进行。每当要执行提升的任务时,客户端(命名管道客户端)始终与服务(命名管道服务器)通信。通信采用 JSON 字符串的形式。需要保护此通信的安全,以便服务不会被欺骗而代表攻击者执行提升的任务。 @Xecrets 该服务是客户端执行提升任务的一种特权助手。该服务具有一些强大的功能,例如将文件复制到 Program Files、安装 MSI 以及运行 .reg 注册表文件。
服务器端已经采取了一些安全措施:
PipeSecurity pipeSecurity = new PipeSecurity();
var id = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
// Allow read and write access to the pipe from different user sessions
pipeSecurity.SetAccessRule(new PipeAccessRule(id, PipeAccessRights.ReadWrite, AccessControlType.Allow));
// Grant Service user instance full control.
pipeSecurity.AddAccessRule(new PipeAccessRule(System.Security.Principal.WindowsIdentity.GetCurrent().User, PipeAccessRights.FullControl, AccessControlType.Allow));
然而,存在另一种漏洞利用的风险,即 DLL 注入。如果将 DLL 注入到我们的客户端进程中,当 DLL 尝试连接到我们的服务命名管道时,DLL 的路径似乎与客户端应用程序的路径相同。这会欺骗服务,并且一些任意命令可以从注入的 DLL(恶意)传递到服务。这可能会允许权限升级。我们如何确保只有我们的客户端应用程序可以与服务通信?
也许这是相关的,我不确定: 从命名管道获取客户端用户令牌
我们应该尝试保护命名管道以避免注入 DLL 与我们的服务通信,还是应该尝试完全使用不同的 IPC,例如服务合同?
尝试提炼以下思路来解决这个问题:
Microsoft 安全和访问权限 (https://learn.microsoft.com/en-us/windows/win32/ipc/named-pipe-security-and-access-rights) 这看起来有点难以理解。我也不确定这是否能真正解决我的问题。
考虑在客户端和服务之间的通信中使用非对称加密。但这种方法的挑战在于,在客户端和服务之间安全地分发公钥和私钥看起来是不可能的。鉴于客户端在未提升的情况下运行,客户端肯定无法将公钥存储在安全位置。因此,攻击者可以轻松修改公钥并提供自己的公钥来欺骗服务。
我的想法是启动一个监控线程,不断扫描正在使用的DLL信息。当扫描检测到不属于白名单的DLL信息时,即可判定为作弊。当然,微软也提供了一些手段来防止未签名的DLL注入。请参考。