Recon Montreal 2018上我与Alex Ionescu一起展示了"未知已知的dll和其他违反代码完整性信任的行为"。我们描述了Microsoft Windows的代码完整性机制的实现以及Microsoft如何实现受保护的进程(PP)。作为其中一部分,我演示了各种绕过Protected Process Light (PPL)的方法,有些需要管理员权限,有些不需要。

在此博文中,我将描述我在Windows 10 1803上发现一种将代码注入PPL的方法的过程。由于微软认为唯一违反了防御安全边界的问题现在已经修复,因此我可以更详细地讨论这个漏洞。

Windows保护进程的背景

Windows Protected Process (PP)模型的起源可以追溯到Vista,在Vista中引入了它来保护DRM进程。受保护的进程模型受到严格限制,将加载的dll限制为操作系统安装的代码子集。此外,要使可执行文件被认为具有启动保护资格,它必须使用嵌入在二进制文件中的特定Microsoft证书进行签名。没有受保护的进程无法打开具有足够权限注入任意代码或读取内存的受保护进程的句柄,是内核强制执行的一项保护措施。

在Windows 8.1中引入了一种新的机制,即Protected Process Light (PPL),使得保护更加普遍。PPL放宽了某些限制,即哪些dll对于加载受保护的进程有效,并为主要的可执行文件引入了不同的签名要求。另一个重大变化是引入了一组签名级别,以区分不同类型的受保护进程。一个级别的PPL可以在相同或更低的签名级别上开放任何进程的完全访问权限,并将有限的访问权限授予更高级别。这些签名级别被扩展到旧的PP模型中,一个级别的PP可以在相同或更低的签名级别上打开所有的PP和PPL,但是反过来不是这样的,PPL不能在任何签名级别上以完全访问的方式打开PP。以下是一些层次及关系图:

签名级别允许微软向第三方开放受保护的进程,尽管目前第三方可以创建的唯一受保护进程类型是Anti-Malware PPL。Anti-Malware 级别是特殊的,因为它允许第三方通过注册 Early Launch Anti-Malware (ELAM)证书添加额外的允许签名密钥。还有微软的TruePlay,这是一种反欺诈的技术,它使用了PPL的组件,但对于这个讨论来说并不重要。

我可以花很多时间来描述PP和PPL在幕后是如何工作的,但是我建议阅读Alex Ionescu的博客系列文章(第123部分),这会做得更好。虽然博客文章主要基于Windows 8.1,但大多数概念在Windows 10中并没有发生实质性的变化。

我在之前以Oracle在Windows上的VirtualBox虚拟化平台上的自定义实现的形式写过关于保护进程的文章link,。博客展示了我如何使用多种不同的技术绕过进程保护。当时我没有提到的是我所描述的第一种技术,将JScript代码注入到这个过程中,这也与微软的PPL实现背道而驰。正如我报告中所说,我可以将任意的代码注入到PPL到Microsoft(见issue 1336),这是出于对微软想要慎重的修复这个问题。在这种情况下,微软决定它不会作为一个安全公告被修复。然而,在Windows下一个主要版本(1803版)中,微软通过向CI添加以下代码修复了这个问题。DLL,内核的完整代码库:

UNICODE_STRING g_BlockedDllsForPPL[] = {
 DECLARE_USTR("scrobj.dll"),
 DECLARE_USTR("scrrun.dll"),
 DECLARE_USTR("jscript.dll"),
 DECLARE_USTR("jscript9.dll"),
 DECLARE_USTR("vbscript.dll")
};

NTSTATUS CipMitigatePPLBypassThroughInterpreters(PEPROCESS Process, 
                                                LPBYTE Image, 
                                                SIZE_T ImageSize) {
 if (!PsIsProtectedProcess(Process))
   return STATUS_SUCCESS;

 UNICODE_STRING OriginalImageName;
 // Get the original filename from the image resources.
 SIPolicyGetOriginalFilenameAndVersionFromImageBase(
     Image, ImageSize, &OriginalImageName);
 for(int i = 0; i < _countof(g_BlockedDllsForPPL); ++i) {
   if (RtlEqualUnicodeString(g_BlockedDllsForPPL[i], 
                             &OriginalImageName, TRUE)) {
     return STATUS_DYNAMIC_CODE_BLOCKED;
   }
 }
 return STATUS_SUCCESS;
}

