CVE-2021-21958
A heap-based buffer overflow vulnerability exists in the Hword HwordApp.dll functionality of Hancom Office 2020 11.0.0.2353. A specially-crafted malformed file can lead to memory corruption and potential arbitrary code execution. An attacker can provide a malicious file to trigger this vulnerability.
Hancom Office 2020 11.0.0.2353
Hancom Office 2020 - https://office.hancom.com/
7.8 - CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-122 - Heap-based Buffer Overflow
Hancom Office is considered one of the more popular Office suites used within South Korea.
To be able to reproduce the vulnerability, we need to turn on PageHeap for Hword.exe app and open our malicious file.
The debugger stops with the following information
(1294.1198): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Time Travel Position: 26E63B2:0
eax=7f169054 ebx=00000053 ecx=00000014 edx=00000053 esi=7f169040 edi=7f167000
eip=69c9f26d esp=011cd768 ebp=011cd788 iopl=0 nv up ei ng nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00200287
MSVCR120!memcpy+0x2a:
69c9f26d f3a4 rep movs byte ptr es:[edi],byte ptr [esi]
As we can see a heap-based buffer overflow occured. Let’s go back to a few functions before :
Line 1 struct_this *__thiscall read_CFB_directory_entry_data(struct_this *this, int a2, unsigned int stream_size, int StartSecLoc)
Line 2 {
Line 3 unsigned int vector_size; // edi
Line 4 void *dstBuffer; // eax
Line 5 unsigned __int16 sectorSize; // [esp-18h] [ebp-38h]
Line 6 int size_to_read; // [esp-14h] [ebp-34h]
Line 7
Line 8 sub_10BBE230(this, (_WORD *)a2, stream_size);
Line 9 this->vftable0 = &tfo_olefs::OleEntryMiniInputStream::`vftable';
Line 10 this->vftable8 = &tfo_olefs::OleEntryMiniInputStream::`vftable';
Line 11 vector_size = (stream_size >> 6) + 1;
Line 12 if ( (this->currentEnd - this->secStartPtr) >> 2 < vector_size )
Line 13 {
Line 14 if ( vector_size > 0x3FFFFFFF )
Line 15 std::_Xlength_error("vector<T> too long");
Line 16 vector_resize((struct_this_1 *)&this->secStartPtr, vector_size);
Line 17 }
Line 18 if ( get_mini_fat_sectors(this->gapC, &this->secStartPtr, StartSecLoc) )
Line 19 {
Line 20 sub_10B7CE20(*(_DWORD **)this->gapC, (char **)&this[1]);
Line 21 if ( (unsigned int)((this->secEndPtr - this->secStartPtr) >> 2) <= 1 )
Line 22 size_to_read = this->stream_size;
Line 23 else
Line 24 size_to_read = 0x40;
Line 25
Line 26 dstBuffer = operator new[](
Line 27 0x40u,
Line 28 1,
Line 29 "..\\..\\Common\\Engine\\TfoCore\\tfo_olefs\\tfo_olefs\\OleEntryMiniInputStream.cpp",
Line 30 29);
Line 32 this->dstBuffer = dstBuffer;
Line 33 this->word24 = 0;
Line 34 sectorSize = this->sectorSize;
Line 35 this->dword18 = 0;
Line 36 fread_wrapper(this->dword10, (int)dstBuffer, &this[1].vftable0, StartSecLoc, sectorSize, size_to_read);
Line 37 this->byte4 = 1;
Line 38 }
Line 39 else
Line 40 {
Line 41 this->byte4 = 0;
Line 42 }
Line 43 return this;
Line 44 }
The heap overflow occured after a call to fread_wrapper
in line 36
where the size of the bytes to read is controled by the variable size_to_read
.
The dstBuffer
will always have a constant size equal to 0x40
bytes (line 26
).
Further analysis revealed that the structure being parsed here is Compound File Directory Entry
[https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/60fe8611-66c3-496b-b70d-a504c94c9ace] (OLESSDirectoryEntry) located at offset : 0x18180
1:8180h: 01 00 43 00 6F 00 6D 00 70 00 4F 00 62 00 6A 00 ..C.o.m.p.O.b.j.
1:8190h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1:81A0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1:81B0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1:81C0h: 12 00 02 00 20 00 00 00 21 00 00 00 FF FF FF FF .... ...!...ÿÿÿÿ
1:81D0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1:81E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1:81F0h: 00 00 00 E4 F2 00 00 00 54 00 00 00 00 00 00 00 ...äò...T.......
The size_to_read
value was assigned at line 22
. It equals 0x54, which corresponds to Stream Size
located at offset : 1:81F8h
.
But why was line 22
executed instead of line 24
? It turned out that at the beginning, right after the call to vector_resize
(line 16
) both
this->secEndPtr
and this->secStartPtr
point to the same memory space address.
Later, inside get_mini_fat_sectors
, the address in this->secEndPtr
is increased by 4 each time a new sector is added to the vector, related with a parsed directory entry
until the FAT_ENDOFCHAIN
marker is found.
In our case only one sector (0xF2
is added at the beginning ) because:
Starting Sector Location (4 bytes)
offset : 1:81F8h - F2 00 00 00
MiniFat entries in memory + (0xF2 * 4) == fffffffe (FAT_ENDOFCHAIN) - possible offset in the file 0x123C8
Which in consequence give us a difference of 4 between this->secEndPtr
and this->secStartPtr
. Next, divided by 4 (line 21 ( >> 2)
) this passes the constraint and to size_to_read
is assigned 0x54
which leads to a heap-based buffer overflow.
0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** WARNING: Unable to verify checksum for PresentationFramework.ni.dll
*** WARNING: Unable to verify checksum for WindowsBase.ni.dll
Failed to request MethodData, not in JIT code range
MethodDesc: 2f0380f0
Method Name: HwordAppModule.HwordDocProxy.Open(HwordAppModule.HwordFrameProxy, System.String, System.String, Int32, Int32)
Class: 2ea08dfc
MethodTable: 2f0382a0
mdToken: 060002dd
Module: 2df82848
IsJitted: yes
CodeAddr: 00344368
Transparency: Safe critical
Unable to load image c:\Program Files (x86)\Hnc\Office 2020\HOffice110\Bin\HwordAppModule.dll, Win32 error 0n2
MethodDesc: 2df8e340
Method Name: Hword.HwordFrame._OpenDocument(System.String, HwordDefine.OpenAttr, Boolean, Boolean, Boolean, System.String)
Class: 2a39ace0
MethodTable: 2df8e8a4
mdToken: 06001258
Module: 161e4044
IsJitted: yes
CodeAddr: 003431e8
Transparency: Critical
MethodDesc: 2df8e334
Method Name: Hword.HwordFrame.OpenDocument(System.String, HwordDefine.OpenType, HwordDefine.OpenAttr, Boolean)
Class: 2a39ace0
MethodTable: 2df8e8a4
mdToken: 06001257
Module: 161e4044
IsJitted: yes
CodeAddr: 00341be8
Transparency: Critical
MethodDesc: 2df8cee8
Method Name: Hword.HwordApp.ProcessShellCommand(Hnc.Static.CommandParser)
Class: 2a391574
MethodTable: 2df8d058
mdToken: 0600116e
Module: 161e4044
IsJitted: yes
CodeAddr: 2f06ee40
Transparency: Critical
MethodDesc: 161eb214
Method Name: Hword.HwordAppMain.StartApp(Hnc.Static.CommandParser)
Class: 1f837b24
MethodTable: 161eb290
mdToken: 0600075b
Module: 161e4044
IsJitted: yes
CodeAddr: 2e7410c8
Transparency: Critical
MethodDesc: 161eb1d8
Method Name: Hword.HwordAppMain.OnApplicationStartup(System.Object, System.Windows.StartupEventArgs)
Class: 1f837b24
MethodTable: 161eb290
mdToken: 06000756
Module: 161e4044
IsJitted: yes
CodeAddr: 1d75abb8
Transparency: Critical
KEY_VALUES_STRING: 1
Key : AV.Fault
Value: Read
Key : Analysis.CPU.mSec
Value: 38139
Key : Analysis.DebugAnalysisManager
Value: Create
Key : Analysis.Elapsed.mSec
Value: 268034
Key : Analysis.Init.CPU.mSec
Value: 285562
Key : Analysis.Init.Elapsed.mSec
Value: 86923456
Key : Analysis.Memory.CommitPeak.Mb
Value: 1927
Key : CLR.BuiltBy
Value: NET48REL1LAST_C
Key : CLR.Engine
Value: CLR
Key : CLR.Version
Value: 4.8.4400.0
Key : Timeline.OS.Boot.DeltaSec
Value: 420319
Key : WER.Process.Version
Value: 11.0.0.2353
NTGLOBALFLAG: 2000000
PROCESS_BAM_CURRENT_THROTTLED: 0
PROCESS_BAM_PREVIOUS_THROTTLED: 0
APPLICATION_VERIFIER_FLAGS: 0
APPLICATION_VERIFIER_LOADED: 1
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 69c9f26d (MSVCR120!memcpy+0x0000002a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 7f167000
Attempt to read from address 7f167000
FAULTING_THREAD: 00001198
PROCESS_NAME: Hword.exe
READ_ADDRESS: 7f167000
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE_STR: c0000005
EXCEPTION_PARAMETER1: 00000000
EXCEPTION_PARAMETER2: 7f167000
STACK_TEXT:
011cd76c 69c9f71f 7f166fc1 7f169001 00000053 MSVCR120!memcpy+0x2a
011cd788 69ca744f 7f166fc1 fffffffe 7f169001 MSVCR120!memcpy_s+0x3e
011cd7bc 69ca74bd 7f166fc0 ffffffff 00000001 MSVCR120!_fread_nolock_s+0xd5
011cd804 69ca7512 7f166fc0 ffffffff 00000001 MSVCR120!fread_s+0x6b
011cd820 66112be4 7f166fc0 00000001 00000054 MSVCR120!fread+0x16
WARNING: Stack unwind information not available. Following frames may be wrong.
011cd838 66af18e9 7f166fc0 00000054 000000f2 HwordApp!HwordDeletePropertyArray+0x188a64
011cd854 66af15ad 7f162f28 7f166fc0 787f6ff4 HwordApp!HwordDeletePropertyArray+0xb67769
011cd8a4 66abeb4b 51520f80 00000054 000000f2 HwordApp!HwordDeletePropertyArray+0xb6742d
011cd8d8 664b7eda 787f6fc0 2e77cd93 6269ef90 HwordApp!HwordDeletePropertyArray+0xb349cb
011cd90c 664b7fc2 51520f80 807f6fa8 011cd974 HwordApp!HwordDeletePropertyArray+0x52dd5a
011cd94c 6643d959 51520f80 807f0f90 011cd974 HwordApp!HwordDeletePropertyArray+0x52de42
011cda28 66443a47 51520f80 00001a00 502e2f48 HwordApp!HwordDeletePropertyArray+0x4b37d9
011cdcb0 66446aa3 37a0adf8 82e3ef90 62e0ffa8 HwordApp!HwordDeletePropertyArray+0x4b98c7
011cdf08 66446289 37a0adf8 82e3ef90 62e0ffa8 HwordApp!HwordDeletePropertyArray+0x4bc923
011ce4c8 6645474a 37a0adf8 82e3ef90 7a120fc0 HwordApp!HwordDeletePropertyArray+0x4bc109
011ce574 66441a45 7a120fc0 82e3ef90 62748a78 HwordApp!HwordDeletePropertyArray+0x4ca5ca
011ce5c8 6677fe29 53706fd8 00000000 53706fd8 HwordApp!HwordDeletePropertyArray+0x4b78c5
011ce5fc 660eceb0 2800cfd8 011ce65c 27d2cfdc HwordApp!HwordDeletePropertyArray+0x7f5ca9
011ce624 660ea988 53702fe8 011ce65c 27d2cfdc HwordApp!HwordDeletePropertyArray+0x162d30
011ce6f8 65fa2d43 00000000 83348fb0 011ce828 HwordApp!HwordDeletePropertyArray+0x160808
011cea78 00344404 4ecc8fa0 6823ef6c 69c75094 HwordApp!HwordDeletePropertyArray+0x18bc3
011ceae0 003434c9 00000000 00000000 200c1228 0x344404
011ceba8 00341f67 2014a1e4 00000000 00000000 0x3434c9
011cebf4 2f06f1b9 00000000 00000000 00000001 0x341f67
011cec54 2e7412bf 2016699c 201669ac 20149a84 0x2f06f1b9
011cec68 1d75ac14 2016699c 201662c8 20166594 0x2e7412bf
011cec7c 6e0cfd43 2016699c 00000000 20149e8c 0x1d75ac14
011cec94 6e095ef2 20166458 00000000 011cecbc PresentationFramework_ni+0x2ffd43
011ceca4 6feeee42 00000001 20166458 200d4628 PresentationFramework_ni+0x2c5ef2
011cecbc 6feeed85 00000001 00000000 00000000 WindowsBase_ni+0xdee42
011cecf8 6fef10cd 00000000 00000001 00000000 WindowsBase_ni+0xded85
011ced40 6feef56f 201664e4 73e68604 200c3b4c WindowsBase_ni+0xe10cd
011cedac 73e68537 00000000 20149b58 00000000 WindowsBase_ni+0xdf56f
011cedc0 73e684f4 00000000 20149b58 00000000 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)$##6003AEF+0x17
011ceddc 6fef0f83 20149b58 201664c4 00000000 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)$##6003AEE+0x44
011cee0c 6fef0d80 20149b58 00000000 00000000 WindowsBase_ni+0xe0f83
011cee44 6feed346 00000000 200d46fc 00000000 WindowsBase_ni+0xe0d80
011cee84 6feec57c 00000000 00000000 200d4380 WindowsBase_ni+0xdd346
011ceec0 6feee661 200d52f0 00000000 00000000 WindowsBase_ni+0xdc57c
011ceefc 6feee94c 200d4f4c 00000000 00000000 WindowsBase_ni+0xde661
011cef1c 6feeee42 00000001 200c3b4c 200d4628 WindowsBase_ni+0xde94c
011cef34 6feeed85 00000001 200d4f34 00000000 WindowsBase_ni+0xdee42
011cef70 6feecf62 00000000 00000001 200d4f34 WindowsBase_ni+0xded85
011cefc8 6feee4b4 00000001 200d4f34 200d4f14 WindowsBase_ni+0xdcf62
011cf010 161ed16e 00000000 00000000 0000c1c0 WindowsBase_ni+0xde4b4
011cf044 775636db 0017052e 0000c1c0 00000000 0x161ed16e
011cf070 7755a66a 26ff9ff6 0017052e 0000c1c0 USER32!_InternalCallWinProc+0x2b
011cf154 775583da 26ff9ff6 00000000 0000c1c0 USER32!UserCallWinProcCheckWow+0x33a
011cf1c8 775581a0 011cf220 011cf210 6ff074f1 USER32!DispatchMessageWorker+0x22a
011cf1d4 6ff074f1 011cf220 29163fd7 74f5fda4 USER32!DispatchMessageW+0x10
011cf210 6feeb3d7 201475ec 200d4380 0017052e WindowsBase_ni+0xf74f1
011cf258 6feeb319 20166978 011cf274 6e095ebc WindowsBase_ni+0xdb3d7
011cf264 6e095ebc 20149ac4 00000000 011cf294 WindowsBase_ni+0xdb319
011cf274 6e095a7a 6dddd384 00000000 201662c8 PresentationFramework_ni+0x2c5ebc
011cf294 6e09586e 20149a84 201662c8 011cf2dc PresentationFramework_ni+0x2c5a7a
011cf2dc 1d75b67a 200c1fd4 200c6a00 200c1fec PresentationFramework_ni+0x2c586e
011cf2f0 1d750ede 200c67f4 011cf3b0 00000000 0x1d75b67a
011cf308 74f5f066 1f827ac0 011cf368 74f6230a 0x1d750ede
011cf314 74f6230a 011cf3b0 011cf358 75052440 clr!CallDescrWorkerInternal+0x34
011cf368 74f685eb 00000000 200c233c 011cf3c4 clr!CallDescrWorkerWithHandler+0x6b
011cf3dc 7510b28b 011cf4b8 3102b858 161eb1a8 clr!MethodDescCallSite::CallTargetWorker+0x16a
011cf500 7510b96a 011cf544 00000000 3102ba34 clr!RunMain+0x1b3
011cf76c 7510b897 00000000 3102b108 00d90000 clr!Assembly::ExecuteMainMethod+0xf7
011cfc50 7510ba18 3102b1f0 00000000 00000000 clr!SystemDomain::ExecuteMainMethod+0x5ef
011cfca8 7510bb3e 3102b1b0 00000000 75107420 clr!ExecuteEXE+0x4c
011cfce8 75107445 3102b07c 00000000 75107420 clr!_CorExeMainInternal+0xdc
011cfd24 7573fa84 7c0c16f9 757d4330 7573fa20 clr!_CorExeMain+0x4d
011cfd5c 757ce81e 757d4330 75730000 011cfd84 mscoreei!_CorExeMain+0xd6
011cfd6c 757d4338 757d4330 7682fa29 01354000 MSCOREE!ShellShim__CorExeMain+0x9e
011cfd74 7682fa29 01354000 7682fa10 011cfde0 MSCOREE!_CorExeMain_Exported+0x8
011cfd84 779d7a9e 01354000 09867502 00000000 KERNEL32!BaseThreadInitThunk+0x19
011cfde0 779d7a6e ffffffff 779f8a41 00000000 ntdll!__RtlUserThreadStart+0x2f
011cfdf0 00000000 757d4330 01354000 00000000 ntdll!_RtlUserThreadStart+0x1b
STACK_COMMAND: ~0s ; .cxr ; kb
FAULTING_SOURCE_LINE: f:\dd\vctools\crt\crtw32\string\i386\memcpy.asm
FAULTING_SOURCE_FILE: f:\dd\vctools\crt\crtw32\string\i386\memcpy.asm
FAULTING_SOURCE_LINE_NUMBER: 188
FAULTING_SOURCE_CODE:
No source found for 'f:\dd\vctools\crt\crtw32\string\i386\memcpy.asm'
SYMBOL_NAME: MSVCR120!memcpy+2a
MODULE_NAME: MSVCR120
IMAGE_NAME: MSVCR120.dll
FAILURE_BUCKET_ID: INVALID_POINTER_READ_STRING_DEREFERENCE_AVRF_c0000005_MSVCR120.dll!memcpy
OSPLATFORM_TYPE: x86
OSNAME: Windows 8
IMAGE_VERSION: 12.0.40649.5
FAILURE_ID_HASH: {9105dc67-e4c3-f9b0-d352-023f957ac60d}
Followup: MachineOwner
---------
2021-10-19 - Vendor Disclosure
2022-02-15 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.