MS14-066 In Depth Analysis

A few days ago I published an article detailing how a second bug, in the schannel TLS handshake handling, could allow an attacker to trigger the DecodeSigAndReverse heap overflow in an application that doesn’t support client certificates. I had stated I was not familiar with ECC signatures and was unsure of how to trigger the exploit; However, a few hours research fixed that.

BeyondTrust’s post implies they triggered the overflow by randomly modifying the ECC signature, though I believe this is unlikely and was just a safer alternative to disclosing exactly how to trigger the exploit. It was possible for me to achieve remote code execution with either ASLR or DEP disabled, but on a system with both  it would prove quite a challenge, thus I’m not too worried about detailing exactly how to trigger the overflow.

DecodeSigAndReverse

We already know the function in which the overflow occurs, so I decided to work backwards from there. This function is responsible for decoding the ASN.1 (DER) encoded ECC signature and returning it to be verified.

DecodeSigAndReverse assembly code 1

The first thing that is done here is the ECC signature is passed to CryptDecodeObject in order to calculate the total size of the decoded signature, which is used to allocate some memory using SPExternalAlloc (LocalAlloc Wrapper). CryptDecodeObject will always handle the signature correctly, with the returned size being sufficient.

DecodeSigAndReverse assembly code 2

CryptDecodeObject is now called again, but this time it is passed a pointer to the allocate memory in which to copy the decoded signature. The “cmp ebx, 2Fh” checks the signature type (X509_ECC_SIGNATURE) and will direct the code to the left.

The decoded signature is pointed to by an ECC_SIGNATURE header, which is 12 bytes in size an looks something like this.

CERT_ECC_SIGNATURE structure

What R and S are doesn’t really matter here, all we need to know is they are extremely large integers. Our ECC structure now contains the size of each integer and a pointer to where it’s stored.

The 2 memcpy operations should be pretty obvious now, the first one copies rSize bytes from R to some allocated memory, then the second copies sSize bytes of S to the same memory directly after R; If there’s going to be an overflow It’s going to be in the second memcpy. What we don’t yet know is the size of the destination memory or how it’s allocated.

CheckClientVerifyMessage assembly code

All I had to do to find where the memory gets allocated was to look at the call graph, find the function responsible for coding DecodeSigAndReverse, then scout it for the “Dst” parameter.

This is where everything goes right (or wrong if you’re Microsoft). _BCryptGetProperty is being passed “KeyLength” to… Drum roll please…. get the key length. Directly below that length is being divided by 8 (converted from bits to bytes) then doubled; this is due to the fact the signature length is (should be) double the key length. Just before the call to DecodeSigAndReverse we can see that the destination buffer is also allocated on the heap.

DecodeSigAndReverse assembly code 2

So back at the 2 memcpys now with knowledge of the destination buffer size, we can see exactly what triggers the heap overflow. If we use a key size of 256 bit (32 bytes), then the function is expecting a 512 bit (64 byte) signature, any more will overflow the heap and when it’s freed cause a crash.

There are very few constraints on the signature, due to the fact the whole thing is just 2 massive integers. As long as we maintain a valid ASN.1 (DER) encoding and the signature is of valid size, we can write arbitrary data to the heap header resulting in an access violation or even remote code execution when the system tries to free the memory.

Vulnerability Research
BlueKeep: A Journey from DoS to RCE (CVE-2019-0708)

Due to the serious risk of a BlueKeep based worm, I’ve held back this write-up to avoid advancing the timeline. Now that a proof-of-concept for RCE (remote code execution) has been release as part of Metasploit, i feel it’s now safe for me to post this. This article will be …

Vulnerability Research
DejaBlue: Analyzing a RDP Heap Overflow

In August 2019 Microsoft announced it had patched a collection of RDP bugs, two of which were wormable. The wormable bugs, CVE-2019-1181 & CVE-2019-1182 affect every OS from Windows 7 to Windows 10. There is some confusion about which CVE is which, though it’s possible both refer to the same …

Vulnerability Research
Analysis of CVE-2019-0708 (BlueKeep)

I held back this write-up until a proof of concept (PoC) was publicly available, as not to cause any harm. Now that there are multiple denial-of-service PoC on github, I’m posting my analysis. Binary Diffing As always, I started with a BinDiff of the binaries modified by the patch (in …