CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

admin 2021年4月24日03:13:08评论90 views字数 7378阅读24分35秒阅读模式


CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

0x00前言



       Windows图形组件DWrite库是用于高质量文本呈现的用户模式动态库,DWrite库存在远程代码执行漏洞。目前已有POC,POC可以实现任意地址写任意内容。

基于此我们做了分析,分析后得知字体库文件中的”maxp”表内容存在错误数据时,DWrite库使用此数据计算字体所需内存,导致分配内存过小,程序读取字体库中的数据写入数组并越界写入到另外一个数据结构中,后续将结构中数据作为指针操作其中内容,写入数据和指针都可控。通过分析补丁,补丁修补方案为:取出”maxp”表的另一字段再加4,比较之前畸形数据得到较大值, 以此计算需要分配内存大小。

文章包含如下内容:

定位chrome引擎的渲染进程

使用条件记录断点方法动态调试分析

使用IDA补丁比较静态分析


0x01漏洞信息



  • 漏洞简述

    漏洞名称:(Windows图形组件远程执行代码漏洞)

    漏洞编号:(CVE-2021-24093)

    漏洞类型:(数组越界写)

    漏洞影响:(远程代码执行)

    CVSS评分:(8.8)

    利用难度:不太容易利用

    基础权限:需要用户访问网页

  • 组件概述

    Microsoft DirectWrite是用于高质量文本呈现的现代Windows API。它的大部分代码位于DWrite.dll用户模式库中。它用作各种广泛使用的桌面程序(例如Windows上的chrome,Firefox和Edge)的字体光栅化程序。

  • 漏洞利用

    使用chrome浏览器访问Web页面,渲染引擎进程异常,导致chorme页面崩溃。

  •  漏洞影响

    漏洞主要影响Win10的某些版本及Windows Server 2016、2019、2004、20H2等系统。


0x02漏洞复现



CVE-2021-21087

  • 环境搭建

    漏洞环境: Windows 1909专业版 x64、chrome 86.0.4240.193 (64位)

    poc.html放在本机,漏洞环境也在本机。

  • 复现过程

    将POC文件与poc.ttf放在同一目录下,使用chrome打开poc.html文件。

    CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    页面打开,点击确定按钮加载ttf文件。


    CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    浏览器渲染引擎进程崩溃。

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

        定位进程崩溃地点

       (1) 打开Html页面时会启动多个chrome进程,首先需要定位到哪个是渲染引擎进程。

       (2)先关闭chrome浏览器(否则会影响定位结果),使用火绒剑来定位渲染引擎进程,清空火绒剑记录内容,开启监控,设置动作过滤包括进程启动和进程退出,点击确定,然后开启监控,如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析   

       (3)使用chrome打开poc.html,在弹出框上点击确定,之后渲染引擎崩溃,关闭监控,查看监控到的内容,过滤监控内容,只需要包含chrome.exe的记录,如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

       (4)可以看到最后一个进程退出,进程ID为4228,渲染引擎崩溃,进程应该也会退出,假设最后一个进程是渲染引擎进程,它创建记录是在从上往下数第七个,再试一次,重复(2-3)的过程,这次打开poc.html之后不要点击确定按钮,查看火绒剑记录如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

       定位到第七个进程,进程ID为4948,使用Windbg x64附加此进程,(如果chrome浏览器切换到后台,比如我点击回到桌面,chrome会自动点击确定按钮,导致渲染进程退出,可以先打开windbg,不用切回桌面再打开windbg,或者使用双屏幕也可以。)

       附加成功之后,输入g继续运行,然后回到浏览器中,点击确定按钮,windbg中断,如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

       可以看到引用一个错误的内存地址,发生异常,可知已经定位到正确的渲染进程。


