Analyzing CVE-2021-1665 – Distant Code Execution Vulnerability in Home windows GDI+

0
111

[ad_1]

Introduction
Microsoft Home windows Graphics System Interface+, also called GDI+, permits numerous functions to make use of completely different graphics performance on video shows in addition to printers. Home windows functions don’t immediately entry graphics {hardware} similar to gadget drivers, however they work together with GDI, which in flip then interacts with gadget drivers. On this approach, there may be an abstraction layer to Home windows functions and a typical set of APIs for everybody to make use of.
Due to its advanced format, GDI+ has a recognized historical past of assorted vulnerabilities. We at McAfee constantly fuzz numerous open supply and closed supply software program together with home windows GDI+. Over the previous couple of years, we’ve got reported numerous points to Microsoft in numerous Home windows parts together with GDI+ and have obtained CVEs for them.
On this put up, we element our root trigger evaluation of 1 such vulnerability which we discovered utilizing WinAFL: CVE-2021-1665 – GDI+ Distant Code Execution Vulnerability.  This subject was mounted in January 2021 as a part of a Microsoft Patch.
What’s WinAFL?
WinAFL is a Home windows port of a preferred Linux AFL fuzzer and is maintained by Ivan Fratric of Google Undertaking Zero. WinAFL makes use of dynamic binary instrumentation utilizing DynamoRIO and it requires a program referred to as as a harness. A harness is nothing however a easy program which calls the APIs we need to fuzz.
A easy harness for this was already supplied with WinAFL, we are able to allow “Picture->GetThumbnailImage” code which was commented by default within the code. Following is the harness code to fuzz GDI+ picture and GetThumbnailImage API:
 

As you may see, this small piece of code merely creates a brand new picture object from the offered enter file after which calls one other operate to generate a thumbnail picture. This makes for a wonderful assault vector and might have an effect on numerous Home windows functions in the event that they use thumbnail photos. As well as, this requires little consumer interplay, thus software program which makes use of GDI+ and calls GetThumbnailImage API, is weak.
Gathering Corpus:
corpus offers a sound basis for fuzzing. For that we are able to use Google or GitHub along with additional check corpus accessible from numerous software program and public EMF information which have been launched for different vulnerabilities. Now we have generated a number of check information by making adjustments to a pattern code offered on Microsoft’s web site which generates an EMF file with EMFPlusDrawString and different data:

Ref: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emfplus/07bda2af-7a5d-4c0b-b996-30326a41fa57
Minimizing Corpus:
After we’ve got collected an preliminary corpus file, we have to reduce it. For this we are able to use a utility referred to as winafl-cmin.py as follows:

winafl-cmin.py -D D:workwinaflDynamoRIObin32 -t 10000 -i inCorpus -o minCorpus -covtype edge -coverage_module gdiplus.dll -target_module gdiplus_hardik.exe -target_method fuzzMe -nargs 2 — gdiplus_hardik.exe @@

How does WinAFL work?
WinAFL makes use of the idea of in-memory fuzzing. We have to present a operate identify to WinAFL. It’ll save this system state in the beginning of the operate and take one enter file from the corpus, mutate it, and feed it to the operate.
It’ll monitor this for any new code paths or crashes. If it finds a brand new code path, it would think about the brand new file as an attention-grabbing check case and can add it to the queue for additional mutation. If it finds any crashes, it would save the crashing file in crashes folder.
The next image reveals the fuzzing circulation:

Fuzzing with WinAFL:
As soon as we’ve got compiled our harness program, collected, and minimized the corpus, we are able to run this command to fuzz our program with WinAFL:

afl-fuzz.exe -i minCorpus -o out -D D:workwinaflDynamoRIObin32 -t 20000 —coverage_module gdiplus.dll -fuzz_iterations 5000 -target_module gdiplus_hardik.exe -target_offset 0x16e0 -nargs 2 — gdiplus_hardik.exe @@

Outcomes:
We discovered a number of crashes and after triaging distinctive crashes, and we discovered a crash in “gdiplus!BuiltLine::GetBaselineOffset” which seems as follows within the name stack under:

