Qualys Blog

www.qualys.com
ses wang

Hunting For Vulnerable Functions In Microsoft Silverlight MS16-006

This week Microsoft released a patch for a critical Silverlight issue, MS16-006, and since I worked on Silverlight signatures in the past it caught my eye. It’s a Remote Code Execution vulnerability which allows attackers to run code of his or her choice on the victim machine. I had a hunch that something more was hiding. I started to analyze it as soon as I finished writing signatures for the existing patch. When I was working on the analysis Kaspersky Lab published a great blog post about the story of this vulnerability.

In this blog, I’m presenting analysis of a different function that was also fixed in the same patch.


Analysis of CVE-2016-0034 and the Patch

Silverlight is powered by the .NET Framework. Microsoft bulletin mentions "malicious decoder that can return negative offsets". Since there were too many files that were changed in the patch, I decided to just google ".net framework decoder" from which I came across mscorlib.dll. I decided to analyze it and below is a screen capture of the diff between the unpatched and patched file:

Patchdiff

In the changed function list, most changes are related to the "GetChars()" function or related calls.   The discoverer from Kaspersky had already reported that the vulnerability existed in “GetChars()“. But I decide to investigate further for any other vulnerable entry points.  I found the System.IO.BinaryWrite_Write_15 function which takes a string as its parameter:

public unsafe virtual void Write(String value)

The “_15” at the end means it’s an overloaded function. System.IO.BinaryWrite Class has multiple function with the same name.

The function first retrieves the member variable _maxChars as follows:

_maxChars = LargeByteBufferSize / _encoding.GetMaxByteCount(1);

The _maxChars variable is a private member of integer in public class BinaryWriter:

private int _maxChars;

The interesting aspect with this variable was that it is an ‘int’ variable and not ‘unsigned int’. What the difference? Well ‘int’ variables can be assigned negative values.

After setting the _maxChars variable, the function code goes into a loop:

int charStart = 0;
               while (numLeft > 0) {
                    // Figure out how many chars to process this round.
                    int charCount = (numLeft > _maxChars) ? _maxChars : numLeft;
                    int byteLen;
                              char* pChars = value;
                    byteLen = _encoder.GetBytes(pChars + charStart, charCount, pBytes, LargeByteBufferSize, charCount == numLeft);

                    charStart += charCount;
                    numLeft -= charCount;
                }

The value of ‘_maxChars’ is passed to the ‘CharCount’ variable if It’s less than ‘numleft’ in line 04. Ahh! That implies that another vulnerability exists while calculating the value of ‘_maxChars’ !!!

_maxChars = LargeByteBufferSize / _encoding.GetMaxByteCount(1);

The first element of the division (LargeByteBufferSize) is 0x100 by default.

Largebuffer

The second element comes from the return value of "_encoding.GetMaxByteCount(1)",

Getmaxcount

GetMaxByteCount(1) is a user overridable function and its return type is int32. This implies that the return value of this function is in the control of the user.  And it can return a negative value.

Let’s say  “_MaxChars” is set to -100 before we enter the loop.

The first time loop is all right. The pointer "pChars + charStart" just points the 0 offset of the String’s buffer (charStart’s initial value is 0).

But after executing charStart += charCount; the charStart will be set to -100;

When _encoder.GetBytes is called the second time, parameter one is pointing to pChars-100;

And the worst part is ‘_encoder.GetBytes’ is another user overridable function. So attackers can control the heap by the offset they want in their function.

Working of the patch

As you can see in the image Microsoft added an extra check after getting the value of _maxChars;

Fix

ldfld int32 System.IO.BinaryWriter::_maxChars

Push the _maxChars into the stack.

ldc.i4.0

Push 0 into the stack. Then compare the 2 values and jumps to the red line section if _maxChars is less than 0. An ‘ArgumentOutOfRange’ exception will be raise. This exception is added to all fixes for mscorlib.dll included in MS16-006.

So if you have set a honeypot or are trying to figure out if you are being exploited by this vulnerability within your organization, you should search for ‘ArgumentOutOfRange’ in your log.

Conclusion

I did the binary diff only with mscorlib.dll. There are many other files which have changed in the patch and I encourage you to go through them if you are interested in digging more. Since this is a serious remote code execution issue,  I suggest you apply the patch as soon as possible.

Leave a Reply