Monday, October 5, 2020

CVE-2020-1034: The Case for Explicitness in Vulnerability Management

Posted on: Sun, Oct 6 2020

1. Introduction

The Patch Tuesday of last September included several vulnerabilities that allowed kernel elevation of privilege. But no details or analysis were published about them.

In this post, I will present my research on CVE-2020-1034 vulnerability.

2. Patch Diffing

The affected module was ntoskrnl.exe. I downloaded both patched and unpatched versions of this module. I carried out my analysis on Windows 10 1903 x64.

Here is the bindiff result of comparing version 18362.1049 to 18362.1082.

It was clear that EtwpNotifyGuid was changed. I had a close look at the function and discovered an important change.

I decided to look into this further.

3. The Vulnerability

First, I studied NtTraceControl which is the gateway to the EtwpNotifyGuid. This is a description of NtTraceControl.

The FunctionCode that leads to the call of EtwpNotifyGuid is 0x11. And a few checks need to be satisfied before the actual call as you will see in the following diagram.

Then, I analyzed the function in question. If we take a careful look at EtwpNotifyGuid, we will discover some interesting points. Pay great attention at the spot where the patch was made.

The rdi register contains the address of the input buffer. The diagram says the byte at address rdi+0Ch decides whether to create a UmReplyObject.
Let’s see where the value of r12b register comes from.

The initial value of r12b was 4. But it is reset to 1. So when the value of byte ptr [rdi+0Ch] equals to 1, the qword at rdi+18h is set to the address of newly created UmReplyObject.
Otherwise, the qword will remain intact. This may contain a dangerous consequences. As the input can never be trusted.

I expected and tried to see if it really is. I set the qword at rdi+18h to an arbitrary value and saw what happened. It was just as I expected. I got a BSOD.

Wow! I got very excited. I carried on my analysis further.

The input buffer is passed to EtwpSendDataBlock and EtwpQueueNotification.

Looking into EtwpQueueNotification, I found where the UmReplyObject was referenced.

The value of bl is zero. If the byte at rbp+0Ch is not 0, then the qword at rbp+18h is read as a pointer to an object. And the reference of the object is increased.

I understood the root cause of the problem. The culprit was the inconsistent comparison of the byte at rbp+0C.

In the comparison done in EtwpNotifyGuid, the value was compared to 1 to decide whether to create a new UmReplyObject.
But in the last comparison, the value was compared to zero.

The first comparision might look like the following in C code.
if (*(bool*)(rdi+0x0C) == true)

The second one might look like the following.
if (*(bool*)(rbp+0x0C))

You see the inconsistency? What if the value is other than 1 or 0? An arbitrary value will be taken as an object address.
Then, ObfReferenceObject is called for it which means the operation qword ptr [[InputBuffer + 0x18] - 0x30] ++ is carried out. So arbitrary address increment was achieved.

This is the proof-of-concept code.

4. How to Exploit

It is a very nice vulnerability and the exploitation is quite straightforward.

On kernels of Win10 RS3 or below, we can use the technique of two adjacent palettes.
On kernels of Win10 RS4 or above, we can manipulate the Privilege field of the process token.

5. Conclusion

Explicit boolean testing is dangerous if performed on the value of a boolean pointer.

It took much time for me to reproduce this vulnerability. It was indeed a nice one that is very simple and reliable.
It was quite surprising that windows kernel should contain this sort of vulnerability.

I will not disclose the full exploit code as it will be abused by malicious actors.

6. Demo

contact : youtube.com/@openexploitresearch

Friday, October 2, 2020

Exploiting the V8 NULL Pointer Dereference Vulnerability

 Posted on: Tue, Oct 3 2020

Introduction

Last year, The UK’s National Cyber Security Centre (NCSC) reported a bug existed in the V8 compiler and Google patched it silently. The bug ID is 1003286 and you can find the details here. According to their report, it is NULL pointer dereference DoS bug which is not exploitable and it can be triggered via WASM code. During the deep analysis, we found that there is another way to trigger the bug and it is exploitable by leveraging V8 JIT compiler process.

