Archive for April, 2008

It all comes back to the basics

April 29th, 2008 by Samuel Bucholtz

Recently there has been a lot of talk in the security community about the Flash ActionScript exploit written by Mark Dowd (http://documents.iss.net/whitepapers/IBM_X-Force_WP_final.pdf). I will not go into a breakdown of the exploit as others have already done a great job of blogging about it. What I would like to discuss is two big takeaways that even programmers who are not "uber-hackers" can appreciate.

The first takeaway is the importance of understanding and implementing the fundamentals. The exploit above occurs because of a NULL dereference triggered by an out of memory return by malloc(). I remember in my first C programming class when I was working with a partner an a project and he was trying to properly implement malloc(). I had already been using C for a few years and always checked the return of a function. I could not figure out why he was not checking to make sure sufficient memory had been allocated. He gave me the excuse that it would require a lot of code to check the return value and that since the data structure was small the allocation would fail. Nonsense, as I demonstrated by filling up the 640K of standard memory. He then argued that we would be better off implementing XMS or EMS to access the other 3MB of "high" memory, a silly argument if ever there was one.

When non-security professionals describe what hackers do they often say that hackers look for ways to bypass restrictions and go around roadblocks. This is a somewhat fair description, but what they may not know is that often hackers are merely taking advantage of mistakes or the faulty reasoning of programmers who tried to skip or work around something simple or basic that they felt would be too much work to implement properly. The original "hacks" were simply ways of getting things done quicker, easier, or more elegantly but sometimes there is a fundamental reason for doing things one way and the "hack" just gets you into hot water. Anyone who has ever picked up a C programming book and looked at the function info for malloc() knows that it is NOT guaranteed to return the memory requested. Obviously, it is a BAD idea to simply assume that it succeeded in allocating all the memory requested. Know your functions/methods and how to properly implement them.

The second takeaway for the average programmer is the need to integrate and leverage the latest in security functionality in your code from the ground up. What do I mean by this? Follow-up research on the exploit has shown that if DEP had been turned on and opted-in the exploit would not have worked. DEP marks portions of memory as NX (No Execute). Such areas in memory will trigger a processor fault if an attacker attempts to execute shellcode they have somehow loaded into such memory. Is DEP a panacea- No. But it provides a second layer of defense. Now you might say- DEP is a system setting that users or admins or Microsoft can turn on or off, there is nothing I can do as a programmer. This is not true. First of all, you need to write your application to make sure it works properly with DEP turned on. You need to test your application to verify this. You need to inform users so they know they can safely use DEP with your application.

A number of other features like ASLR (Address space layout randomization), /GS (canary based buffer overflow detection), etc. are provided now by Visual Studio and other compilers or by the latest versions of the Windows operating system. Developers should be building their code to use these basic security tools that are in most cases so easily integrated. None of these features can prevent all security threats, but there are many applications out there using outdated compilers or failing to implementeven the simplest of automated defenses for lack of awareness or a fear of performance degradation. To the former- browse through just a few of the numerous security respurce out there and then review your compiler/linkers security related flags; to the latter- given the massive code bloat in this object oriented development world compared with the (good) old days of hand tuned assembly in a COM file what is a one or two percent more overhead :) .

How safe is the safecrt handling of formatting strings?

April 25th, 2008 by Jordan Tigani

One rule of thumb in c/c++ is that you should never let the user be in control of a formatting string. This has been recognized as a security bug for years, and one that has been mostly cleaned up since it is so easy to identify and fix. With visual studio 2005, Microsoft released a safer version of the crt — functions that end with _s to tell you that they are security enhanced. So let's say you are being a good security citizen by using the safe-crt …. can a format string vulnerability (where the user controls the format string) still be exploited?

The MSDN docs don't really have the answer. A cursory reading of the “security enhancements in the CRT” page as well as others may lead you to believe that format string vulnerabilities are a thing of the past. One example shows a call to 'sprintf_s(buf,_countof(buf), “%s”,NULL)' and remarks that this results in a runtime error. Looks like they do some kind runtime-validation. However, unless they added magic pixie dust to their compiler that sends cosmic rays from outer space to fix up malicious format strings at runtime, it isn't really possible to have strongly-typed printf-style format strings in C.

So let's investigate how far the parameter validation will get you. Here is a little sample program I wrote to send nasty format strings to sprintf_s:


#include
#define OUT_SIZE 0x1000
int main(int argc, char** argv) {
char * out = new char[OUT_SIZE];
sprintf_s(out, OUT_SIZE, OUT_SIZE, argv[1]);
printf("%s\n", out);
return 0;
}

So let's try this with a couple of format strings:

Input: "%s"
Output: Error: ("Buffer too small", 0)

So far so good… but buffer too small?
What about just dumping stack variables?

Input: "%p %p %p %p %p %p"
Output: 00344FD0 00344FD0 0012FFB8 004019D3 00000002 00343728

Interesting… so looks like this type checking is not so robust after all. We've just dumped the stack.
Let's see if we can crash the program. Looks like there is a 0000002 on the stack… that probably won't appreciate being dereferenced.

Input: "%p %p %p %p %s"


Ok so we can crash the program. Can we do anything more interesting?
Let's say there was some interesting data somewhere in the program. To simulate this, I'll put my bank account number on the stack with the following line of code at the beginning of “main” “volatile char * bankAccount = “Account#123-456-7890″;” (the volatile helps convince the compiler not to throw it away since I don't use it).

Now when I call the function with the right input, I can dump my bank account number:

Input: test.exe "%p %s"
Output: 00344FD0 Account#123-456-7890 00344FD0

Ok but nobody really cares about Denial-of-service and Information-disclosure. Those are sooooo pri-3. Can we use take over the machine? As everyone knows, the hacker's favorite format string character is '%n'. '%n' writes the number of bytes written so far to the param from the stack. Let's try a '%n':

Input: test.exe "%p %n"
Output: Error: (state != ST_INVALID)

Blast! Foiled! It turns out Microsoft decided that %n was too much power, and that we mere mortals couldn't handle it. Good for them. There is an override, but it turns out to not be available using the Safe CRT. The moral of the story? The safe crt is a wonderful and powerful tool to help prevent buffer overruns. But there is no excuse for letting a user control a format string.

Handling Unicode when marshalling from .Net to a platform invoke

April 22nd, 2008 by Chris Weber

By default, the .Net runtime will marshall a string (and files in a value type) as a LPStr to a platform invoke (p/invoke) function. By default the .Net framework and runtime handles strings as UTF-16. That's two bytes representing a single Unicode 'code point', and more familiar, a single character. An LPStr on the other hand, is an ANSI character, so in order to convert, the runtime will perform a best-fit conversion to the classic windows-1252 code page. This conversion is well-documented here:

http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt

This might not be so surprising to people in tune with Unicode, but it's can lead to huge security problems when security filters are at risk. For example, if you're performing HTML filtering or file canonicalization, you need to perform so after the conversion to LPStr.

This default marshalling behavior is documented at: http://msdn2.microsoft.com/en-us/library/system.runtime.interopservices.marshalasattribute(VS.71).aspx

To properly and more safely deal with this, you can use the MarshallAsAttribute class to specify a LPWStr type instead of a LPStr. For example:

[MarshalAs(UnmanagedType.LPWStr)]

Because LPWStr is a pointer to a null-terminated array of Unicode characters, this ensures the Unicode code points are preserved across the marshalling.