聚焦源代码安全,网罗国内外最新资讯!

编译:奇安信代码安全卫士

作者:BORIS LARIN、COSTIN RAIU 和 BRIAN BARTHOLOMEW

本文作者在分析 CVE-2021-1732 的 exploit 时,发现了和 BITTER APT 组织相关的另外一个 0day exploit。2月份作者将新 exploit 告知微软,后者证实确实为 0day 并分配编号 CVE-2021-28310。微软在4月补丁星期二中修复了该漏洞。如下是对作者博客文章的节选编译。

我们认为该 exploit 已遭在野利用,可能已被多个威胁行动者所利用。它是一个提权exploit,很可能会被和其它浏览器 exploit 结合使用逃逸沙箱或获得系统权限以进一步访问系统。遗憾的是,我们无法捕捉到完整的利用链,因此目前不清楚该漏洞是否已被攻击者结合其它浏览器0day或已知已修复漏洞利用。

技术详情

CVE-2021-28310 是位于 dwmcore.dll 中的一个界外写漏洞,dwmcore.dll 是 Desktop Window Manager (dwm.exe) 的一部分。由于缺乏边界检查,攻击者可创建一种情境,使用 DirectComposition API 在受控的偏移处写受控数据。DirectComposition 是一个 Windows 组件,自 Windows 8 起引入,用于启用具有变换、效果和动画的位图合成,并支持不同来源的位图(GDI、DirectX 等)。之前我们曾发布文章分析了关于滥用 DirectComposition API 的在野 0day。DirectComposition API 由 win32kbase.sys 驱动程序实现,所有相关的系统调用名称均以字符串 “NtComposition” 开头。

实施利用仅需三个系统调用:NtDCompositionCreateChannel、 NtDCompositionProcessChannelBatchBuffer 和NtDCompositionCommitChannel。NtDCompositionCommitChannel 系统调用初始化可与 NtDCompositionProcessChannelBatchBuffer 组合利用的信道,以批量模式一次发送多个 DirectComposition 命令,供内核处理。为此,需要在由 NtDCompositionCommitChannel 映射的特殊缓冲区中连续写命令。每个命令都有自己的格式,变量长度和参数清单。

enum DCOMPOSITION_COMMAND_ID
{ProcessCommandBufferIterator,CreateResource,OpenSharedResource,ReleaseResource,GetAnimationTime,CapturePointer,OpenSharedResourceHandle,SetResourceCallbackId,SetResourceIntegerProperty,SetResourceFloatProperty,SetResourceHandleProperty,SetResourceHandleArrayProperty,SetResourceBufferProperty,SetResourceReferenceProperty,SetResourceReferenceArrayProperty,SetResourceAnimationProperty,SetResourceDeletedNotificationTag,AddVisualChild,RedirectMouseToHwnd,SetVisualInputSink,RemoveVisualChild
};

虽然这些命令由内核处理,但同时也被序列化到另外一种格式并由 Local Procedure Call (LPC) 协议传递到 Desktop Window Manager (dwm.exe) 进程以渲染到屏幕。这个程序可由第三个系统调用 NtDCompositionCommitChannel 进行初始化。

为触发该漏洞,所发现的 exploit 使用了三种命令:CreateResource、ReleaseResource 和 SetResourceBufferProperty。

void CreateResourceCmd(int resourceId)
{DWORD *buf = (DWORD *)((PUCHAR)pMappedAddress + BatchLength);*buf = CreateResource;buf[1] = resourceId;buf[2] = PropertySet; // MIL_RESOURCE_TYPEbuf[3] = FALSE;BatchLength += 16;
}void ReleaseResourceCmd(int resourceId)
{DWORD *buf = (DWORD *)((PUCHAR)pMappedAddress + BatchLength);*buf = ReleaseResource;buf[1] = resourceId;BatchLength += 8;
}void SetPropertyCmd(int resourceId, bool update, int propertyId, int storageOffset, int hidword, int lodword)
{DWORD *buf = (DWORD *)((PUCHAR)pMappedAddress + BatchLength);*buf = SetResourceBufferProperty;buf[1] = resourceId;buf[2] = update;buf[3] = 20;buf[4] = propertyId;buf[5] = storageOffset;buf[6] = _D2DVector2; // DCOMPOSITION_EXPRESSION_TYPEbuf[7] = hidword;buf[8] = lodword;BatchLength += 36;
}

