Hi,
There's a Linux hardening project called PaX. Few years ago it
introduced some new interesting approaches to security, that over time
proved themselves to be of help when facing mostly unknown threats. The
idea behind this approach is that you design the security of the system
to prevent the exploit, and not the vulnerability.
The PaX project can be found on the web at
http://pax.grsecurity.net
And detailed documentation about the variety of features it contains,
including some performance benchmarks, can be found at
http://pax.grsecurity.net/docs/
I decided to download the paxtest tool, used to check if the various
features of PaX are working or not. What this tool does is run a few
tests to see if techniques that are commonly used in exploits are
working or not. More on this inline below, in square brackets.
The PaX test-suite can be downloaded from
ftp://ftp.NetBSD.org/pub/NetBSD/misc/elad/paxtest-0.9.7-pre4.tar.gz
Extract it and type "gmake netbsd" to build the paxtest tool, then use
it as "./paxtest blackhat".
The attack techniques this test suite checks for are
1. If anonymous mappings, or the bss/data/stack/heap sections of a
binary, are executable by default. If they are, it means the most
basic buffer overflow exploits will work.
2. If it's possible to make previously executable mappings writable,
or previously writable mappings executable. While this is standard
operation, it's a technique used to bypass W^X and the likes, and
can be seen in several modern exploits.
3. Amount of randomization in mappings each time a program starts.
The more predictable the mappings are, the easier it is to perform
attacks that require jumping to a known address - like ret-to-libc
for example, used also to bypass W^X.
Note: While SSP may also help in preventing these ret-to-libc
attacks, this is another layer that should be considered, where the
two can provide more coverage against this type of attack.
4. Return-to-lib attacks via string manipulation routines. If shared
libraries are mapped where the address of functions in them have
a NULL byte it means that the attacker can't (easily) use a
return-to-lib attack to get to them, because the input used to
overflow must be ASCII armored.
5. Same as above, only this time the overflow is made in a routine
that isn't affected by a NULL byte. SSP should be able to stop
these attacks.
6. Checks if code in the data/bss segments of a shared library can be
executed.
7. Checks if it's possible to map text segments as writable. Another
form of the attack in #2.
The goal, of course, is to pass all tests in this suite.
Here's output from a (slightly modified version of) paxtest run on my
NetBSD machine:
phyre:paxtest-0.9.7-pre4 {319} ./paxtest blackhat
PaXtest - Copyright(c) 2003,2004 by Peter Busser <peter@adamantix.org>
Released under the GNU Public Licence version 2 or later
Writing output to paxtest.log
It may take a while for the tests to complete
Test results:
PaXtest - Copyright(c) 2003,2004 by Peter Busser <peter@adamantix.org>
Released under the GNU Public Licence version 2 or later
Mode: blackhat
NetBSD phyre.bsd.org.il 3.99.14 NetBSD 3.99.14 (GENERIC) #14: Sun Dec 11
23:00:39 IST 2005
elad@phyre.bsd.org.il:/usr/netbsd/src/sys/arch/amd64/compile/obj/GENERIC
amd64
Executable anonymous mapping : Killed
Executable bss : Killed
Executable data : Killed
Executable heap : Killed
Executable stack : Killed
[ #1. That's good. On architectures where there's no NX bit,
these would be vulnerable too. i386, for example. ]
Executable anonymous mapping (mprotect) : Vulnerable
Executable bss (mprotect) : Vulnerable
Executable data (mprotect) : Vulnerable
Executable heap (mprotect) : Vulnerable
Executable shared library bss (mprotect) : Vulnerable
Executable shared library data (mprotect): Vulnerable
Executable stack (mprotect) : Vulnerable
[ #2. While to not be vulnerable to this attack we need to
change semantics of mprotect(), doing this based on a sysctl
knob might be a good idea.
The performance cost of adding this protection is ~zero,
because it's a matter of testing for flags. ]
Anonymous mapping randomisation test : No randomisation
Heap randomisation test (ET_EXEC) : No randomisation
Main executable randomisation (ET_EXEC) : No randomisation
Shared library randomisation test : No randomisation
Stack randomisation test (SEGMEXEC) : No randomisation
Stack randomisation test (PAGEEXEC) : No randomisation
[ #3. Randomization hooks could fix these. ]
Return to function (strcpy) : paxtest: return address
contains a NULL byte.
Return to function (strcpy, RANDEXEC) : paxtest: return address
contains a NULL byte.
[ #4. That's good. Is this on purpose? :) (no) ]
Return to function (memcpy) : Vulnerable
Return to function (memcpy, RANDEXEC) : Vulnerable
[ #5. SSP fixes this one, as well as #4. ]
Executable shared library bss : Killed
Executable shared library data : Killed
[ #6. That's good, but again, not on all architectures. ]
Writable text segments : Vulnerable
[ #7. Same note as #2. ]
phyre:paxtest-0.9.7-pre4 {320}
As you can see, NetBSD is not doing too well in these tests. While there
could certainly be a performance/functionality penalty in fixing some of
these -- namely, the randomization and mprotect() ones -- I feel we
should leave the choice to the users to decide (whether to enable or
not).
What I would like to discuss is the possibility of importing two
important features from PaX -- ASLR and MPROTECT.
I've CC'd this mail to the PaX author, who knows about this stuff a lot
more than I do (and is in general a very cool dude :) so he could give
his comments during the discussion; please CC him on replies as well.
Thanks,
-e.
--
Elad Efrat