Buffer Overflow (also called buffer overrun) is a common cause of security meltdown. And recently, in April 2004, an article in ComputerWorld?
cited an example where a commercial security products itself got compromised by an attack on this vulnerability.
The result? Up to 20,000 computers got damaged through a product designed to protect computers.
Not being a security person myself, I wonder if buffer overflow is such a common problem, why with all those XP and other quality processes, we still get knocked out time and over again by the same type of problem.
Well, buffer overflows are not always the obvious variety. Frequently, a BufferOverflow
is preceded by some other kind of SecurityExploit?
, like an IntegerOverflow?
, which causes a read loop to go insane on what it's expecting. You actually still see the classic buffer overflows (things like gets), but now-a-days most of them are more subtle. In the end, it seems the surest way to avoid a StackOverflow
, or PrintfOverflow?
is to use a language that doesn't allow you to really touch the raw pointers, or one that will allocate memory as needed to assure that user data never ends up anywhere that it shouldn't be. -- DaveFayram
Buffer Overflows are especially easy on the x86 architecture. With variable-width instructions (and a single-byte NOP instruction), alignment problems are much easier to cope with on the x86. Often times , a buffer overflow will take within the first shot if the attacker does their homework. Other architectures provide slightly more resistance. The PowerPC architecture is an example of one that is harder to BufferOverflow
Most architecture that have fixed-width instructions are harder to overflow than ones that do not. In the case of the x86, you must determine the alignment of the return address and the address you are jumping to (which typically is the shellcode you inserted after the return address). The alignment of the instructions is irrelevant because you provide a "NopSled?
", which is a long array of NOP instructions to acquire alignment. In architectures that lack this feature, you must not only hit your ShellCode?
, but hit it with the right alignment.
If you can see the stack frame in memory, this is easy, but when you are inferring information about it from what you know of other architectures, other test cases, and other information (perhaps from a PrintfOverflow?
), it can get appreciably more difficult.
On the PowerPC, the top stack frame doesn't keep its own return address, that is held in a special purpose register. Frames underneath (or above, depending on your perspective) the current frame do keep their return addresses on the stack, and so these frames can be targeted. This means that the current function AND the one calling it must return for a StackOverflow
to kick in. In some cases, like fork(2)'d daemons that handle requests, it may never actually happen.
To further digress about BufferOverflow
s on the PowerPC, Motorolla's implementation of the PowerPC (the G3 and G4 in Apple terms) followed the spec, but allowed "reserved" bits in instructions to hold any value. This might have reduced the cost of the chips slightly, but it also meant that BufferOverflow
s became possible on the PowerPC. One of the tricks of building a good ShellCode?
is to make sure no null bytes (and in some cases, no carriage return or linefeed bytes) exist in the ShellCode?
. This would be very difficult in the PowerPC instruction set, if it were not for Motorolla allowing bits in some instructions to go to any value. The NOP instruction is particularly important for making an easy-to-use ShellCode?
Are buffer overflows the result of using too low-level data structures? If this is done for speed, then perhaps now is the time when security is more important than speed. Time to use higher-level libraries that can detect problems and degrade more gracefully.
As of right now, I really don't know if IBM's PowerPC970 (Apple G5) allows these bits to float or actually enforces them being 0 or not, so I can't say for certain if the PowerPC970 (and FX) are more resistant to buffer overflows than their cousins from Motorolla. -- DaveFayram
A common fault in programs (especially those written in CeeLanguage
?) where input data overflows the area in memory allocated to it. This fault is commonly exploited by crackers and ScriptKiddies?
For issues specifically related to the CeeLanguage
, see CeeLanguageAndBufferOverflows
For more information on buffer overruns, and how they are exploited, see the infamous SmashingTheStackForFunAndProfit
How does one patch or prevent a Buffer
From the start - don't stuff more bytes into a buffer than it can hold.
More specifically (this applies to C/C++; a lot of these problems don't occur in other languages):
The best way to avoid buffer overruns and the related list overruns and list jams is to make a religion of testing your boundary conditions, testing your boundary assumptions and, most important, any programmer whose code allows them should be subjected to the most severe ridicule and humiliation the team's culture will allow. Dunce caps are easy to make and very effective.
- If writing code in C++, use the string class rather than char for strings whenever performance isn't a priority.
- Never use gets() -- always use fgets()
- Never use sprintf(), use snprintf() instead
- Never use strcpy(), use strncpy() instead
- Never use strcat(), use strncat() instead
- Never use printf (foo) to print a raw string; always use printf ("%s", foo). Especially important if foo is a string generated by a user. One class of attacks is to embed nasty formatting controls (like %n) in a string, trying to cause a buffer overflow. (See FormatStringVulnerability?)
- If you have to use char rather than string, keep track of your buffer lengths.
- Never assume a 4K or other size buffer is "long enough"... chances are it won't be.
- Use dynamic char buffers, and DoubleAfterFull to maintain good performance.
A number of projects have attempted to find a more systematic way of preventing buffer overflow exploits (or at least, making them much more difficult). The OpenBsd
project has been particularly productive, with a number of innovative techniques being introduced in OpenBsd
- The OpenBsd kernel randomises the stack gap. This means that attackers may need thousands of guesses to get a correct offset into the stack, and therefore a working exploit.
- OpenBsd has a modified version of gcc that includes ProPolice? StackProtection?. This uses DeadCanary values to detect attempted buffer overflow attempts, and terminate offending processes.
- OpenBsd also incorporates various tweaks to read, write, and execute permissions on memory pages that can significantly increase the difficulty of exploiting a buffer overflow.
2002 includes some similar stack protection. That protection was enhanced in VS 2003, and further enhanced in the (yet unreleased) VS 2005. VS 2005 was used to build Windows XP SP2, making SP2 even more secure.