In this blog, we describe the details to exploit this vulnerability and demonstrate the remote code execution.

Root Cause

For the code optimization, V8 JIT compiler uses the Node graphs and generates optimized native code by reducing them through several phase of optimization pipeline. This Node graphs are also used in WASM compiler to compile the WASM code to native code.

The Nodes are linked each other in the graph using “Use” structure as following.

By using this structure, Nodes can specify their input nodes and user nodes for traversing the graph to reduce. The Use structure contains bit-field that is used to hold multiple pieces of information.

The InputIndex field indicates the index of the input Node of this Use and this is used to locate the corresponding input Node of the user Node. However this field only provides 17 bits of space to store the index and there is no code to check this limitation. Therefore constructing a graph with a large number of input Nodes to a single Node can cause integer overflow. For example, 0x20002 indicates 0x2 as the input index.

This InputIndex field is used in Use::input_ptr and Use::from functions used to locate the user Node or corresponding input Node.

This can cause type confusion between Node, Use and its sub-fields.

NCSC constructed proof-of-concept (PoC) using WebAssembly and led to NULL pointer dereference. The WASM code optimization process is much simpler than JIT compiler and thus controlling the process is more difficult than using the JIT compiler, so they cannot avoid NULL pointer dereferencing.

During the analysis, we found the JIT code that can make a Node having a lot of input Nodes.

Using this function, we constructed the PoC different from NCSC’s triggering bug successfully and got more ability to control execution flow.

Exploitation

Although this vulnerability exists in the V8 JIT compiler, it is very different from others. The common JIT compiler bugs are caused due to lack of map and bound check and mis-typing. In those cases, the optimized codes are successfully generated but they contains vulnerabilities. However, in this case the crash occurs during the JIT compilation of the Javascript code before generating optimized code. This makes exploitation more difficult.

For successful exploitation, it is needed to generate vulnerable code leveraging the original bug and achieve remote code execution from it. As described above, the typical type of JIT bugs are invalid map check, bound check and typing bugs and it is easy to exploit them. So we decided to generate these types of vulnerable code and studied the method to eliminate MapCheck or BoundCheck Node in the graph by replacing the Opcode of the Node.

Node, Use and Operator are the structures we can cause type confusion and they have the following structures.

Above mentioned Use::input_ptr and Use::from functions are called from ReplaceWithValue function which is used for replacing a value Node with other node.

Here, the type of “old_to” is not Node by the type confusion and it can be the field of Use e.g. Use *next, *prev or bit_field.

If use->prev is NULL, old_to->first_use is replaced with use->next. From the fact that “old_to” can be Use, old_to->first_use can be the Operator of CheckMap Node. If old_to->first_use is replaced with use->next, the CheckMapNode->op->opcode becomes use->next->bit_field. In this case, the opcode of the CheckMap Node can be replaced with other opcode and this results in CheckMap Node elimination. This is the main scenario of first step of exploitation.

Based on this model, we created the code as following.

The Node graph before replacing JSStrictEqual Node created by Turbolizer satisfies our modeling.

The array MapCheck Node is successfully changed with other opcode (EffectPhi), but several problems occur due to the changing including crashes in the next phases of optimization. To overcome these problems, we trimmed the graph that causes the crash by triggering GraphTrimmingPhase of compilation pipeline and generated valid optimized native code not including array map checking that can be used for out-of-bound access.

Now, we can cause type confusion between PACKED_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS arrays and obtain arbitrary read/write and addrof primitives used for achieve remote code execution.

You can confirm it works by lauching the full exploit on Chrome version 77.

Conclusion

By the efforts of many security researchers interested in V8, a lot of vulnerabilities were discovered and V8 has become more strengthened. There are few vulnerabilities in V8 that can be exploited easily, in other words, critical vulnerabilities. This says deep dive analysis and more efforts are essentially needed to exploit the vulnerabilities in V8.

We expect our blog will help you.

Thanks for reading this. Here is the demo video.


Unveiling CVE-2024-38112 in the Shadows of Internet Explorer

Overview Recent security research uncovered a new vulnerability within Windows systems that exploits Internet Explorer to execute remote cod...