该修复程序将根据一个包含5个dll的黑名单检查部分正在加载的图像的资源的原始文件名。DLLs黑名单包括了诸如实现了原始的JScript脚本引擎的JSCRIPT.dll,和实现了scriptlet对象的SCROBJ.DLL。如果内核检测到PP或PPL加载了这些dll中的一个,那么使用STATUS_DYNAMIC_CODE_BLOCKED拒绝加载图像。如果您修改其中一个列出的dll的资源部分,则图像签名将失效,从而导致由于密码散列不匹配而导致图像加载失败。实际上,这与Oracle在VirtualBox中用来阻止攻击的修复方法是相同的,尽管它是在用户模式中实现的。

寻找新的目标

前面使用脚本代码的注入技术是一种通用技术,适用于任何加载COM对象的PPL。技术修复后,我决定回过头来看看作为PPL可以加载哪些可执行程序,看看它们是否有任何明显的漏洞,我可以利用这些漏洞来获得任意的代码执行。我本可以选择去追求一个完整的PP,但是PPL似乎是两者中比较容易的,我必须从某个地方开始。如果我们能够获得管理员权限,那么注入PPL的方法有很多,其中最简单的方法就是加载内核驱动程序。由于这个原因,我发现的任何漏洞都必须从一个正常的用户帐户运行。我还想获得最高的签名级别,那意味着PPL在Windows TCB签名级别。

第一步是识别作为受保护进程运行的可执行程序,这给了我们分析漏洞的最大攻击面。根据Alex的博客文章,似乎为了加载为PP或PPL,签名证书需要在证书的增强密钥使用(EKU)扩展中有一个特殊的对象标识符(OID)。PP和PPL有单独的OID;我们可以在下面的WERFAULTSECURE.exe的比较中看到这一点,可以运行为PP/PPL和CSRSS.EXE,只能作为PPL运行。

我决定寻找嵌入了EKU OIDs签名的可执行文件,这样我就能得到所有可执行文件的列表,以寻找可利用的行为.我为我的NtObjectManager PowerShell 模块编写了Get-EmbeddedAuthenticodeSignature cmdlet来提取这些信息。

此时,我意识到依赖签名证书的方法存在一个问题,我希望能够以PP或PPL的形式运行许多二进制文件,但是我生成的列表中没有这些文件。由于PP最初是为DRM设计的,所以没有明显的可执行文件来处理受保护的媒体路径,比如AUDIODG.EXE。同时,根据我之前的研究设备保护和Windows 10系列,我知道必须有一个可执行的运行在.net框架可以作为PPL添加缓存签署NGEN水平信息生成的二进制文件(NGEN是一个将net汇编转换为本机代码的提前JIT)。PP/PPL的标准比我预期的更流畅。我不再做静态分析,而是决定执行动态分析,于是开始保护我可以列举和查询的每个可执行文件。我编写了下面的脚本来测试单个可执行文件:

Import-Module NtObjectManager