As might be seen within the above picture, this system is crashing whereas making an attempt to learn knowledge from a reminiscence tackle pointed by edx+8. We are able to see it registers ebx, ecx and edx accommodates c0c0c0c0 which implies that web page heap is enabled for the binary. We are able to additionally see that c0c0c0c0 is being handed as a parameter to “gdiplus!FullTextImager::RenderLine” operate.
Patch Diffing to See If We Can Discover the Root Trigger
To determine a root trigger, we are able to use patch diffing—specifically, we are able to use IDA BinDiff plugin to establish what adjustments have been made to patched file. If we’re fortunate, we are able to simply discover the basis trigger by simply wanting on the code that was modified. So, we are able to generate an IDB file of patched and unpatched variations of gdiplus.dll after which run IDA BinDiff plugin to see the adjustments.
We are able to see that one new operate was added within the patched file, and this appears to be a destructor for BuiltLine Object :

We are able to additionally see that there are a number of features the place the similarity rating is < 1 and one such operate is FullTextImager::BuildAllLines as proven under:

Now, simply to verify if this operate is basically the one which was patched, we are able to run our check program and POC in windbg and set a break level on this operate. We are able to see that the breakpoint is hit and this system doesn’t crash anymore:

Now, as a subsequent step, we have to establish what has been modified on this operate to repair this vulnerability. For that we are able to verify circulation graph of this operate and we see one thing as follows. Sadly, there are too many adjustments to establish the vulnerability by merely wanting on the diff:

The left aspect illustrates an unpatched dll whereas proper aspect reveals a patched dll:

Inexperienced signifies that the patched and unpatched blocks are identical.
Yellow blocks point out there was some adjustments between unpatched and patched dlls.
Crimson blocks name out variations within the dlls.

If we zoom in on the yellow blocks we are able to see following:

We are able to be aware a number of adjustments. Few blocks are eliminated within the patched DLL, so patch diffing will alone won’t be enough to establish the basis reason for this subject. Nonetheless, this presents worthwhile hints about the place to look and what to search for when utilizing different strategies for debugging similar to windbg. Just a few observations we are able to spot from the bindiff output above:

Within the unpatched DLL, if we verify rigorously we are able to see that there’s a name to “GetuntrimmedCharacterCount” operate and afterward there may be one other name to a operate “SetSpan::SpanVector”
Within the patched DLL, we are able to see that there’s a name to “GetuntrimmedCharacterCount” the place a return worth saved inside EAX register is checked. If it’s zero, then management jumps to a different location—a destructor for BuiltLine Object, this was newly added code within the patched DLL:

So we are able to assume that that is the place the vulnerability is mounted. Now we have to determine following:

Why our program is crashing with the offered POC file?
What subject within the file is inflicting this crash?
What worth of the sector?
Which situation in program which is inflicting this crash?
How this was mounted?

EMF File Format:
EMF is also called enhanced meta file format which is used to retailer graphical photos gadget independently. An EMF file is consisting of assorted data which is of variable size. It could actually include definition of assorted graphic object, instructions for drawing and different graphics properties.

Credit score: MS EMF documentation.
Typically, an EMF file include the next data:

EMF Header – This accommodates details about EMF construction.
EMF Data – This may be numerous variable size data, containing details about graphics properties, drawing order, and so forth.
EMF EOF File – That is the final file in EMF file.

Detailed specs of EMF file format might be seen at Microsoft web site at following URL:
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emf/91c257d7-c39d-4a36-9b1f-63e3f73d30ca
Finding the Susceptible File within the EMF File:
Typically, a lot of the points in EMF are due to malformed or corrupt data. We have to determine which file kind is inflicting this crash. For this if we take a look at the decision stack we are able to see following:

We are able to discover a name to operate “gdiplus!GdipPlayMetafileRecordCallback”

By setting a breakpoint on this operate and checking parameter, we are able to see following:

We are able to see that EDX accommodates some reminiscence tackle and we are able to see that parameter given to this operate are: 00x00401c,0x00000000 and 0x00000044.
Additionally, on checking the situation pointed by EDX we are able to see following:

If we verify our POC EMF file, we are able to see that this knowledge belongs to file from offset: 0x15c:

By going by EMF specification and manually parsing the data, we are able to simply determine that this can be a “EmfPlusDrawString” file, the format of which is proven under:

In our case:
File Kind = 0x401c EmfPlusDrawString file
Flags = 0x0000
Measurement = 0x50
Knowledge dimension = 0x44
Brushid = 0x02
Format id = 0x01
Size = 0x14
Layoutrect = 00 00 00 00 00 00 00 00 FC FF C7 42 00 00 80 FF
String knowledge =