0x03漏洞分析



  • 基本信息

        漏洞文件:DWrite.dll

        漏洞函数:fsg_ExecuteGlyph

        漏洞对象:TrueType字体中的”maxp”表

  • 背景知识

    TrueType字体通常包含在单个TrueType字体文件中,其后缀为.TTF。TrueType中的所有数据都使用big-endian编码,TTF文件中包含了字体的版本号和几个表,每个表都有一个TableEntry结构项,TableEntry结构包含了资源标记、校验和、偏移量和每个表的大小。下面是TrueType字体目录的C语言定义:

    typedef sturct

    {

        char   tag[4];

        ULONG   checkSum;

        ULONG   offset;

        ULONG   length;

    }TableEntry;

    typedef struct

    {

        Fixed   sfntversion;   //0x00010000   for   version   1.0

        USHORT   numTables;

        USHORT   searchRange;

        USHORT   entrySelector;

        USHORT   rangeShift;

        TableEntry  entries[1];//variable  number   of   TableEntry

    }TableDirectory;

    文件开头为TableDirectory结构体,TableDirectory结构的最后一个字段是可变长度的TableEntry结构的数组,每个结构对应一个表。TrueType字体中的每个表都保存了不同的逻辑信息,其中”maxp”表的作用是描述字体中所需内存分配情况的汇总数据,”maxp”表的内容具体结构为:

    typedef struct

    {

        Fixedversion;//0x00010000 for version 1.0

        USHORTnumGlyphs;

        USHORTmaxPoints;//非复合字形中的最大点

        USHORTmaxContours;

        USHORTmaxCompositePoints;//复合字形中的最大点

        USHORTmaxCompositeContours;

        USHORTmaxZones;

        USHORTmaxTwilightPoints;

        USHORTmaxStorage;

        USHORTmaxFunctionDefs;

        USHORTmaxInstructionDefs;

        USHORTmaxStackElements;

        USHORTmaxSizeOfInstructions;

        USHORTmaxComponentElements;// 任何复合字形在“顶级”处引用的最大组件数

        USHORTmaxComponentDepth;

    }

 

  • 详细分析

  •     基础分析

    poc.ttf数据如下:

    

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

       图中箭头1指向的数据为maxp表的TableEntry结构,Offset字段为00000158为箭头2所指向的地方,是”maxp”表内容的具体结构,maxPoints字段值为0(距离箭头2偏移0x6),maxCompositePoints为3(距离箭头2偏移0xA)。

       AE标志符号的<gvar>表条目中的x和y增量在运行时会覆盖到另一个数据结构,TTF中内容如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

       异常触发时指令为add     word ptr [r8+56h],ax,其中ax为 0x9E9F(图中1标记),r8为0x00007A7B00007879(图中2标记)的地址处,78 79 7A 7B都是TTF中的数据,补0是因为在异常指令之前对x数组和y数组调用了memset初始化内存空间。

        poc.html代码如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

       正常情况下,ttf文件中maxPoints字段值为168,maxCompositePoins字段值为2352,在poc.ttf文件中将maxp结构中改为0,将maxCompositePoins值改为3,当加载并光栅化损坏的”maxp”表的数据时,会导致堆分配缓冲区过小,调用栈如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    当复合字形Æ(AE,HTML实体&#198;,U + 00C6)被栅格化时,函数DWrite!fsg_ExecuteGlyph崩溃,调用栈如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

        fsg_ExecuteGlyph函数内部对堆块内部的两个整数数组(对应于x和y坐标)进行操作,使用0x148这个长度调用memset来初始化两个数组,实际数组的长度小于0x148,所以会将跟在数组后面的一个指针置0。

    如果字体是一个变量且指定了轴值,它还将调用TrueTypeRasterizer :: Implementation::ApplyOutlineVariation->GlyphOutlineVariationInterpolator :: ApplyVariation会从TTF中获取数据赋值给数组内的成员,但是数组较小,所以将数组后面的指针置为TTF中的数据。之后会向这个指针指向的地址中写入数据导致异常。

       漏洞库版本如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析



  • 静态分析

崩溃函数fsg_ExecuteGlyph分析

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    在大的堆块中,有两块内存用于存放x数组和y数组,调用memset初始化,调用函数call    cs:off_7FFF41C70D10函数内部会调用DWrite!TrueTypeRasterizer::Implementation::ApplyOutlineVariation给x数组和y数组赋值,addr1指向的内存没有0x148字节那么大,所以会写到其它的数据对象上,接下里会引用被覆盖的数据作为指针去写数据:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    rsi+8中的数据被数组赋值时修改了,使用TTF中的数据覆盖了[rsi+8]的数据,0x00007FFF41B341F6地址处调用的指令add [r8+56],ax,其中ax中的数据也是可以控制的。


  • 函数调用链

计算内存大小的函数调用链为

TrueTypeRasterizer::Implementation::Initialize->fs_NewSfnt ->fsg_WorkSpaceSetOffsets函数fsg_WorkSpaceSetOffsets内部计算需要申请的内存空间大小并将结果传出到fs_NewSfnt中。

fs_NewSfnt获取需要申请的内存大小,之后调用calloc申请内存。

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    可以看到图中调用完成fs_NewSfnt后,在下面的循环中获取v39内存块中的内容作为申请内存的大小。

     fs_NewSfnt函数内容如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    v2为传入的第二个参数a2,*((_DWORD *)v2 + 3)与fs_NewSfnt中取内存大小区域(*(_DWORD *)(v14 + 4i64 * j),j为3时)是一致的。

  • 补丁Diff

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    fsg_WorkSpaceSetOffsets函数补丁前后有修改。

    查看补丁前fsg_WorkSpaceSetOffsets函数伪C代码如下:

    其中参数v3指向”maxp”表具体内容

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    可以看到图中从maxCompositePoints和maxPoints字段中取较大值,并且与常量1比较取较大值,得到值为3,之后加8,得到0xb,作为第一个参数传入fsg_GetOutlineSizeAndOffsets中,这个函数看名称应该是获取轮廓的大小和偏移值。

补丁后fsg_WorkSpaceSetOffsets函数伪C代码有点问题,所以下面贴出汇编代码如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

    打过补丁后,程序是先从maxCompositePoints和maxPoints字段中取较大值,得到3,再与1比较得较大值仍然为3,3+8得到0xb,再取出maxp表中maxComponentElements字段,POC中此值为0062,相对”maxp”表具体内容偏移为0x1C

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

 0x62+4=0x66,比较0x66与0xb得到较大值作为第一个参数传入fsg_GetOutlineSizeAndOffsets函数中。

函数fsg_GetOutlineSizeAndOffsets没有变化,只是因为传入的第一个参数不同,所以最终计算出的结果也不同。

 

  • 漏洞函数分析

fsg_ExecuteGlyph函数对堆块内部的两个整数数组,对应于x坐标和y坐标进行操作,实际上数组的较小,fsg_ExecuteGlyph函数先调用了两次memset将数组清零,如果字体是一个变量且指定了轴值,还会调用TrueTypeRasterizer::Implementation::ApplyOutlineVariation->GlyphOutlineVariationInterpolator::ApplyVariation将字体中的数据赋值到坐标数组,这样就会破坏到后续的结构成员。

 

  • 动态分析

计算所需内存的过程可以通过条件断点的方式来调试,附加到调试器后,设置如下断点命令,

bpDWrite!TrueTypeRasterizer::Implementation::Initialize "r $t0=$t0+1;.printf "Initialize times:%dn",@$t0;.echo;gc"

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

可以看到第13次调用TrueTypeRasterizer::Implementation::Initialize函数之后就会进入崩溃。

重新启动,下断点:

bp DWrite!TrueTypeRasterizer::Implementation::Initialize"r $t0=$t0+1; .printf "Initializetimes:%dn",@$t0;.echo;.if(@$t0 == 0x0D){}.else{gc}"

运行可以看到:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

在调用fs_NewSfnt之前下断点,查看传入参数内容:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

单步步过,再次查看内存,可以看到需要申请的内存大小为6fa4。

继续往下运行:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

可以看到申请的内存地址为0x00000196bc484b60。

在崩溃函数中下断点,运行:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

堆块起始地址为上面的申请的0x00000196bc484b60,调用memset使用的大小为0x148,上面是内存块1,addr1为00000196bc4850fc

查看堆块大小以及addr1相对堆块起始地址的偏移大小如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

最终调用fsg_ExecuteGlyph+772处的指令add    [r8+56h], ax时,a8来源于[rsi+8]

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

查看rsi+8相对于堆块的偏移

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

rsi+8相对于堆块起始地址偏移0x6c8,而addr1相对于堆块起始地址偏移0x59c,0x59c+0x148=0x6E4>0x6C8,所以操作addr1中的数据时会覆盖rsi+8处的数据,从图上可以看到,调用memset后rsi+8中的数据初始化为0。

调用ApplyOutlineVariation函数之后,rsi+8处数据被修改为ttf文件中的数据。(重新启动,内存地址与上面不一样)

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

继续运行,如下:

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

可以看到ax为0x9e9f,r8为0x00007a7b00007879,这两个数据都在poc.ttf文件中的数据,所以这个指针数据可控(where),要写入的内容(what)也可控。

       打过补丁之后查看DWrite!fsg_ExecuteGlyph函数没有变化,调试发现整个堆块的大小变得更大了,X数组和Y数组的大小还是0x148字节,ESI对象距离堆块起始地址的距离变大,所以在X数组和Y数组的赋值过程中没有覆盖到ESI对象,如下:

      

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

       可以看到堆块大小为0x7d24,之前为6fa4。

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

addr1结束地址为0x0000015fd070427c<0x0000015fd0704868,所以数组使用0x148的大小不会覆盖到后面的数据。


0x04总结


TTF文件的”maxp”表描述字体中所需内存分配情况的汇总数据,DWrite库没有校验数据,在ttf中写入畸形数据时,程序申请内存过小,导致溢出到其它的数据结构,实现了任意地址写任意数据。补丁在计算所需内存时读取ttf中另一个值+4,与之前畸形数据比较得较大值,申请足够的内存


0x05解决方案


微软已经更新了官方补丁,下载链接:

https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-24093


0x06参考文献



https://bugs.chromium.org/p/project-zero/issues/detail?id=2123

https://docs.microsoft.com/en-us/typography/opentype/spec/maxp

https://blog.csdn.net/blueangle17/article/details/23750999


0x07支持热线



天融信公司后续将积极为用户提供技术支持,进行持续跟踪并及时通报进展,如有需要请拨打7 x 24小时客服联系电话:400-777-0777。


0x08声明



天融信阿尔法实验室拥有对此公告的修改和解释权,如欲转载,必须保证此公告的完整性。由于传播、利用此公告而造成的任何后果,均由使用者本人负责,天融信阿尔法实验室不为此承担任何责任。

天融信阿尔法实验室成立于2011年,一直以来,阿尔法实验室秉承“攻防一体”的理念,汇聚众多专业技术研究人员,从事攻防技术研究,在安全领域前瞻性技术研究方向上不断前行。作为天融信的安全产品和服务支撑团队,阿尔法实验室精湛的专业技术水平、丰富的排异经验,为天融信产品的研发和升级、承担国家重大安全项目和客户服务提供强有力的技术支撑。

CVE-2021-24093 Windows图形组件远程执行代码漏洞分析
CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

天融信

阿尔法实验室

长按二维码关注我们


本文始发于微信公众号(天融信阿尔法实验室):CVE-2021-24093 Windows图形组件远程执行代码漏洞分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年4月24日03:13:08
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2021-24093 Windows图形组件远程执行代码漏洞分析http://cn-sec.com/archives/300080.html

发表评论

匿名网友 填写信息