我们先来看下 dwmcore.dll 中的CPropertySet::ProcessSetPropertyValue 函数。该函数负责处理 SetResourceBufferProperty 命令。我们对负责处理 DCOMPOSITION_EXPRESSION_TYPE = D2DVector2 的代码最感兴趣。

int CPropertySet::ProcessSetPropertyValue(CPropertySet *this, ...)
{...if (expression_type == _D2DVector2){if (!update){CPropertySet::AddProperty<D2DVector2>(this, propertyId, storageOffset, _D2DVector2, value);}else{if ( storageOffset != this->properties[propertyId]->offset & 0x1FFFFFFF ){goto fail;}CPropertySet::UpdateProperty<D2DVector2>(this, propertyId, _D2DVector2, value);}}...
}int CPropertySet::AddProperty<D2DVector2>(CResource *this, unsigned int propertyId, int storageOffset, int type, _QWORD *value)
{int propertyIdAdded;int result = PropertySetStorage<DynArrayNoZero,PropertySetUserModeAllocator>::AddProperty<D2DVector2>(this->propertiesData,type,value,&propertyIdAdded);if ( result < 0 ){return result;}if ( propertyId != propertyIdAdded || storageOffset != this->properties[propertyId]->offset & 0x1FFFFFFF ){return 0x88980403;}result = CPropertySet::PropertyUpdated<D2DMatrix>(this, propertyId);if ( result < 0 ){return result;}return 0;
}int CPropertySet::UpdateProperty<D2DVector2>(CResource *this, unsigned int propertyId, int type, _QWORD *value)
{if ( this->properties[propertyId]->type == type ){*(_QWORD *)(this->propertiesData + (this->properties[propertyId]->offset & 0x1FFFFFFF)) = *value;int result = CPropertySet::PropertyUpdated<D2DMatrix>(this, propertyId);if ( result < 0 ){return result;}return 0;}else{return 0x80070057;}
}

对于表达式类型被设置为 D2DVector2 的 SetResourceBufferProperty 命令而言,函数 CPropertySet::ProcessSetPropertyValue(…) 要么调用 CPropertySet::AddProperty<D2DVector2>(…),要么调用 CPropertySet::UpdateProperty<D2DVector2>(…),具体取决于更新flag 是否在命令中设置。首先抓住眼球的是新属性被添加到函数CPropertySet::AddProperty<D2DVector2>(…) 中的方式。可以看到,它在资源中新增了新属性,但仅检查增加新属性后,新属性的 propertyId 和 StorageOffset 是否和所提供的值相等,如果不相等则返回错误消息。在工作结束后才进行检查是一种不良的编程实践,可导致漏洞的产生。然而,函数 CPropertySet::UpdateProperty<D2DVector2>(…) 中发生了一个真正的问题。检查不会确保所提供的 propertyId 是否小于添加到资源中的属性的个数。因此,如果攻击者设法绕过了属性数组中对数据的两个额外检查,则攻击者可使用该函数通过 propertiesData 缓冲区执行 OOB 写操作。

(1)  storageOffset == this->properties[propertyId]->offset & 0x1FFFFFFF
(2)  this->properties[propertyId]->type == type

如攻击者能够在 dwm.exe 进程中分配并发布对象,将堆收集为想要的状态并通过虚假属性在具体位置喷射内存,则可绕过这些检查。所发现的 exploit 使用命令 CreateResource、ReleaseResource 和 SetResourceBufferProperty 做到了这一点。

在本文成稿时,我们仍未分析到修复该漏洞的更新二进制,但为了排除该漏洞的其它变体,微软也需要检查其它表达式类型属性的数量。

即使 dwmcore.dll 中出现了上述问题,但如果实现了所想要的内存状态,绕过之前提到的检查,并发布批量命令触发该漏洞,但还鉴于另外一个因素的存在,仍无法触发该漏洞。

