Some interesting comments on pro-active security appeared on the daily dave just now. http://lists.immunitysec.com/pipermail/dailydave/2004-September/000918.html Pasted for your convenience: [Dailydave] Theo's presentation on exploit prevention pageexec at freemail.hu pageexec at freemail.hu Theo's presentation on exploit prevention or the siren [1] sang again. lest we die in ignorance though, let's look at that song. slides 1-2: we're getting lured into the belief that something genuine is going to happen here. we're about to learn how the OpenBSD project smartened up finally and copied the intrusion prevention technologies that others had developed in the previous few years and more! we're promised a much more hostile system environment and backwards compatibility, no less. one begins to suspect why the stupid greek sailors all died in the end. slide 3: here we learn in more detail about the noble goals of this effort. it's not quite clear how one's supposed to not break behaviour that the apps depend on while still prevent the exploits from making use of the same behaviour... but let's not rush ahead so fast. we're going to follow POSIX and still do nasty nasty things to those attackers - or so the song promises. slides 4-5: let's cut to the meat! buffer overflows. to add insult to injury, it's the stack based ones. oh, not THEM again. we thought we'd been past that for years now! while marveling at the beauty of the 1000th buffer overflow depiction we keep wondering when the OpenBSD Team will eventually learn about the clever attacker that is exploiting more than buffer overflows. anyway, let's look at this old buddy again. we learn that the buffer is ALWAYS at the same place. how nice. how secure. stuff like environment strings, program arguments and whatnot surely have no role in the stack pointer value. apparently not on OpenBSD. proactive insecurity, isn't it. so what shall we do about it? shift the stack by a random amount! where, how, how much? apparently on OpenBSD the top of the stack is what normal mortals consider the bottom of it... honest to god mistake, we understand where the real gap is. at the bottom. no pun intended. and then look at those failures! all due to that unbelievable 15 bits of randomness OpenBSD managed to cram into that space! and we learn that all this costs us at most one physical page of RAM. what we don't learn is that it also costs us 256 kB of virtual address space (or more precisely, whatever our admin deemed acceptable for his sense of security), but we have got plenty of that and as we'll see later, it's a drop in the water only (we're sailors, don't miss the pun!) compared to what will follow later. so, what is 15 bits of randomness worth really? at one attempt a second, it's less than half a day on average (assuming we're actually going for the full 15 bits and can't get away with less), for stuff that forks only it's even guaranteed in that time. on localhost it's a matter of minutes. and you're wondering why other vendors haven't picked it up (one wonders where OpenBSD picked it up from). maybe because they can count further than 15. what about 24, or 32 or whatever the address space reasonably allows? sounds better, doesn't it. slide 6: here we learn about the fantastic japanese stuff (great sailors of their time) that many in the world, including OpenBSD, have blissfully ignored for... a few years at least. but now they have rediscovered the precious, and it's all theirs and theirs and... we get this stack overflow focus again. the one ring that binds them all. and we forget about information leaking bugs that render this and other randomization based approaches pretty vulnerable to attack. we also forget about localhost where we get unexpected help for this: the kernel (and the nice bugs in it). the best use of SSP is in the kernel itself. having a single canary value sitting like a duck for the uptime of the system is the best idea men, err, sirens could come up with. having it change per process and syscall crosses only the minds of mad sailors. slide 7: we can see that SSP found a few exploitable bugs. but where are the advisories? surely not swept under the carpet, right? slides 8-9: W^X! no, we didn't want to curse at you, honest! this pearl is the OpenBSD attempt at PaX a few years late ([2], [3]), and on the surface it actually does what it promises: separate writable (not writeable) pages from executable ones unless the program Wants Just That. problem is that as any female reader can attest, a boy Wants Just That. including those badass blackhats who dare to challenge the security of OpenBSD. and since the OpenBSD Team made it the policy to obey the program's wishes, they stand a chance to actually wish something very pleasant. no, not that (that fish is thorny, not horny), just a r00t shell or the like. but let's do things at their own pace. slides 10-15: we've got a bunch of messy diagrams here, no wonder no sailor has ever found his way back from here. looks like the author got lost too and confused things like ctors/dtors with the C++ language constructs (__attribute__((constructor)) is not at all equivalent to C++ class constructors). first we see that the black sheep in the family a.k.a. the stack (it can't even identify its own bottom as we saw above) is executable. and all that because someone put the signal trampoline there. so they move it to its own page, adding a whole bunch of logic to the kernel instead of figuring out that libc could very well host it in its own .text, not unlike how any Linux system has been doing it for a few years now. then come other evil animals that also host writable and executable pages. getting rid of them is a matter of splitting them up into their own pages so they fall into either of the allowed categories. or change between them. as the runtime linker or the application (read: attacker) wish. not to mention that mprotect'ing the GOT/PLT on every lazily resolved entry must surely be a huge performance benefit and clearly superior to the PT_GNU_RELRO approach preferred by RedHat [4]. last but not least we get to hear about the sad story of i386 where per-page non-executable rights are just an impossibility. they seriously mean it. look at that monster address space layout. if you consider the fragmentation and waste you realize that the 256 kB stack gap pales in comparison. while not exactly the semantics one would expect under POSIX, we'll happily forgive it because this implementation offers us a true gem. the userland code segment comes in only two sizes, and while most people learn early to not put all their eggs in one basket (both code segment descriptors in the GDT), this old adage has apparently fallen on the collective deaf ears of the OpenBSD Team. so what this allows our hypothetical attacker to do is a simple return to a 'retf' instruction that will further return to the injected shellcode in the all-executable code segment... voila, proactive security at its best. slides 16-17: here we are told that i386 is not all that bad provided one uses its 64 bit cousin and learns to program in PAE mode. apparently the latter is a serious challenge for the OpenBSD Team (read: they couldn't just lift the code from FreeBSD). so the sirens are now trying to lure the unsuspecting vendors into implementing yet another way of doing non-executable pages, as if it wasn't already messy enough. slide 18: so what did W^X buy us? security! performance! compatibility! we! all! believe! in! sirens! obviously something's wrong here. security concerns were discussed above, performance numbers can be hardly argued without actually having them... so let's see compatibility. nothing breaks. sure, X didn't break either then. including its homegrown module loader that every non-executable page implementation ran into over time. and there're no OpenBSD specific defines for this reason in the X module loader code either. 'cos nothing broke. honest. at least it's fixed now. what about JIT engines like in Java? we are told that on split I-D cache systems they would not have worked anyway without proper use of msync and mprotect. weird, i386 has split caches yet it's never ever needed any of these to generate code at runtime. obviously the problem is not the split cache itself but that it's not coherent on every system (and some systems offer simple userland accessible primitives for flushing the caches, no need for expensive syscalls at all). slides 19-20: this one is a true gem as well: library order randomization. we are led to believe that it's a worthwile effort. let's see... 'n' libraries can be loaded in n! order, that's a nice exponential value in 'n' (one would think of more than 'n' bits of extra randomness that an attacker has to get right). question is whether that is its true security value as well or not. considering that an attacker normally wants to use a single library in a ret-to-libc style attack (libc... get it?), we can easily conclude that for this purpose the load order will be 'right' once in every 'n' attempt. that in turn means that all this gained is log(n) bits of extra randomization... hardly worth a mention at all, not to mention its cost in code complexity and performance impact in ld.so. then we're shown the 'wee bit' of virtual address space that is wasted in library base address randomization. heavily fragmented all 256 MB of it. double that as the waste is mirrored above the executable limit as well (most if not all libraries contain both code and data). that's 1/6th of the entire address space. a wee bit understated, indeed. slide 21: confused yet? rhetorical question but see, those dumb attackers really are, no question about it. they're facing incredible amounts of entropy, they can no longer execute their payload, and worst, they are stuck at these classic buffer overflows! of course information leaking bugs are unheard of in siren land, as are non-linear overflows. and the many kinds of memory corruption bugs that the creative human mind comes up with. slide 22: good old mmap randomization (3+ years in PaX), except it doesn't only depend on the presence of MAP_FIXED but also the address hint (non-0 hints above p_vmspace->vm_daddr won't be randomized). slide 23: there is hope! apparently someone did hear about heap overflows and related exploits in the OpenBSD Team. a pity they haven't actually delved in the fine details of it [5], else they would know that adding randomization within a page gives only 2-8 bits of randomness, hardly a challenge. slide 24: this is probably the most useless security feature one can ever come up with. while making .rodata non-executable looks like good housekeeping on the surface, it's pretty useless as a security measure. the readership is challenged to find (or produce) a real-life bug that cannot be exploited except when .rodata is executable. we have yet to see one. we also learn the underlying concept of all these address space tweaks: the noble goal of least privilege. except the security-challenged OpenBSD Team doesn't know that memory protection rights come in pair: one set defines the active permissions and another the attainable ones. restricting the former only while leaving free reign over the latter means that it is possible to circumvent the former. and it wasn't until 3.4 where one could call mprotect() with random stack garbage as arguments and have the kernel still accept the protection flags it knew about and ignore the rest. slide 25: besides the usual trashing of the quality of "Open Source" (one wonders if it applies to OpenBSD as well then), we note that there is a reason why ElectricFence is not used in production, it just kills performance due to the heavy address space fragmentation. and this thing is at least a decade old... does everything take this long to be 'discovered' in the OpenBSD world? slides 26-27: this is a cool hack! it's not quite clear though what advantage it has over SSP given that they both detect the same kind of attacks. and we are of course forever indebted for the reference to PaX [3], in those hard days when the OpenBSD Team hadn't heard of us for another year or two. seriously. they said so therefore it must be true. slides 28-32: least privilege again, this time of more mundane ones, not memory access rights. of the two methods, privilege revocation does actually make sense however privilege separation (not seperation) doesn't. for noone has a bugfree kernel. especially not OpenBSD that wasn't written from scratch by its maintainers who have often little idea what a given piece of code does. examples like the improper use of the i386 GDT mentioned above and other (sometimes not yet public) snafus clearly prove the point. so what does a kernel bug do? a good one will allow the skilled attacker to run his code with kernel privileges (say ring-0 on i386) and effectively circumvent anything that the OpenBSD Team have dreamt up for protection. in other words, it doesn't matter where you shift the buggy code, it can already exploit any of the kernel bugs to gain whatever privileges the attacker needs. put that into the second stage of a normal remote exploit and you're back at square one, remote root, whatever way you look at it. slides 33-34: finally, we can see the difficulties facing the defenders: - no clear concept let alone implementation against exploits of memory corruption bugs (tree vs. forest problem), effectively you can never be sure if a given bug is exploitable under these measures and what kind of damage it can cause, - performance and compatibility information is unreliable, you're still best off by simply testing it yourself, that's especially important for 3rd party apps that might break due to the unconventional address space layout and memory protection semantics, - exploitable bugs are fixed silently, how to learn to update then? this concludes our odyssey and for the rest of you, happy sailing! just don't forget the earplugs when the sirens begin to sing. [1] http://dictionary.reference.com/search?q=siren [2] http://marc.theaimsgroup.com/?l=openbsd-tech&m=97416533704634&w=2 [3] http://stackghost.cerias.purdue.edu/stackghost/node32.html [4] http://people.redhat.com/drepper/nonselsec.pdf [5] http://www.blackhat.com/presentations/bh-europe-03/BBP/bh-europe-03-bbp.pdf