August 23, 2015

In this post I'm writing about memory corruption in fully managed C# code. On the internet, many people advocate that managed C# should be immune against memory corruption. Even reputable organizations mention the same but provide no reference so people can't check the source of the information for themselves.

An access violation occurs in unmanaged or unsafe code when it attempts to read or write to memory that has not been allocated, or to which it does not have access.

This is quite true, however, AccessViolationException can be originated from fully managed code, too.

In the past months, I was doing some C# development, and during the testing, I experienced several times that my app had terminated with the sign of memory corruption:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

It looks this error is commonly seen in the search result.

Memory Corruption

I did a bit of research on this topic, and wrote a simplified testcase for one of such corruption. I sent it to the people at MSRC. When they finished their investigation I received a reply from them:

We have successfully reproduced the issue and can confirm that the memory corruption is happening within the application itself and not the system. As such, this does not appear to be a security issue and I will be closing this case.

The statement above is a bit vague but this is my understanding of what it means.

If there is a C# API that's designed to handle untrusted data (such as a decompression API) and there is a memory corruption bug in the way the API handles the data the bug may be a security issue, and so it has to be fixed by Microsoft.

However, if the bug is triggered due to an erroneous use of the C# API, such as a non-sanitized parameter is supplied, then the bug is considered to be fixed in the application.

Whether the bug is in the system or application you can end up corrupting the memory in the process so it can affect the security of your app. Despite this the bug may not be qualified for a fix in the .NET framework.

.NET framework manages the memory to eliminate the memory problems but this doesn't guarantee that it eliminates all the memory problems. Memory corruption in fully managed C# is possible.

Testcase

The testcase is a Visual Studio 2013 project that reproduces the memory corruption on Windows Phone 8.1 device and Windows Phone 8.1 Emulator.

The testcase creates an array of pixels with the use of IRandomAccessStream, BitmapEncoder and Stream. When checksumming the bytes in the array the checksum changes every time the vulnerability is triggered.

Checksumming is simple like this (the idea is borrowed from one of the public Flash infoleak made by Chris Evans).

int checksum = 0;
foreach (byte i in arr)
{
checksum += arr[i];
}

Sometimes the testcase crashes with AccessViolationException but most of the time it's observed that the app continues to run after the memory corruption.

February 24, 2015

coco.cpp is a simple pintool for code coverage analysis. It comes with the Pin Framework.

The reason I write a post about it is because it's really a simple but well-designed tool. The code coverage information for an executable section is stored in a vector of booleans. Each boolean represents a byte in the executable section. If the boolean is set true it means the corresponding byte has been executed. If the boolean is set false the corresponding byte is untouched.

If you want the tool to produce the code coverage hash just add yourself a call that calculates the hash of the vector of booleans. This works well when the pintool is executed on small programs.

However when working with more complex programs it's possible you notice that different code coverage hashes produced for seemingly similar executions. This is not an error. The code coverage can be different between the executions in the finest graduality sense. One example is when the application exits via different path between the executions.

To filter these differences above you can virtually split the vector into many regions and produce the hash of each region. Now you may see that most of the hashes are the same between the executions.

UPDATE 24/February/2015 No official PIN repository to see coco.cpp but Gunther was kind to share it via Twitter for those want to take a look at without the need to download the framework. Thx!

In Programmer mode (View -> Programmer) when Dec and Byte are selected the minimum value the calculator can accept is -128. It's tricky to enter that value but you can do by the following four key-presses: (1) (+/-) (2) (8). I said it's tricky as you can't type (1) (2) (8) (+/-) because 128 is greater than the maximum value of INT8 that is 127. While it's a bit inconvenience it can be worked around.

To reproduce the bug select Dec and Byte and type -128. Copy it to the clipboard via Edit -> Copy or Ctrl+C. Then paste it via Edit->Paste or Ctrl+V. What happens is -12 is pasted rather than -128, discarding the last digit.

Last digit is discarded when -128 (INT8_MIN) is pasted.

The effect is the same if you copy -128 in Notepad then paste it in Calculator.

While a beeping sound may be heard when pasting, nothing else warns you about the error. Those who muted the speaker may not notice the error. This is especially possible when the value is long in digits (INT64_MIN) and can be easily overlooked.

It's plausible that programmers use INT_MIN values in their calculations as these are commonly used when developing software.

Windows 8.1 is affected by this issue. Other versions are not verified but likely affected.

While this issue is most likely the limitation of the design some may find it embarrassing as a calculator has nothing else to do than to work with numbers without failure.

The issue found when I was recently working on my own calculator for Windows Phone. I realized I had to deal with many corner cases and I checked how these corner cases affect Windows Calculator.

January 11, 2015

Let's assume that an extensive code review had identified the direct security issues and the developers eliminated all. Now the code is free from bugs. How nice to write that. :-)

That would not be the reason to stop code review though. There may be still things to be done to reduce the severity of potential future bugs.

Newly added code can introduce and/or expose issues. The idea is to make changes in the existing code that make the exploitation of a future bug more challenging. This is good to do without introducing new issues like performance degradation, etc.

Given a heap based buffer overflow, one of the common attack scenario is to overwrite a function pointer in any structure. If, however, the function pointer is at the end of the structure, the overflow may:

Not be long enough to overwrite the function pointer

Overwrite the variables preceding the function pointer and so destroy the internal state of the application. This could lead the application to bail out early before the function gets called.

So putting the function pointer as a last item in the structure can make exploitation more challenging.

A more generic suggestion in security point of view is like this. If possible, arrange the variables to have

the sensitive ones at the end of the structure

the ones that can bail the execution out early at the beginning of the structure

January 6, 2015

Sometimes no matter how simple your pintool is when it's run against the target it crashes. Recently I investigated such crash. One of my pintool was randomly crashed/hung/terminated as well as displayed memory errors.

My target was added to EMET (Enhanced Mitigation Experience Toolkit). Also, EMET was running at the time of experiment. I was thinking... what if I stop EMET? I disabled all the mitigations in EMET and stopped its service. Re-launched my pintool and checked if EMET.dll and EMET64.dll are not loaded in the target's process. This time my pintool was running without any obstacle.

Third party programs can make a pintool to crash. Of course, it's not a surprise but it's something to be aware of when working with a pintool.

If your pintool is still crashing you may want to take look at one of my earlier post.