function Test-ProtectedProcess {
   [CmdletBinding()]
   param(
       [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
       [string]$FullName,
       [NtApiDotNet.PsProtectedType]$ProtectedType = 0,
       [NtApiDotNet.PsProtectedSigner]$ProtectedSigner = 0
       )
   BEGIN {
       $config = New-NtProcessConfig abc -ProcessFlags ProtectedProcess `
           -ThreadFlags Suspended -TerminateOnDispose `
           -ProtectedType $ProtectedType `
           -ProtectedSigner $ProtectedSigner
   }

   PROCESS {
       $path = Get-NtFilePath $FullName
       Write-Host $path
       try {
           Use-NtObject($p = New-NtProcess $path -Config $config) {
               $prot = $p.Process.Protection
               $props = @{
                   Path=$path;
                   Type=$prot.Type;
                   Signer=$prot.Signer;
                   Level=$prot.Level.ToString("X");
               }
               $obj = New-Object –TypeName PSObject –Prop $props
               Write-Output $obj
           }
       } catch {
       }
   }
}

当执行此脚本时,将定义一个函数Test-ProtectedProcess。该函数获取一个可执行文件的路径,以指定的保护级别启动该可执行文件,并检查它是否成功。如果ProtectedType和ProtectedSigner参数为0,那么内核将决定“最佳”进程级别。这导致了一些恼人的问题,例如SVCHOST.EXE显式地标记为PPL,并将在PPL- windows级别上运行,但是由于它也是一个有符号的OS组件,内核将确定其最大级别为PP-Authenticode。另一个有趣的问题是使用本机进程创建api,可以将DLL作为主要可执行映像启动。由于大量的系统dll都嵌入了微软的签名,它们也可以作为PP-Authenticode启动,尽管这并不一定有用。将在PPL上运行的二进制文件列表和它们的最大签名级别如下所示:

将任意代码注入NGEN

在仔细检查了以PPL我确定的方式运行的可执行程序列表之后
试图攻击前面提到的 .net NGEN二进制文件,MSCORSVW.EXE。我选择NGEN二进制的理由是:

但是NGEN二进制有一个问题,特别是它不符合我得到最高签名级别的标准-Windows TCB。然而,我知道,当微软修复了1332号问题时,他们留下了一个后门,如果调用过程是PPL,在签名过程中可以维护一个可写句柄,如下所示:

NTSTATUS CiSetFileCache(HANDLE Handle, ...) {

 PFILE_OBJECT FileObject;
 ObReferenceObjectByHandle(Handle, &FileObject);

 if (FileObject->SharedWrite ||
    (FileObject->WriteAccess && 
     PsGetProcessProtection().Type != PROTECTED_LIGHT)) {
   return STATUS_SHARING_VIOLATION;
 }

 // Continue setting file cache.
}

如果我能在NGEN二进制文件中执行代码,我就可以重用这个后门来缓存一个可以加载到任何PPL的任意文件。然后我可以劫持一个完整的PPL-WindowsTCB进程来达到我的目标

为了开始这个调查,我们需要确定如何使用MSCORSVW可执行文件。微软在任何地方都没有记录使用MSCORSVW,所以我们需要做一些挖掘。首先,这个二进制文件不应该直接运行,而是在创建一个NGEN'ed二进制文件时由NGEN调用。因此,我们可以运行NGEN二进制文件,并使用进程监视器等工具来捕获MSCORSVW进程使用的命令行。执行命令:

C:\> NGEN install c:\some\binary.dll

执行以下命令行的结果:

MSCORSVW -StartupEvent A -InterruptEvent B -NGENProcess C -Pipe D

A、B、C和D是NGEN确保在新进程启动之前继承到新进程的句柄。由于我们没有看到任何原始的NGEN命令行参数,它们似乎是通过IPC机制传递的。“Pipe”参数表示指定的管道用于IPC。深入研究MSCORSVW中的代码,我们发现方法ngenworkerembed,如下所示

void NGenWorkerEmbedding(HANDLE hPipe) {
 CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
 CorSvcBindToWorkerClassFactory factory;

 // Marshal class factory.
 IStream* pStm;
 CreateStreamOnHGlobal(nullptr, TRUE, &pStm);
 CoMarshalInterface(pStm, &IID_IClassFactory, &factory,
                    MSHCTX_LOCAL, nullptr, MSHLFLAGS_NORMAL);

 // Read marshaled object and write to pipe.
 DWORD length;
 char* buffer = ReadEntireIStream(pStm, &length);
 WriteFile(hPipe, &length, sizeof(length));
 WriteFile(hPipe, buffer, length);
 CloseHandle(hPipe);

 // Set event to synchronize with parent.
 SetEvent(hStartupEvent);

 // Pump message loop to handle COM calls.
 MessageLoop();

 // ...
}

这段代码并不完全符合我的预期。它不为整个通信通道使用命名管道,而是仅用于将编组的COM对象传输回调用进程。COM对象是一个实体类,通常您会使用CoRegisterClassObject注册实体,但这将使它在同一安全级别上对所有进程都可访问,因此,通过使用封送处理的连接只能保留为私有,只有产生MSCORSVW的NGEN二进制文件才是私有的。一个使用COM的.net相关的过程让我很感兴趣,正如我之前在另一篇博客文章中描述的那样,你可以利用.net中实现的COM对象。如果幸运的话,这个COM对象是在.net中实现的,我们可以通过查询它的接口来确定它是否在.net中实现,例如我们在我的OleViewDotNet PowerShell模块中使用Get-ComInterface命令,如下面的截图所示:

不幸的是,这个对象没有在.net中实现,因为您至少会看到_Object接口的一个实例。只有一个ICorSvcBindToWorker接口实现了,让我们深入到这个接口,看看有没有什么可以利用的。

有些东西引起了我的注意,在屏幕截图中有一个HasTypeLib列,对于ICorSvcBindToWorker,我们看到这个列设置为True。HasTypeLib表明,接口的代理代码不是使用预定义的NDR字节流来实现的,它是从类型库中动态生成的。我曾经滥用这个自动生成代理机制来提升到system权限,报告为问题1112。在这个问题中,我使用了系统的运行对象表(ROT)的一些有趣行为来强制系统COM服务中的类型混淆。虽然微软已经解决了用户到系统的问题,但是没有什么可以阻止我们使用类型混淆的技巧来利用MSCORSVW进程以PPL的身份在相同的权限级别上运行并获得任意代码执行。使用类型库的另一个优点是,一个普通的代理将作为DLL加载,这意味着它必须满足PPL签名级别的要求;然而,类型库只是数据,因此可以加载到PPL中,而不存在任何签名级别冲突。

类型混淆是如何工作的?从类型库查看ICorSvcBindToWorker接口:

interface ICorSvcBindToWorker : IUnknown {
   HRESULT BindToRuntimeWorker(
             [in] BSTR pRuntimeVersion, 
             [in] unsigned long ParentProcessID, 
             [in] BSTR pInterruptEventName, 
             [in] ICorSvcLogger* pCorSvcLogger, 
             [out] ICorSvcWorker** pCorSvcWorker);
};

单个BindToRuntimeWorker接受5个参数,4个导入,1个导出。当试图从我们不可信的进程通过DCOM访问方法时,系统将自动为调用生成代理和存根。这将包括将COM接口参数编组到缓冲区,将缓冲区发送到远程进程,然后在调用实函数之前将编组解到指针。例如,假设有一个简单的函数,DoSomething只需要一个IUnknown指针。编组过程如下所示:

方法调用的操作如下:

这些排列操作改变如下:

通过将参数的类型从接口指针更改为整数,我们导致了类型混淆,这允许我们得到任意指针解除引用,从而导致任意代码执行。我们甚至可以通过向类型库添加以下结构来简化攻击:

struct FakeObject {
   BSTR FakeVTable;
};

如果我们传递一个指向FakeObject的指针而不是接口指针,自动生成的代理将封送结构和它的BSTR,在存根的另一边重新创建它。由于BSTR是一个已计数的字符串,它可以包含空值,因此这将创建一个指向对象的指针,该对象包含一个指向可充当VTable的任意字节数组的指针。在BSTR中放置已知的函数指针,您就可以轻松地重定向执行,而无需猜测合适的VTable缓冲区的位置

为了充分利用这一点,我们需要调用一个合适的方法,可能运行一个ROP链,我们可能还需要绕过CFG。所有这些听起来都很辛苦,所以我将采用另一种方法,通过滥用 KnownDlls来让任意代码在PPL二进制文件中运行。

KnownDlls 和 受保护的进程

在我的前一篇博客文章中,我描述了一种将权限从任意对象目录创建漏洞提升到系统的技术,方法是向KnownDlls目录中添加一个条目,并将任意DLL加载到特权进程中。我注意到,这也是PPL代码注入的管理员,因为PPL还将从系统的KnownDlls位置加载dll。由于代码签名检查是在段创建期间执行的,而不是段映射,只要您可以将一个条目放入KnownDlls中,您就可以将任何内容加载到PPL,甚至是无符号代码中

这看起来并不是很有用,如果不是管理员,我们就不能给KnownDlls写入信息,即使没有一些聪明的技巧也不行。然而,值得一看的是如何加载一个已知的DLL,以了解如何可以滥用它。在NTDLL的加载器(LDR)代码中有以下函数来确定是否存在一个预先存在的已知DLL:

NTSTATUS LdrpFindKnownDll(PUNICODE_STRING DllName, HANDLE *SectionHandle) {
 // If KnownDll directory handle not open then return error.
 if (!LdrpKnownDllDirectoryHandle)
   return STATUS_DLL_NOT_FOUND;

 OBJECT_ATTRIBUTES ObjectAttributes;
 InitializeObjectAttributes(&ObjectAttributes, 
   &DllName,
   OBJ_CASE_INSENSITIVE,
   LdrpKnownDllDirectoryHandle,
   nullptr);

 return NtOpenSection(SectionHandle, 
                      SECTION_ALL_ACCESS, 
                      &ObjectAttributes);
}

LdrpFindKnownDll函数调用NtOpenSection来为已知的DLL打开指定的section对象。它没有打开绝对路径,而是使用本机系统调用的特性为OBJECT_ATTRIBUTES结构中的对象名称查找指定一个根目录。这个根目录来自全局变量LdrpKnownDllDirectoryHandle。以这种方式实现调用允许加载器只指定文件名(例如EXAMPLE.DLL),而不必像查找与现有目录相关的内容那样重新构造绝对路径。跟踪LdrpKnownDllDirectoryHandle的引用,我们可以发现它在LdrpInitializeProcess中初始化,如下所示

NTSTATUS LdrpInitializeProcess() {
 // ...
 PPEB peb = // ...
 // If a full protected process don't use KnownDlls.
 if (peb->IsProtectedProcess && !peb->IsProtectedProcessLight) {
   LdrpKnownDllDirectoryHandle = nullptr;
 } else {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING DirName;
   RtlInitUnicodeString(&DirName, L"\\KnownDlls");
   InitializeObjectAttributes(&ObjectAttributes, 
                              &DirName,
                              OBJ_CASE_INSENSITIVE,
                              nullptr, nullptr);
   // Open KnownDlls directory.
   NtOpenDirectoryObject(&LdrpKnownDllDirectoryHandle, 
                         DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 
                         &ObjectAttributes);
}

这段代码不应该那么出人意料,实现调用NtOpenDirectoryObject,将KnownDlls目录的绝对路径作为对象名传递。打开的句柄存储在LdrpKnownDllDirectoryHandle全局变量中,供以后使用。值得注意的是,这段代码检查PEB,以确定当前进程是否为完全受保护的进程。在完全受保护的过程模式下,对加载已知dll的支持是禁用的,这就是为什么即使有管理员权限和我在上一篇博客文章中介绍的聪明技巧,我们也只能损害PPL,而不能损害PP。

这些知识对我们有什么帮助?我们可以使用我们的COM类型混淆技巧将值写入任意内存位置,而不是试图劫持代码执行,从而只对数据进行攻击。因为我们可以将任何我们喜欢的句柄继承到新的PPL进程中,所以我们可以设置一个带有命名节的对象目录,然后使用类型混淆将LdrpKnownDllDirectoryHandle的值更改为继承句柄的值。如果我们从System32引入一个已知名称的DLL负载,那么LDR将检查我们的伪目录中的指定部分,并将未签名代码映射到内存中,甚至为我们调用DllMain。不需要注入线程,ROP或绕过CFG。

我们只需要一个合适的数据类型来编写任意值,不幸的是,虽然我可以找到导致任意写入的方法,但我无法充分控制正在写入的值。最后,我使用了ICorSvcBindToWorker::BindToRuntimeWorker返回的对象上实现的接口和方法

interface ICorSvcPooledWorker : IUnknown {
   HRESULT CanReuseProcess(
           [in] OptimizationScenario scenario, 
           [in] ICorSvcLogger* pCorSvcLogger, 
           [out] long* pCanContinue);
};

在CanReuseProcess中,pCanContinue的目标值总是初始化为0。因此,通过将类型库定义中的[out] long替换为[in] long,我们可以将0写入到指定的任何内存位置。通过prefilling低16位新流程的处理与处理假KnownDlls目录表我们可以肯定真实之间的一个别名KnownDlls将打开过程一旦开始,我们只需修改前16位的处理为0。如下图所示:

一旦我们用0覆盖了前16位(写是32位,但是句柄在64位模式下是64位,所以我们不会覆盖任何重要的东西)LdrpKnownDllDirectoryHandle现在指向我们的一个KnownDlls 句柄。然后,我们可以通过将自定义封送对象发送到相同的方法来轻松地诱导DLL负载,我们将在PPL中得到任意的代码执行

提升到PPL-Windows TCB

我们不能就此打住,攻击MSCORSVW只会让我们获得CodeGen签名级别的PPL,而不是Windows TCB。我知道生成一个假的缓存签名DLL应该在PPL中运行,并且微软在任何签名级别为PPL进程留下后门,我把我的c#代码从1332号问题转换成c++来生成一个假的缓存签名DLL。通过滥用DLL劫持在WERFAULTSECURE.EXE将作为PPL Windows TCB运行,我们应该在期望的签名级别执行代码。这适用于Windows 10 1709和更早的版本,但在1803年就不适用了。显然,微软已经在某种程度上改变了缓存签名级别的行为,也许他们已经完全放弃了对PPL的信任。这似乎不太可能,因为这会对性能产生负面影响。

在与Alex Ionescu讨论了这一点之后,我决定将一个快速解析器与Alex提供的关于文件缓存签名数据的信息放在一起。这在NtObjectManager中被公开为Get-NtCachedSigningLevel命令。我对一个假的有符号二进制文件和一个系统二进制文件运行了这个命令,这个系统二进制文件也缓存了有符号的二进制文件,并且立即发现了不同之处:

对于伪签名文件,标志被设置为TrustedSignature (0x02),但是对于系统二进制PowerShell无法解码枚举,因此只能输出十六进制中的整数值66 (0x42)。值0x40是在原始可信签名标志之上的额外标志。看起来,如果没有设置这个标志,DLL就不会被加载到PPL进程中。一定有什么东西设置了这个标志,所以我决定检查如果我加载了一个有效的缓存签名DLL而没有额外的标志到PPL进程中会发生什么。我通过监控Process Monitor得到了答案

进程监视器跟踪显示,内核首先从DLL查询扩展属性(EA)。缓存的签名级别数据存储在文件的EA中,因此这几乎肯定是缓存的签名级别被读取的指示。在检查完整签名的完整跟踪工件(如列举目录文件)中,为了简洁起见,我从屏幕快照中删除了这些工件。最后设置EA,如果我检查文件的缓存签名级别,它现在包含额外的标志。设置缓存的签名级别是自动完成的,问题是如何设置?通过提取堆栈跟踪,我们可以看到它是如何发生的

查看堆栈跟踪的中间部分,我们可以看到对CipSetFileCache的调用源自对NtCreateSection的调用。当这样做有意义时,内核会自动缓存签名,例如在PPL中,这样后续的图像映射就不需要重新检查签名。可以从具有写访问权限的文件中映射图像部分,这样我们就可以重用第1332号问题中的相同攻击,并用NtCreateSection替换对NtSetCachedSigningLevel的调用,并且可以伪造任何DLL的签名。事实证明,设置文件缓存的调用是在引入写检查来修复1332问题之后发生的,因此可以使用它再次绕过设备保护。基于这个原因,我将旁路报告为问题1597,该问题在2018年9月被修正为CVE-2018-8449。然而,与第1332号问题一样,PPL的后门仍然存在,因此即使修复消除了设备保护旁路,它仍然可以用来让我们从PPL- codegen到PPL- Windows TCB

结论

这个博客展示了我如何能够在不需要管理员权限的情况下将任意代码注入PPL。你能用这种新发现的力量做什么?作为一个普通用户,这并不是什么大问题,但是操作系统中有一些部分,比如Windows Store,它依赖于PPL软件来保护文件和资源,而这些文件和资源是普通用户无法修改的。如果你升级到管理员,然后注入到一个PPL,你会得到更多的东西来攻击,比如CSRSS(通过它你当然可以得到内核代码执行)或者攻击Windows防御程序,运行PPL反恶意软件。随着时间的推移,我确信大多数PPL的用例将被虚拟安全模式(VSM)和独立用户模式(IUM)应用程序所取代,这些应用程序具有更大的安全保证,而且也被认为是安全边界,微软将对此进行维护和修复。

我是否向微软报告了这些问题?微软已经明确表示,他们不会在安全公告中只修复影响PP和PPL的问题。如果没有安全公告,研究人员就不会收到对该发现的确认,比如CVE。这个问题不会在Windows的当前版本中修复,尽管它可能在下一个主要版本中修复。之前确认微软解决一个特定安全问题上的政策是基于先例,不过他们最近出版的Windows技术将列表或不会固定在Windows安全服务标准,为保护过程如下所示,微软不会修复或支付相关问题特性赏金。因此,从现在开始,如果我发现了一些我认为只会影响PP或PPL的问题,我将不再与微软合作

我向微软报告的一个错误只是修复了,因为它可以用来绕过设备保护。当你思考这个问题的时候,只修复设备保护有点奇怪。我仍然可以通过注入PPL和设置缓存的签名级别来绕过Device Guard,但是微软不会修复PPL问题,但会修复Device Guard问题。尽管Windows安全服务标准文档确实有助于澄清微软会修复什么,不会修复什么,但它仍然有些武断。安全特性很少是孤立的安全特性,几乎可以肯定的是该特性是安全的,因为其他特性使其如此。

在本博客的第2部分中,我们将讨论我如何能够使用COM的另一个有趣的特性来分解完整的PP-WindowsTCB进程

本文翻译自: https://googleprojectzero.blogspot.com/2018/10/injecting-code-into-windows-protected.html

源链接

Hacking more

...