|The following excerpt is from Chapter 1 of "The 19 Deadly Sins of Software Security" written by Michael Howard, David LeBlanc and John Viega. Click for the complete book excerpt series or visit McGraw-Hill to purchase the book.|
Extra defensive measures
Consider additional defensive measures the same way you think of seat belts in your car. Seat belts will often reduce the severity of a crash, but you still do not want to get into an accident. It's important to note that for every major class of buffer overrun mitigation, previously exploitable conditions that are no longer exploitable at all exist; and for any given mitigation technique, a sufficiently complex attack can overcome the technique completely. Let's look at a few of them.
Stack protection was pioneered by Crispin Cowan in his Stackguard product, and was independently implemented by Microsoft as the /GS compiler switch. At its most basic, stack protection places a value known as a canary on the stack between the local variables and the return address. Newer implementations may also re-order variables for increased effectiveness. The advantage of this approach is that it is cheap, has minimal performance overhead, and has the additional benefit of making debugging stack corruption bugs easier. Another example is ProPolice, a Gnu Compiler Collection (GCC) extension created by IBM. Any current product should utilize stack protection.
You should be aware that stack protection can be overcome by a variety of techniques. If a virtual function pointer table is overwritten and the function is called prior to return from the function -- virtual destructors are good candidates -- then the exploit will occur before stack protection can come into play.
Non-executable stack and heap
This countermeasure offers considerable protection against an attacker, but it can have a significant application compatibility impact. Some applications legitimately compile and execute code on the fly, such as many applications written in Java and C#. It's also important to note that if the attacker can cause your application to fall prey to a return into libc attack, where a legitimate function call is made to accomplish nefarious ends, then the execute protection on the memory page may be removed.
Unfortunately, most of the hardware currently available is unable to support this option, and support varies with CPU-type, operating system, and operating system version as well. As a result, you cannot count on this protection being present in the field, but you must test with it enabled to ensure that your application is compatible with a non-executable stack and heap, by running your application on hardware that supports hardware protection, and the target operating system set to use the protection. For example, if you are targeting Windows XP, then make sure you run all your tests on a Windows XP SP2 computer using an AMD Athlon 64 FX processor. On Windows, this technology is called Data Execution Protection (DEP); it was once known as No eXecute (NX).
Windows Server 2003 SP1 also supports this capability. PaX for Linux and OpenBSD also support non-executable memory.
Click for the next excerpt in this series: Other resources
This was first published in September 2005