如上所述,这些命令首先由内核处理,之后被发送到 Desktop Windows Manager (dwm.exe)。这意味着如果你尝试发送具有不合法 propertyId 的命令,则 NtDCompositionProcessChannelBatchBuffer 系统调用将返回出错消息,而该命令也不会被传递到 dwm.exe 进程。SetResourceBufferProperty 命令的表达式类型被设置为 D2DVector2,在 win32kbase.sys 驱动程序中和函数 DirectComposition::CPropertySetMarshaler::AddProperty<D2DVector2>(…) 以及 DirectComposition::CPropertySetMarshaler::UpdateProperty<D2DVector2>(…) 一起处理,这和 dwmcore.dll 中的函数非常类似(可能是被复制粘贴的)。然而,函数 UpdateProperty<D2DVector2> 的内核版本还存在一个显著差异:它实际上会检查被添加到资源中的属性的数量。

int DirectComposition::CPropertySetMarshaler::UpdateProperty<D2DVector2>(DirectComposition::CPropertySetMarshaler *this, unsigned int *commandParams, _QWORD *value)
{unsigned int propertyId = commandParams[0];unsigned int storageOffset = commandParams[1];unsigned int type = commandParams[2];if ( propertyId >= this->propertiesCount|| storageOffset != this->properties[propertyId]->offset & 0x1FFFFFFF)|| type != this->properties[propertyId]->type ){return 0xC000000D;}else{*(_QWORD *)(this->propertiesData + (this->properties[propertyId]->offset & 0x1FFFFFFF)) = *value;...}return 0;
}

检查 UpdateProperty<D2DVector2> 函数内核模式版本中的 propertiesCount 进一步阻止了用户模式 twin 对恶意命令的处理并缓解了该漏洞,但这正是 DirectComposition::CPropertySetMarshaler::AddProperty<D2DVector2>(…) 发挥作用的地方。AddProperty<D2DVector2> 函数的内核版本运作方式完全和其用户模式变体一致且也应用了同样的行为:在添加后检查属性,且如果所创建属性的 propertyId 和 storageOffset 不匹配所提供的价值后返回错误。鉴于此,有可能使用函数 AddProperty<D2DVector2> 增加一个新属性并强制该函数返回错误并引发分配到内核模式/用户模式的属性数量之间不一致。在内核中的 propertiesCount 检查可通过这种方法被绕过,而恶意命令将被传递到 Desktop Windows Manager (dwm.exe)。

被分配到内核/用户模式中相同资源的属性数量之间的不一致可能造成其它漏洞,因此我们建议微软更改函数 AddProperty 的行为并在添加前首先检查属性。

利用流程总结

所发现exploit 的整个利用流程如下:

1、创建大量资源,特定大小的属性使堆变为可预测状态。

2、通过特定大小和内容的属性创建额外资料,通过虚假属性在特定位置喷射内存。

3、发布在第2阶段创建的资源。

4、创建具有属性的其它资源。这些资源将用于执行 OOB 写操作。

5、在第1阶段创建的资源中制造漏洞。

6、为第4阶段创建的资源创建额外属性。它们的缓冲区会被分配到特定位置。

7、创建“特别”属性,引起在第4阶段所创建资源被分配到内核模式/用户模式中的同样资源的属性数量不一致。

8、使用 OOB 写漏洞写 shellcode,创建对象并执行代码。

9、在另外一个系统进程中注入其它 shellcode。

推荐阅读

Windows “七大奇迹”:DNS Dynamic Updates 中的7个严重漏洞

谷歌发布 Windows 10 图形组件 RCE 漏洞的详情

详述 Discord Desktop app RCE 挖洞经过,最后得$5000 + $300 (含 PoC 视频)

原文链接

https://securelist.com/zero-day-vulnerability-in-desktop-window-manager-cve-2021-28310-used-in-the-wild/101898/

题图:Pixabay License

本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的

产品线。

 觉得不错,就点个 “在看” 或 "赞” 吧~