Now that we’ve got situated the file that appears to be inflicting the crash, the subsequent factor is to determine why our program is crashing. If we debug and verify the code, we are able to see that management reaches to a operate “gdiplus!FullTextImager::BuildAllLines”. After we decompile this code, we are able to see one thing  like this:

The next diagram reveals the operate name hierarchy:

The execution circulation in abstract:

Inside “Builtline::BuildAllLines” operate, there’s a whereas loop inside which this system allocates 0x60 bytes of reminiscence. Then it calls the “Builtline::BuiltLine”
The “Builtline::BuiltLine” operate strikes knowledge to the newly allotted reminiscence after which it calls “BuiltLine::GetUntrimmedCharacterCount”.
The return worth of “BuiltLine::GetUntrimmedCharacterCount” is added to loop counter, which is ECX. This course of will likely be repeated till the loop counter (ECX) is < string size(EAX), which is 0x14 right here.
The loop begins from 0, so it ought to terminate at 0x13 or it ought to terminate when the return worth of “GetUntrimmedCharacterCount” is 0.
However within the weak DLL, this system doesn’t terminate due to the best way loop counter is elevated. Right here, “BuiltLine::GetUntrimmedCharacterCount” returns 0, which is added to Loop counter(ECX) and doesn’t enhance ECX worth. It allocates 0x60 bytes of reminiscence and creates one other line, corrupting the information that later leads this system to crash. The loop is executed for 21 occasions as an alternative of 20.

Intimately:
1. Inside “Builtline::BuildAllLines” reminiscence will likely be allotted for 0x60 or 96 bytes, and within the debugger it seems as follows:

2. Then it calls “BuiltLine::BuiltLine” operate and strikes the information to newly allotted reminiscence:

3. This occurs in aspect some time loop and there’s a operate name to “BuiltLine::GetUntrimmedCharacterCount”.
4. Return worth of “BuiltLine::GetUntrimmedCharacterCount” is saved in a location 0x12ff2ec. This worth will likely be 1 as might be seen under:

5. This worth will get added to ECX:

6. Then there’s a verify that determines if ecx< eax. If true, it would proceed loop, else it would bounce to a different location:

7. Now within the weak model, loop doesn’t exist if the return worth of “BuiltLine::GetUntrimmedCharacterCount” is 0, which implies that this 0 will likely be added to ECX and which implies ECX won’t enhance. So the loop will execute 1 extra time with the “ECX” worth of 0x13. Thus, this may result in loop getting executed 21 occasions slightly than 20 occasions. That is the basis reason for the issue right here.
Additionally after some debugging, we are able to determine why EAX accommodates 14. It’s learn from the POC file at offset: 0x174:

If we recall, that is the EmfPlusDrawString file and 0x14 is the size we talked about earlier than.
In a while, this system reaches to “FullTextImager::Render” operate corrupting the worth of EAX as a result of it reads the unused reminiscence:

This will likely be handed as an argument to “FullTextImager::RenderLine” operate:

Later, program will crash whereas making an attempt to entry this location.

Our program was crashing whereas processing EmfPlusDrawString file contained in the EMF file whereas accessing an invalid reminiscence location and processing string knowledge subject. Mainly, this system was not verifying the return worth of “gdiplus!BuiltLine::GetUntrimmedCharacterCount” operate and this resulted in taking a unique program path that  corrupted the register and numerous reminiscence values, in the end inflicting the crash.
How this subject was mounted?
As we’ve got discovered by taking a look at patch diff above, a verify was added which decided the return worth of “gdiplus!BuiltLine::GetUntrimmedCharacterCount” operate.

If the retuned worth is 0, then program xor’s EBX which accommodates counter and bounce to a location which calls destructor for Builtline Object:

Right here is the destructor that forestalls the problem:

Conclusion:
GDI+ is a really generally used Home windows element, and a vulnerability like this could have an effect on billions of methods throughout the globe. We suggest our customers to use correct updates and maintain their Home windows deployment present.
We at McAfee are constantly fuzzing numerous open supply and closed supply library and work with distributors to repair such points by responsibly disclosing such points to them giving them correct time to repair the problem and launch updates as wanted.
We’re grateful to Microsoft for working with us on fixing this subject and releasing an replace.
 
 
 
 
x3Cimg peak=”1″ width=”1″ type=”show:none” src=”https://www.fb.com/tr?id=766537420057144&ev=PageView&noscript=1″ />x3C/noscript>’);

[ad_2]