Wednesday, 7 November 2007

What can stop a Buffer Overflow Exploit - Before it has a chance?

Well actually, we could attempt to fix the stack for a start. Fixing the multitude of programmes and programmers is unlikely and than again new ones are "born" every day. Better training is good, don't get me wrong, but it will not stop the problem.

We should all know that code "usually" resides in a R/O text area at the start of the program memory. In an ideal world our programs will not execute any instructions off of the data stack. [1]

Where the hardware supports it, software can be integrated to stop many of these exploits. On AMD64 and Pentium-4 (and newer) CPU's there is what is called an NX bit. The Linux kernel has had support for the NX bit functionality since 2.6.8. In solaris and HP-UX there are kernel switches for this behaviour on RISC chips (eg noexec_user_stack=1 in /etc/system on Solaris).

OpenBSD has W^X (3.4 up) and the grsecurity ( PaX patches include stack-protection from the Admantix Linux Project. Redhat has "Exec Shield" for this.

With the Risc systems (Solaris, HPUX etc), stack protection prevents executing code off stack pages. This still does not stop heap attacks - but these are another issue.

W^X and PaX (with NX) marks all writable-pages as non-executable - even the heap area and other data areas - not just the stack. The issues come as many high level languages (ie JAVA, JSP etc) execute runtime code out of the heap. Thus these can break Java.

So this is a functionality issue for a start. Many systems (eg Internet DNS) do not need the extended functionality provided by Java and other high level languages. In this case - there is a good case to disable code from running out of the data areas, stack and heap. On the other hand, Users want to browse the web etc and as such they want this added feature (ie no heap protection).

Alternatively there is another option.

There are complier-based solutions. Adding a "Canary" between the frame pointer and return address in order to create code that is resistant to buffer overflows. In this, any buffer overflow exploit that overflows the data area and writes downward to the return address pointer will also overwrite the canary value (I will ignore format string attacks for this as this make the post a little too complex).

In the normal course of program execution, the program will check the canary value. If this has been altered (ie buffer overflow exploit or error) the program aborts rather than returning the memory address given by the return address pointer. This adds an overhead of about 10% to the system, but makes many classical buffer overflows unable to be executed. GCC has this option built in (-fstack-protector & -fstack-protector-all) though they are rarely used. I believe that Novell - from OpenSUSE 10.3 is building this in though I have not tried to break this myself.

So to end - there are a number of options. Some work very well, but all have a cost. This may be an increase performance hit and it may be no Java, but it is possible. So for the original question, PAX helps, but it breaks Java and other pretty user toys.

[R/O = Read Only]
[1 = assuming the readership to be Geeks as well...]

No comments: