0x01 漏洞叙述
WPS Office是适用Microsoft Windows,macOS,Linux,iOS和Android的办公室软件,由总公司坐落于珠海市的中国软件房地产商金山软件公司开发设计。WPS Office由三个关键部件构成:WPS Writer,WPS Presentation和WPS Spreadsheet。本人基本上版本可以免费试用,WPS Office软件中具有一个远程控制实行编码漏洞,是当Office软件在剖析特制Office文档时有误地处置运行内存中的目标时造成的。取得成功利用此漏洞的网络攻击可以在现阶段客户的前后文中运作任何编码。漏洞很有可能会造成拒绝服务攻击,易受攻击的商品WPS Office,危害版本11.2.0.9453。
0x02 漏洞剖析
在WPS Office中用以图像文件格式分析的Qt控制模块中发觉存有堆外溢。置入WPS office的特制位图文件很有可能会触发此漏洞。开启特制的文挡时,触发浏览矛盾。EDX指向二维数组的表针,而EAX是指向二维数组的数据库索引。
0:000>g(c50.b4):Accessviolation-codec0000005(firstchance)Firstchanceexceptionsarereportedbeforeanyexceptionhandling.Thisexceptionmaybeexpectedandhandled.eax=000000c0ebx=006f1c48ecx=cd2aefbcedx=cd2c6f80esi=2ed7ae18edi=0000001ceip=6ba13321esp=006f1b44ebp=006f1b44iopl=0nvupeiplnznapo;nc;cs=0023ss=002bds=002bes=002bfs=0053gs=002befl=00210202QtCore4!QMatrix::dy 0x48a8:6ba133218b448210moveax,dwordptr[edx eax*4 10h]ds:002b:cd2c7290=????????
奔溃是怎样触发的?使我们看一下PNG标头文件格式。
00029E30FF89504E470D0A1A0A0000000D494844ÿ‰PNG........IHD00029E405200000280000001C60403000000160AR...€...Æ.......00029E5027FC0000000467414D410000B1889598'ü....gAMA..±ˆ•˜00029E60F4A600000030504C5445000000800000ô¦...0PLTE...€..00029E7000800080800000008080008000808080.€.€€...€€.€.€€€00029E808080C0C0C0FF000000FF00FFFF000000€€ÀÀÀÿ...ÿ.ÿÿ...00029E90FFFF00FF00FFFFFFFFFF7B1FB1C40000ÿÿ.ÿ.ÿÿÿÿÿ{.±Ä..
从偏移0x29E31逐渐-0x29E34是PNG文件文件格式的签字标头。PNG库函数的构造:
PNGsignature
在这样的情况下,当WPS Office Suite中采用的QtCore库分析PLTE构造并触发堆外溢时,该漏洞坐落于Word文本文档中的内嵌式PNG文件中。在偏移0x29E82到0x29E85处,调色盘的分析不成功,进而触发了堆中的运行内存毁坏。奔溃触发以前的局部变量追踪:
0000ee17906b8143efQtCore4!path_gradient_span_gen::path_gradient_span_gen 0x6a710100ee17f06b814259QtCore4!QBrush::setMatrix 0x2340200ee58d46b8249a4QtCore4!QBrush::setMatrix 0x9e0300ee58ec6b80cc84QtCore4!QImage::rect 0x22b0400ee59086b857cccQtCore4!QTransform::inverted 0xec80500ee629c6b81c55bQtCore4!QSvgFillStyle::setFillOpacity 0x1b590600ee64806b896844QtCore4!QPainter::drawPixmap 0x1c980700ee65746d1e0fbdQtCore4!QPainter::drawImage 0x3250800ee65946d0dd155kso!GdiDrawHoriLineIAlt 0x11a1a
在QtCore4分析内嵌式图象以前,我们可以见到来源于KSO控制模块的最后一次启用,尝试解决图象kso!GdiDrawHoriLineIAlt。应用IDA Pro溶解应用软件来剖析产生异常情况的函数公式。最终的奔溃途径如下所示(WinDBG結果):
QtCore4!QMatrix::dy 0x48a8:6ba133218b448210moveax,dwordptr[edx eax*4 10h]ds:002b:cd2c7290=????????
在IDA Pro中开启时,我们可以按下列方法反编译该函数公式:
.text:67353315pushebp.text:67353316movebp,esp.text:67353318movzxeax,byteptr[ecx edx];crashhere.text:6735331Cmovecx,[ebp arg_0].text:6735331Fmovedx,[ecx].text:67353321moveax,[edx eax*4 10h].text:67353325movecx,eax
应用crashs存贮中的信息内容,我们知道应用软件在0x67353321(mov eax,[edx eax * 4 10h])处开启了浏览矛盾。我们可以见到EAX寄存器由0xc0值操纵。因而,从这儿我们可以依据造成出现异常的指令对寄存器的状况开展一些假定。必须留意的关键一点是,在产生出现异常以前,我们可以见到ECX(0xc0)中包括的值被载入到下列指令所界定的任一部位:
movecx,[ebp arg_0]
除此之外,大家注意到,在人们的常见故障指令以外,EBP的偏移量储存在ECX寄存器中。我们在前边提及的指令(偏移量为0x6ba1331c)上设定了一个断点,以观查运行内存。断点开启后,我们可以见到第一个值c45adfbc偏向另一个指针,该指针应该是指向二维数组的指针。
Breakpoint0hiteax=0000000febx=004f1b40ecx=d3544100edx=0000001cesi=d1200e18edi=0000001ceip=6ba1331cesp=004f1a34ebp=004f1a34iopl=0nvupeiplnznapo;nc;cs=0023ss=002bds=002bes=002bfs=0053gs=002befl=00200202QtCore4!QMatrix::dy 0x48a3:6ba1331c8b4d08movecx,dwordptr[ebp 8]ss:002b:004f1a3c=c45adfbc0:000>dcebp 8004f1a3cc45adfbc00000048000000006f13830f..Z.H..........o004f1a4c004f5cc8000000000000000000000000.\O.............004f1a5c00000000004f65a0004f662c00000000.....eO.,fO.....004f1a6c779eae8e00000000000000013f800000...w...........?004f1a7c3f8000003f31e4f83f8000003f800000...?..1?...?...?004f1a8c3f8000003f31e4f83f8000003de38800...?..1?...?...=004f1a9c3de388003d9e1c8a3c834080004f3c00...=...=.@.<.004f1aac4101c71c6ba133153f8000004081c71c...A.3.k...?...@
从c45adfbc观查运行内存引入,发觉另一个指针。第一个值ab69cf80自始至终表明为偏向它所引入的任何地方的指针。指针ab69cf80大部分是大家指针的数据库索引二维数组。
0:000>dcc45adfbcc45adfbcab69cf80d35441000000000300000280..i..AT.........c45adfcc0000055a00000012c0c0c0c01c3870e2Z............p8.c45adfdc40ad870e1c3870e240ad870e00000000...@.p8....@....c45adfec00000000c0c0c0c16c1d12c000000000...........l....c45adffcc0c0c0c0????????????????????????....????????????c45ae00c????????????????????????????????????????????????c45ae01c????????????????????????????????????????????????c45ae02c????????????????????????????????????????????????0:000>dcab69cf80ab69cf80000000010000001c0000001000000001................//0000001cisoverwrittenintheregisterEDXandEDIbeforewetriggercrashab69cf90ff000000ff800000ff008000ff808000................ab69cfa0ff000080ff800080ff008080ff808080................ab69cfb0ffc0c0c0ffff0000ff00ff00ffffff00................//ffc0c0c0whereitwillbestoredinEAXaftercrash,atthemomentitonlytakes0xfvalueinEAXab69cfc0ff0000ffffff00ffff00ffffffffffff................ab69cfd0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................ab69cfe0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................ab69cff0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................
由于我们知道奔溃的途径,因此可以采用接下来的指令简易地设定一个断点。该指令将得到指针值“ edx eax * 4 10”,并查验其能否符合0xc0。
bp6ba13321".if(poi(edx eax*4 10)==0xc0){}.else{gc}"0:000>geax=000000c0ebx=004f1b40ecx=c45adfbcedx=ab69cf80esi=d1200e18edi=0000001ceip=6ba13321esp=004f1a34ebp=004f1a34iopl=0nvupeiplnznapo;nc;cs=0023ss=002bds=002bes=002bfs=0053gs=002befl=00200202QtCore4!QMatrix::dy 0x48a8:6ba133218b448210moveax,dwordptr[edx eax*4 10h]ds:002b:ab69d290=????????
观查堆栈,可以看到下列实行:
004f1a386ba3cb98QtCore4!path_gradient_span_gen::path_gradient_span_gen 0x6a74004f1a3cc45adfbc004f1a4000000048004f1a4400000000004f1a486f13830fverifier!DphCommitMemoryForPageHeap 0x16f004f1a4c004f5cc8004f1a5000000000004f1a5400000000004f1a5800000000004f1a5c00000000004f1a60004f65a0004f1a64004f662c004f1a6800000000004f1a6c779eae8entdll!RtlAllocateHeap 0x3e
如果我们反汇编6ba3cb98,则可以看到下列反汇编代码,真真正正的系统漏洞根本原因取决于此编码。
6ba3cb898b96b4000000movedx,dwordptr[esi 0B4h]6ba3cb8f8b4df4movecx,dwordptr[ebp-0Ch]6ba3cb9252pushedx6ba3cb938bd7movedx,edi6ba3cb95ff5580calldwordptr[ebp-80h]6ba3cb988b4e7cmovecx,dwordptr[esi 7Ch]Cpseudocodegrad=*(&ptr_grad);if(grad>0.0099999998){input_value=grad_size(check,size,input);ptr_grad=*(input);...cuthere...
我们在6ba3cb89详细地址上设定中断点并观查ESI 0xB4,大家可以看到一个表针偏向另一个部位:
0:000>reax=00000000ebx=00791878ecx=00000005edx=00793938esi=cb07de18edi=0000001ceip=6ba3cb89esp=00791780ebp=00791870iopl=0nvupeiplnznapo;nc;cs=0023ss=002bds=002bes=002bfs=0053gs=002befl=00200202QtCore4!path_gradient_span_gen::path_gradient_span_gen 0x6a65:6ba3cb898b96b4000000movedx,dwordptr[esi 0B4h]ds:002b:cb07decc=cf69afbc0:000>dcesi 0B4hcb07decccf69afbcc0c0c0000000000000000100..i.............cb07dedcc0c0c0c0000000000000000000000000................cb07deec00000000000000000000000000000000................cb07defc00000000cf030fd00000000000000000................cb07df0c00000000000000000000000000000000................cb07df1cc0c0c0c0000000003ff0000000000000...........?....cb07df2c00000000000000000000000000000000................cb07df3c00000000000000003ff0000000000000...........?....0:000>dccf69afbccf69afbcc88baf80d13261000000000300000280.....a2.........cf69afcc0000055f00000012c0c0c0c01c3870e2_............p8.cf69afdc40ad870e1c3870e240ad870e00000000...@.p8....@....cf69afec00000000c0c0c0c16c1d12c000000000...........l....cf69affcc0c0c0c0????????????????????????....????????????cf69b00c????????????????????????????????????????????????cf69b01c????????????????????????????????????????????????cf69b02c????????????????????????????????????????????????0:000>dcc88baf80c88baf80000000010000001c0000001000000001................c88baf90ff000000ff800000ff008000ff808000................c88bafa0ff000080ff800080ff008080ff808080................c88bafb0ffc0c0c0ffff0000ff00ff00ffffff00................c88bafc0ff0000ffffff00ffff00ffffffffffff................c88bafd0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................c88bafe0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................c88baff0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................
从这儿我们可以了解编码事实上沒有从表针释放出来任何东西。一旦挪到EDX,EDX将保存偏向数据库索引二维数组的表针:
eax=00000000ebx=00791878ecx=00000005edx=cf69afbcesi=cb07de18edi=0000001ceip=6ba3cb8fesp=00791780ebp=00791870iopl=0nvupeiplnznapo;nc;cs=0023ss=002bds=002bes=002bfs=0053gs=002befl=00200202QtCore4!path_gradient_span_gen::path_gradient_span_gen 0x6a6b:6ba3cb8f8b4df4movecx,dwordptr[ebp-0Ch]ss:002b:00791864=d13261000:000>dccf69afbccf69afbcc88baf80d13261000000000300000280.....a2.........cf69afcc0000055f00000012c0c0c0c01c3870e2_............p8.cf69afdc40ad870e1c3870e240ad870e00000000...@.p8....@....cf69afec00000000c0c0c0c16c1d12c000000000...........l....cf69affcc0c0c0c0????????????????????????....????????????cf69b00c????????????????????????????????????????????????cf69b01c????????????????????????????????????????????????cf69b02c????????????????????????????????????????????????0:000>dcc88baf80c88baf80000000010000001c0000001000000001................c88baf90ff000000ff800000ff008000ff808000................c88bafa0ff000080ff800080ff008080ff808080................c88bafb0ffc0c0c0ffff0000ff00ff00ffffff00................c88bafc0ff0000ffffff00ffff00ffffffffffff................c88bafd0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................c88bafe0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................c88baff0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0................
奔溃后的局部变量追踪:
0:000>kvL#ChildEBPRetAddrArgstoChild00012f18d46ba3cb98cc53afbc0000004800000000QtCore4!QMatrix::dy 0x48a801012f19d06b8143ef00000000012f1b78012f1a5cQtCore4!path_gradient_span_gen::path_gradient_span_gen 0x6a7402012f1a306b8142590000002e012f5bd000000000QtCore4!QBrush::setMatrix 0x23403012f5b146b8249a40000003b012f5b68cc780e18QtCore4!QBrush::setMatrix 0x9e04012f5b2c6b80cc840000003b012f5b68cc780e18QtCore4!QImage::rect 0x22b05012f5b486b857ccc0000003b012f5b68cc780e18QtCore4!QTransform::inverted 0xec806012f64dc6b81c55b00000000003c000000000000QtCore4!QSvgFillStyle::setFillOpacity 0x1b5907012f66c06b896844012f6724cc818ff00000001cQtCore4!QPainter::drawPixmap 0x1c9808012f67b46d1e0fbd012f69ec012f66d4012f6864QtCore4!QPainter::drawImage 0x32509012f67d46d0dd155012f6a54012f69ec012f6864kso!GdiDrawHoriLineIAlt 0x11a1a0a012f67ec6d0c8d88012f69ec012f68e0012f6864kso!kpt::PainterExt::drawBitmap 0x23
堆分析:
0:000>!heap-p-acc53afbcaddresscc53afbcfoundin_DPH_HEAP_ROOT@6731000inbusyallocation(DPH_HEAP_BLOCK:UserAddrUserSize-VirtAddrVirtSize)cc36323c:cc53afa858-cc53a00020006f13ab70verifier!AVrfDebugPageHeapAllocate 0x0000024077a9909bntdll!RtlDebugAllocateHeap 0x00000039779ebbadntdll!RtlpAllocateHeap 0x000000ed779eb0cfntdll!RtlpAllocateHeapInternal 0x0000022f779eae8entdll!RtlAllocateHeap 0x0000003e6f080269MSVCR100!malloc 0x0000004b6f08233bMSVCR100!operatornew 0x0000001f6b726c67QtCore4!QImageData::create 0x000000fa6b726b54QtCore4!QImage::QImage 0x0000004e6b7a0e21QtCore4!png_get_text 0x000004366b79d7a8QtCore4!QImageIOHandler::setFormat 0x000000de6b79d457QtCore4!QPixmapData::fromFile 0x000002bf6b725eb4QtCore4!QImageReader::read 0x000001e26d0ca585kso!kpt::VariantImage::forceUpdateCacheImage 0x0000254e6d0c5964kso!kpt::Direct2DPaintEngineHelper::operator= 0x000006936d0c70d0kso!kpt::RelativeRect::unclipped 0x000011466d0c8d0ckso!kpt::VariantImage::forceUpdateCacheImage 0x00000cd56d451d5ckso!BlipCacheMgr::BrushCache 0x0000049a6d451e85kso!BlipCacheMgr::GenerateBitmap 0x0000001d6d453227kso!BlipCacheMgr::GenCachedBitmap 0x000000836d29bb92kso!drawing::PictureRenderLayer::render 0x000009b66d450fb1kso!drawing::RenderTargetImpl::paint 0x000000906d29b528kso!drawing::PictureRenderLayer::render 0x0000034c6d2a2d83kso!drawing::VisualRenderer::render 0x000000606d2b8970kso!drawing::SingleVisualRenderer::drawNormal 0x000002b56d2b86a7kso!drawing::SingleVisualRenderer::draw 0x000001e16d2b945ekso!drawing::SingleVisualRenderer::draw 0x000000466d3d0142kso!drawing::ShapeVisual::paintEvent 0x0000044a680a2b5cwpsmain!WpsShapeTreeVisual::getHittestSubVisuals 0x000068f16d0e36dfkso!AbstractVisual::visualEvent 0x000000516d3cbe97kso!drawing::ShapeVisual::visualEvent 0x0000018f6d0eba90kso!VisualPaintEvent::arriveVisual 0x0000004e0:000>dt_DPH_BLOCK_INFORMATIONcc780e18-0x20verifier!_DPH_BLOCK_INFORMATION 0x000StartStamp:0xc0c0c0c0 0x004Heap:0xc0c0c0c0Void 0x008RequestedSize:0xc0c0c0c0 0x00cActualSize:0xc0c0c0c0 0x010Internal:_DPH_BLOCK_INTERNAL_INFORMATION 0x018StackTrace:0xc0c0c0c0Void 0x01cEndStamp:0xc0c0c0c0
段中的最后一个堆条目通常是一个空闲块。堆块的情况标示为空闲块,堆块申明前一个块的尺寸为00108,而现阶段块的尺寸为00a30。前一块汇报其本身尺寸为0x20字节数,不配对。部位为05f61000的堆块的应用好像是该堆块的应用造成下列块的元数据毁坏的可能性。堆块如下所示:
0:000>!heap-a05f60000IndexAddressNameDebuggingoptionsenabled1:05f60000Segmentat05f60000to0605f000(00001000bytescommitted)Flags:00000002ForceFlags:00000000Granularity:8bytesSegmentReserve:00100000SegmentCommit:00002000DeCommitBlockThres:00000200DeCommitTotalThres:00002000TotalFreeSize:00000146Max.AllocationSize:fffdefffLockVariableat:05f60258NextTagIndex:0000MaximumTagIndex:0000TagEntries:00000000PsuedoTagEntries:00000000VirtualAllocList:05f6009cUncommittedranges:05f6008c05f61000:000fe000(1040384bytes)FreeList[00]at05f600c0:05f605b8.05f605b805f605b0:00108.00a30[100]-freeSegment00at05f60000:Flags:00000000Base:05f60000FirstEntry:05f604a8LastEntry:0605f000TotalPages:000000ffTotalUnCommit:000000feLargestUnCommit:00000000UnCommittedRanges:(1)HeapentriesforSegment00inHeap05f60000address:psize.sizeflagsstate(requestedsize)05f60000:00000.004a8[101]-busy(4a7)05f604a8:004a8.00108[101]-busy(107)Internal05f605b0:00108.00a30[100]05f60fe0:00a30.00020[111]-busy(1d)05f61000:000fe000-uncommittedbytes.0:000>dd05f60fe005f60fe0a9b3c8360300708705f6008c05f6008c05f60ff005f6003805f6003805f61000000fe00005f61000????????????????????????????????05f61010????????????????????????????????05f61020????????????????????????????????05f61030????????????????????????????????05f61040????????????????????????????????05f61050????????????????????????????????
0x03 披露时刻表
该系统漏洞于2020年8月汇报,披露时刻表:
- 2020-08-04-将电子邮件发送到公布提供的WPS的各种各样邮件列表(市场销售和适用)。
- 2020-08-10-WPS团队回应当汇报可以转发给她们。
- 2020-08-11-规定进一步的信息内容,例如向适度的方式披露等。
- 2020-08-17-依据此前的规定与WPS团队开展跟进。
- 2020-08-18-根据电子邮箱提供技术报告和定义认证(未数据加密)。
- 2020-08-25-WPS跟进汇报进展。
- 2020-08-26-WPS升级说此问题已转发给开发设计团队。
- 2020-08-28-WPS推送了一封电子邮件,强调该问题已在近期的免费下载版本11.2.0.9403中获得处理。
- 2020-08-28-对于提供的PoC检测了新版本,并确定问题已处理。
- 2020-08-28-向WPS团队寻找资询或变更日志升级。
- 2020-09-03-申请办理系统漏洞CVE。
- 2020-09-14-已分派CVE序号:CVE-2020-25291。
文中翻譯自:http://zeifan.my/security/rce/heap/2020/09/03/wps-rce-heap.html倘若转截,请标明全文详细地址。