Dissecting modern browser exploit: case study of CVE-2018–8174

When this exploit first emerged in the turn of April and May it spiked my interest, since despite heavy obfuscation, the code structure seemed well organized and the vulnerability exploitation code small enough to make analysis simpler. I downloaded POC from github and decided it would be a good candidate for taking a look at under the hood. At that time two analyses were already published, first from 360 and second from Kaspersky. Both of them helped me understand how it worked, but were not enough to deeply understand every aspect of the exploit. That’s why I’ve decided to analyze it on my own and share my findings.

Preprocessing

First in order to remove integer obfuscation I used regex substitution in python script:

Use after free

Vulnerability occurs, when object is terminated and custom defined function Class_Terminate() is called. In this function reference to the object being freed is saved in UafArray. From now on UafArray(i) refers to the deleted object.

Image for post
Image for post
bp vbscript!VBScriptClass::TerminateClass ".printf \"Class %mu at %x, terminate called\\n\", poi(@ecx + 0x24), @ecx; g";bp vbscript!VBScriptClass::Release ".printf \"Class %mu at: %x ref counter, release called: %d\\n\", poi(@eax + 0x24), @ecx, poi(@eax + 0x4); g";bp vbscript!VBScriptClass::Create+0x55 ".printf \"Class %mu created at %x\\n\", poi(@esi + 0x24), @esi; g";
Class EmptyClass created at 3a7d90
Class EmptyClass created at 3a7dc8
...
Class ReuseClass created at 22601a0
Class ReuseClass created at 22601d8
Class ReuseClass created at 2260210
...
Class ClassTerminateA created at 22605c8
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 1
Class ClassTerminateA at 22605c8, terminate called
Class ClassTerminateA at: 70541748 ref counter, release called: 5
Class ClassTerminateA at: 70541748 ref counter, release called: 4
Class ClassTerminateA at: 70541748 ref counter, release called: 3
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA created at 22605c8
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 2
Class ClassTerminateA at: 70541748 ref counter, release called: 1
Class ClassTerminateA at 22605c8, terminate called
Class ClassTerminateA at: 70541748 ref counter, release called: 5
Class ClassTerminateA at: 70541748 ref counter, release called: 4
Class ClassTerminateA at: 70541748 ref counter, release called: 3
Class ClassTerminateA at: 70541748 ref counter, release called: 2
...
Class ReuseClass created at 22605c8
...
Class ClassTerminateB created at 2260600
Class ClassTerminateB at: 70541748 ref counter, release called: 2
Class ClassTerminateB at: 70541748 ref counter, release called: 2
Class ClassTerminateB at: 70541748 ref counter, release called: 2
Class ClassTerminateB at: 70541748 ref counter, release called: 1
Class ClassTerminateB at 2260600, terminate called
Class ClassTerminateB at: 70541748 ref counter, release called: 5
Class ClassTerminateB at: 70541748 ref counter, release called: 4
Class ClassTerminateB at: 70541748 ref counter, release called: 3
Class ClassTerminateB at: 70541748 ref counter, release called: 2
...
Class ReuseClass created at 2260600
Class ClassTerminateA created at 2240708
Class ClassTerminateA at: 6c161748 ref counter, release called: 2
Class ClassTerminateA at: 6c161748 ref counter, release called: 2
Class ClassTerminateA at: 6c161748 ref counter, release called: 2
Class ClassTerminateA at: 6c161748 ref counter, release called: 1
Class ClassTerminateA at 2240708, terminate called
Class ClassTerminateA at: 6c161748 ref counter, release called: 5
Class ClassTerminateA at: 6c161748 ref counter, release called: 4
Class ClassTerminateA at: 6c161748 ref counter, release called: 3
Class ReuseClass created at 2240740

Type Confusion

Having created those two objects with 7 uncounted references to each, we established read arbitrary memory primitive. There are two similar classes ReuseClass and FakeReuseClass. By replacing first class with second one a type confusion on mem member occurs.

Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
Q=CDbl("174088534690791e-324") ' db 0, 0, 0, 0, 0Ch, 20h, 0, 0

Arbitrary memory read

The result is that we end up with two objects of FakeReuseClass. One of them has a mem member array that is addressing whole user-space (0x00000000 - 0x7fffffff) and the other has a member of type VT_I4 (4 byte integer) with pointer to an empty 16 byte string. Using the second object, a pointer to string is leaked:

some_memory=resueObjectB_int.mem
Image for post
Image for post
Image for post
Image for post

Triggering code execution

Final code execution is achived in two steps. First a chain of two calls is built, but it’s not a ROP chain. NtContinue is provided with CONTEXT structure that sets EIP to VirtualProtect address, and ESP to structure containing VirtualProtect's parameters.

Image for post
Image for post
Image for post
Image for post

Conclusion

CVE-2018–8174 is a good example of chaining few use after free and type confusion conditions to achieve code execution in very clever way. It’s a great example to learn from and understand inner workings of such exploits.

Useful links

Commented exploit code

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store