详细分析已遭利用的 Desktop Window Manager 0day相关推荐

  1. 谷歌再次修复已遭利用的两枚高危0day (CVE-2020-16009/16010)

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 今天,谷歌为 Chrome Web 浏览器发布安全更新,修复了10个安全漏洞,其中包括两个目前已遭利用的高危0day:CVE-2020 ...

  2. 谷歌紧急修复今年已遭利用的第9个0day

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 当地时间上周五,谷歌紧急修复已遭利用的Chrome 高危0day (CVE-2022-4262). 该漏洞是位于V8 JavaScript引擎中 ...

  3. 微软公开PrintNightmare系列第3枚无补丁0day,谷歌修复第8枚已遭利用0day

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 今天,微软发布安全公告,发布了CVSS 评分为7.3.继CVE-2021-1675和CVE-2021-34527之后的第3枚Print S ...

  4. 谷歌修复另一枚已遭利用的 Chrome 释放后使用0day,细节未公开

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 谷歌修复了 Chrome 浏览器中已遭利用的另一枚 0day,成为该公司在一个月内修复的第二枚 0day. 上周五,谷歌发布 Wind ...

  5. 谷歌再修复已遭利用的两个高危 Chrome 0day

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 今天,谷歌发布 Chrome 版本 86.0.4240.198,修复了两个已遭利用的 0day.不过这次并不像之前那样由谷歌内部团队发 ...

  6. 苹果修复三个已遭利用的 iOS 0day

     聚焦源代码安全,网罗国内外最新资讯! 今日,苹果发布安全更新,修复了24个影响 iOS 14.2和 iPadOS 14.2的漏洞,其中包含已修复三个遭在野利用的0day (CVE-2020-2793 ...

  7. 已遭利用的Windows 0day漏洞 CVE-2020-1380分析

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 卡巴斯基发布博客文章,简要分析了微软在8月补丁星期二修复的一个已遭利用 0day CVE-2020-1380.如下内容编译自该文章. ...

  8. 已遭利用的Windows 0day漏洞 CVE-2020-1380 分析

    卡巴斯基发布博客文章,简要分析了微软在8月补丁星期二修复的一个已遭利用 0day CVE-2020-1380.如下内容编译自该文章. 文章指出,2020年5月,卡巴斯基阻止了利用 IE 恶意脚本攻击某 ...

  9. 微软6月补丁日修复7个0day:6个已遭利用且其中1个是为 APT 服务的商用exploit

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 今天,微软发布六月补丁星期二,共修复50个漏洞,其中6个是已遭活跃利用的 Windows 0day,是微软补丁星期二有史以来修复的数量最庞 ...

最新文章

  1. Redis学习笔记 - 数据类型与API(1)Key
  2. 亚马逊云服务(AWS)云原生自研处理器首次落地中国区域!
  3. Spring的使用步骤
  4. 用ESP32玩转真彩屏
  5. openmv串口数据 串口助手_Qt小项目之串口助手控制LED
  6. 一个炒鸡好用的pdf阅读器
  7. JQuery学习记录——DOM的加载
  8. JAVA不同类型数组重载_JAVA补课-DAY1:方法重载和数组
  9. 一个快速排序 和 直接插入排序 的简单 c程序
  10. 全链路数据血缘在满帮的实践
  11. linux免密码登录
  12. s2sh框架搭建mysql_S2SH项目框架搭建(完全注解)
  13. 回溯法求解背包问题java_背包问题回溯法的递归实现(java)
  14. nginx问题一则:nginx路径匹配特殊处理及增加cookie等二三事
  15. 机器人学重点知识点总结
  16. c语言用二维数组学生姓名,C语言实验报告合集-_人人文库网
  17. Node.js使用npm下载第三方模块包步骤
  18. 特殊字符保存到SQL数据库的问题
  19. 大数据平台监控界面和报表
  20. 六级考研单词之路-三

热门文章

  1. Hutool之类型转换类——Convert
  2. Csdn论坛关于一个模板特化不能执行的问题的修改
  3. PHP 文件以及目录操作
  4. PAT A1045 动态规划
  5. JAVA远程通信的几种选择(RPC,Webservice,RMI,JMS的区别)
  6. getCacheDir()和getFilesDir()方法区别
  7. 我的Android进阶之旅------gt;Android中编解码学习笔记
  8. 让 ASP.NET JS验证和服务端的 双验证 更简单
  9. 为什么C# md5 32位加密算法,密码明文会出现31位
  10. 电力三维基础信息平台