Hey there, this is an article I wrote back in 2011 for securityoverride about memory protection mechanisms in linux. Some points may be outdated, like the bit about firefox 0days since UAF bugs have become more popular since and naturally bypass a lot of these protections, but I feel theres still some good points here for those learning about exploit development on linux, or simply want to harden their own system more. So if you see something wrong and/or outdated, please leave a comment pointing it out! Especially if you have references for further reading explaining why in more depth
//intro
Hallo people, first a quick intro about this article. This is going to be all about hardening against
memory corruption attacks. You may commonly know these as 0days, stack overflows, heap corruptions, format strings, ect. Sure code fixing is the main defense but its
reactive defense. It only works after the fact. That fact may be very well that you got 0wned. Aint that the sh*t? Originally I meant this to be about hardening the core OS but after I thought about it, it left out a few compiler based defenses I felt are important. The truth is that if a single a oh-day ruins your day than you FAILED. You have NOT done your job. Thats because nothing but the most top-notch exploit can bypass the modern day mitigations on a linux box, and even then it is highly situational. Also remember that most "hackers" these days are all teeth and no shell. If you got a better shell then you are already ahead. Who knows, maybe you'll learn a thing or two about what it takes to make a real
modern exploit.
*disclaimer* this is not about local kernel 0day protection. My opinion is if youve let them get that far, well f*ck you, you havnt done your job.
//paxtest + checksec.sh
Paxtest and checksec.sh should be your first go-to tools when it comes to evaluating how exploitable* a system is. If you've ever been serious about targeting a box the 'old school way' you know that you try to mirror the target as much as possible. Same kernel, distro, services, ect to play with instead of doing the equivilent of screaming at their network and hoping no one hears you. Thats when you bust out paxtest and checksec.sh, and they are also the first tools you should be using to judge exactly what you need to fix on your box.
Paxtest can be found with a quick google and on my Ubuntu box at least it comes via a nice aptitude install paxtest
Checksec.sh last I've seen can be found at
http://www.trapkit.de/tools/checksec.html First a quick use of paxtest. Paxtest creates and runs several test runs to check what kernel support for memory protections are in place. Run it with sudo paxtest blackhat ((the other option is --kiddie and they return the same result but I suppose back in the day kiddie made 'safer' checks that werent as accurate)) My 'out of the box' Ubuntu returns this for instance:
--snip short useless stuff--
Mode: blackhat
Linux Rigshaw 2.6.32-31-generic #61-Ubuntu SMP Fri Apr 8 18:24:35 UTC 2011 i686 GNU/Linux
Executable anonymous mapping : Killed
Executable bss : Killed
Executable data : Killed
Executable heap : Killed
Executable stack : Killed
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
Anonymous mapping randomisation test : 12 bits (guessed)
Heap randomisation test (ET_EXEC) : 14 bits (guessed)
Heap randomisation test (ET_DYN) : 14 bits (guessed)
Main executable randomisation (ET_EXEC) : 12 bits (guessed)
Main executable randomisation (ET_DYN) : 12 bits (guessed)
Shared library randomisation test : 12 bits (guessed)
Stack randomisation test (SEGMEXEC) : 20 bits (guessed)
Stack randomisation test (PAGEEXEC) : 19 bits (guessed)
Return to function (strcpy) : Vulnerable
Return to function (strcpy, RANDEXEC) : Vulnerable
Return to function (memcpy) : Vulnerable
Return to function (memcpy, RANDEXEC) : Vulnerable
Executable shared library bss : Vulnerable
Executable shared library data : Killed
Writable text segments : Vulnerable
As you can see the kernel protections are pretty sh*t
But wait, Its got NX(linux's dep) and aslr!!! But holy sh*t look at all that other stuff that's vulnerable that can be used to aid in exploitation! And the aslr is crappy as hell!
I bet a vast majority of you are having an exlamation mark above the head going on. Don't worry, it's STILL better then a CentOS or Debian box...
Next is checksec.sh This checks for binary protections of a given file, or optionally some running processes(all if root). Its a very nice complement to paxtest in judging the exploitability of a program assuming that there is a flaw. It can also check kernel defenses with --kernel(but that and fixing it will be an exercise for the reader). Typically you should run it with sudo checksec.sh --proc-all > checksec.log and sit back, it may or may not have a lot of output depending on how many processes you got going on, so it's best to save it somewhere. Again, heres my output for a 'out of the box' Ubuntu:
* System-wide ASLR (kernel.randomize_va_space): On (Setting: 2)
Description - Make the addresses of mmap base, heap, stack and VDSO page randomized.
This, among other things, implies that shared libraries will be loaded to random
addresses. Also for PIE-linked binaries, the location of code start is randomized.
See the kernel file 'Documentation/sysctl/kernel.txt' for more details.
* Does the CPU support NX: Yes
COMMAND PID RELRO STACK CANARY NX/PaX PIE
init 1 Full RELRO Canary found NX enabled PIE enabled
smbd 1031 Full RELRO Canary found NX enabled PIE enabled
getty 1102 Partial RELRO Canary found NX enabled No PIE
getty 1106 Partial RELRO Canary found NX enabled No PIE
getty 1116 Partial RELRO Canary found NX enabled No PIE
getty 1117 Partial RELRO Canary found NX enabled No PIE
getty 1121 Partial RELRO Canary found NX enabled No PIE
acpid 1132 Partial RELRO Canary found NX enabled No PIE
irqbalance 1134 Partial RELRO Canary found NX enabled No PIE
cron 1154 Partial RELRO Canary found NX enabled No PIE
atd 1155 Partial RELRO Canary found NX enabled No PIE
nessus-service 1159 Partial RELRO Canary found NX enabled No PIE
nessusd 1160 Partial RELRO Canary found NX enabled No PIE
mysqld 1176 Full RELRO Canary found NX enabled PIE enabled
wpa_supplicant 1193 Partial RELRO Canary found NX enabled No PIE
privoxy 1292 Partial RELRO Canary found NX enabled No PIE
gdm-binary 1296 Partial RELRO Canary found NX enabled No PIE
console-kit-dae 1309 Partial RELRO Canary found NX enabled No PIE
gdm-simple-slav 1374 Partial RELRO Canary found NX enabled No PIE
Xorg 1386 Partial RELRO Canary found NX enabled No PIE
tor 1486 Partial RELRO Canary found NX enabled No PIE
winbindd 1527 Full RELRO Canary found NX enabled PIE enabled
winbindd 1552 Full RELRO Canary found NX enabled PIE enabled
dbus-launch 1572 Partial RELRO Canary found NX enabled No PIE
gdm-session-wor 1593 Partial RELRO Canary found NX enabled No PIE
upowerd 1595 Partial RELRO Canary found NX enabled No PIE
hald 1598 Partial RELRO Canary found NX enabled No PIE
hald-runner 1599 Partial RELRO No canary found NX enabled No PIE
hald-addon-inpu 1624 Partial RELRO Canary found NX enabled No PIE
hald-addon-rfki 1628 Partial RELRO Canary found NX enabled No PIE
hald-addon-leds 1629 Partial RELRO Canary found NX enabled No PIE
hald-addon-gene 1637 Partial RELRO Canary found NX enabled No PIE
hald-addon-stor 1643 Partial RELRO Canary found NX enabled No PIE
hald-addon-cpuf 1645 Partial RELRO Canary found NX enabled No PIE
hald-addon-acpi 1646 Partial RELRO Canary found NX enabled No PIE
polkitd 1657 Partial RELRO No canary found NX enabled No PIE
cupsd 1721 Full RELRO Canary found NX enabled PIE enabled
getty 1800 Partial RELRO Canary found NX enabled No PIE
winbindd 1804 Full RELRO Canary found NX enabled PIE enabled
gnome-keyring-d 1830 Partial RELRO Canary found NX enabled No PIE
gnome-session 1848 Partial RELRO Canary found NX enabled No PIE
ssh-agent 1961 Full RELRO Canary found NX enabled PIE enabled
dbus-launch 1964 Partial RELRO Canary found NX enabled No PIE
dbus-daemon 1965 Partial RELRO Canary found NX enabled PIE enabled
gconfd-2 1968 Partial RELRO Canary found NX enabled No PIE
gnome-settings- 1975 Partial RELRO No canary found NX enabled No PIE
gvfsd 1977 Partial RELRO Canary found NX enabled No PIE
gvfs-fuse-daemo 1982 Partial RELRO No canary found NX enabled No PIE
metacity 1987 Partial RELRO Canary found NX enabled No PIE
pulseaudio 1989 Full RELRO Canary found NX enabled No PIE
rtkit-daemon 1991 Partial RELRO Canary found NX enabled No PIE
sh 1994 Partial RELRO Canary found NX enabled No PIE
netbook-launche 1996 Partial RELRO Canary found NX enabled No PIE
gnome-power-man 1999 Partial RELRO Canary found NX enabled No PIE
polkit-gnome-au 2001 Partial RELRO No canary found NX enabled No PIE
gnome-panel 2004 Partial RELRO Canary found NX enabled No PIE
rhythmbox 2007 Partial RELRO No canary found NX enabled No PIE
gnome-terminal 2008 Partial RELRO Canary found NX enabled No PIE
evince 2009 Full RELRO Canary found NX enabled PIE enabled
nm-applet 2011 Partial RELRO Canary found NX enabled No PIE
nautilus 2012 Partial RELRO Canary found NX enabled No PIE
yakuake 2013 Partial RELRO No canary found NX enabled No PIE
gconf-helper 2020 Partial RELRO Canary found NX enabled No PIE
gvfs-gdu-volume 2022 Partial RELRO Canary found NX enabled No PIE
udisks-daemon 2026 Partial RELRO Canary found NX enabled No PIE
udisks-daemon 2027 Partial RELRO Canary found NX enabled No PIE
gvfs-gphoto2-vo 2029 Partial RELRO Canary found NX enabled No PIE
gvfs-afc-volume 2031 Partial RELRO No canary found NX enabled No PIE
evinced 2034 Full RELRO No canary found NX enabled PIE enabled
gnome-pty-helpe 2040 Partial RELRO Canary found NX enabled No PIE
bash 2041 Partial RELRO Canary found NX enabled No PIE
bonobo-activati 2044 Partial RELRO Canary found NX enabled No PIE
gnome-screensav 2046 Partial RELRO Canary found NX enabled No PIE
go-home-applet 2054 Partial RELRO No canary found NX enabled No PIE
indicator-apple 2056 Partial RELRO No canary found NX enabled No PIE
clock-applet 2058 Partial RELRO Canary found NX enabled No PIE
indicator-apple 2060 Partial RELRO No canary found NX enabled No PIE
notification-ar 2063 Partial RELRO Canary found NX enabled No PIE
window-picker-a 2064 Partial RELRO No canary found NX enabled No PIE
gvfsd-trash 2085 Partial RELRO Canary found NX enabled No PIE
gdu-notificatio 2090 Partial RELRO No canary found NX enabled No PIE
syndaemon 2095 Partial RELRO Canary found NX enabled No PIE
gvfsd-metadata 2133 Partial RELRO Canary found NX enabled No PIE
indicator-me-se 2136 Partial RELRO No canary found NX enabled No PIE
indicator-sessi 2139 Partial RELRO No canary found NX enabled No PIE
indicator-appli 2144 Partial RELRO No canary found NX enabled No PIE
indicator-sound 2146 Partial RELRO No canary found NX enabled No PIE
indicator-messa 2148 Partial RELRO No canary found NX enabled No PIE
gvfsd-burn 2151 Partial RELRO Canary found NX enabled No PIE
notify-osd 2217 Partial RELRO Canary found NX enabled No PIE
python 2250 Partial RELRO Canary found NX enabled No PIE
kdeinit4 2260 Partial RELRO Canary found NX enabled No PIE
klauncher 2263 Partial RELRO Canary found NX enabled No PIE
kded4 2265 Partial RELRO Canary found NX enabled No PIE
kglobalaccel 2270 Partial RELRO Canary found NX enabled No PIE
bash 2271 Partial RELRO Canary found NX enabled No PIE
gvfsd-http 2329 Partial RELRO Canary found NX enabled No PIE
update-notifier 2364 Partial RELRO Canary found NX enabled No PIE
knotify4 2424 Partial RELRO No canary found NX enabled No PIE
su 2672 Partial RELRO Canary found NX enabled No PIE
bash 2680 Partial RELRO Canary found NX enabled No PIE
nmbd 2814 Full RELRO Canary found NX enabled PIE enabled
udevd 3092 Full RELRO Canary found NX enabled PIE enabled
udevd 3117 Full RELRO Canary found NX enabled PIE enabled
dhclient 3127 Full RELRO Canary found NX enabled PIE enabled
firefox-bin 4752 Full RELRO Canary found NX enabled PIE enabled
plugin-containe 4780 Full RELRO No canary found NX enabled PIE enabled
GoogleTalkPlugi 4813 No RELRO No canary found NX disabled No PIE
xchat 4961 Partial RELRO Canary found NX enabled No PIE
gedit 4972 Partial RELRO Canary found NX enabled No PIE
bash 4973 Partial RELRO Canary found NX enabled No PIE
gksu 5242 Partial RELRO No canary found NX enabled No PIE
synaptic 5243 Partial RELRO Canary found NX enabled No PIE
upstart-udev-br 531 Full RELRO No canary found NX enabled PIE enabled
udevd 534 Full RELRO Canary found NX enabled PIE enabled
smbd 965 Full RELRO Canary found NX enabled PIE enabled
sshd 973 Full RELRO Canary found NX enabled PIE enabled
rsyslogd 978 Partial RELRO Canary found NX enabled No PIE
dbus-daemon 986 Partial RELRO Canary found NX enabled PIE enabled
avahi-daemon 994 Partial RELRO Canary found NX enabled No PIE
NetworkManager 995 Partial RELRO Canary found NX enabled No PIE
avahi-daemon 996 Partial RELRO Canary found NX enabled No PIE
modem-manager 998 Partial RELRO Canary found NX enabled No PIE
Ill explain the different columns as we face them. A quick visual scan and a bit of intuition tell us the the google talk plugin would be pretty easy to exploit if we found a flaw in it. Well, assuming it would even be worthwile to investigate as a target in the first place
another place, another place. Now on to the fun stuff!
//NX
First of all, if your cpu doesnt support hardware NX ((top of checksec.sh output)) Chuck it out and get one that does? There, fixed
//grsecurity
As you may remember from paxtest that my aslr only involves a handful of bits that is really pathetic against a real exploit(if it even bothers beating aslr head on
), and my heap protection and a bunch of other stuff is pretty shitty. This is where grsecurity comes in. You can get a full list of features at
http://grsecurity.net/features.php that can do better justice explaining why it is important better than I ever could. It pretty much fixes almost everything. Why it's patches aren't part of the linux dev tree already is beyond me. You can get it from the same site's download section or if you are using aptitude you can get the package at
http://kernelsec.cr0.org/ *disclaimer* read the F*cking page before you complain about stuff not working. Also this DOES install a new kernel. If need be, hunt down how to apply the patch to your own kernel source if you have a custom compiled one or it suddenly breaks on you.
Follow the simple instructions at the bottom of the page(if you can't, get a new f*cking hobby
). Its recommend you install paxctl while you are at it in case you ever need to change the configuration(why thats in the repos by default and not grsecurity that it controls is another mystery in life).
The only issue is that sometimes it conflicts with some firmware deal and will abort the isntall(did with mine). This means youll have to go the old school way of compiling it from the source. Check out grsecurity's wiki about that. I dont feel like writing an entire book.
//Canaries
Typically this is a protection you SHOULDNT have to worry about. But....looking back at checksec.sh We do a few times out of the box. Stack canaries are a specific set of bytes placed at the end of a stack buffer. The kernel keeps checking for this value whenever a program is running. Since the canary is before eip, you gotta trample the canary to get to eip during an exploit. The kernel is not too found of this idea and will slay the process quicker than you can say shell. Yeah, dont even get to 'shellc'(ode). There are some bypasses but frankly it out of anything makes stack overflows practically obsolete. If you find a process DOESN'T have it, you have to sigh and get it enabled youreself. That means recompiling :/ do a ./configure and then grep the makefile for a -fno-stack-protector and get rid of that retarded line(my lil bro is autistic and I tend to find that workd offensive, that shows how maddening it is to see 'production code' that uses that option. Assuming gcc is up to date, all shall be well. If the proggy breaks thanks to your changes...find an alternative >.>
//Relro
Ahh now to the stuff that seems like only exploit writers(or those serious about learning it, and I mean serious) seem to be aware of. Relro comes in two fassions, partial and full. As you may have guessed full is better than partial. Partial relro is implemented with the gcc compiler options -Wl,z,relro what this does is reorganize a few internel elf data sections to make it more difficult to mess with(not really). And the non-PLT GOT sections is read-only. That last bit is pretty meaningless since it is barely used in exploitation anyways. Nowadays overwriting GOT in general is cool. Full one ups partial by making the ENTIRE got section read-only. With old-school protections that means practically all of your modern 0days are poof! Out the window and out of site
In fact im still trying to dig up papers about crushing full relro but it's been no-dice so far. Too new and badass I suppose and likely any 'generic' technique would be relatively unknown and a quick ticket to fame or infamy. Anyways you get it running with gcc -Wl,-z,relro,-z,now And yeah, this likely means a LOT of re-compiling if youre paranoid.
//PIE
Ahh the older sister of relro. PIE'd executables are likewise badass. PIE stands for position-independent-executable. Heres the part that makes exploitation scary when youre back up looking at checksec.sh. See how all but the most vital daemons ARENT PIE? Not so good. So whats the big secret about PIE? To qoute wikipedia:
"PIE binaries are used in some security-focused Linux distributions to allow PaX or Exec Shield to use address space layout randomization to prevent attackers from knowing where existing executable code is during a security attack using exploits that rely on knowing the offset of the executable code in the binary, such as return-to-libc attacks."
Yep, this is your fancy, modern aslr. Ya know, the one that is even marginally effective? Technicalities and 'test-programs' aside, you can consider aslr to be good as disabled on any non-PIE program. Back to recomp time with a snazy -fPIE slapped onto gcc
doesnt work with --static Ive heard and prob shouldn't be used while compiling .so libs(but the final executable...definately). So far guess what the only real public bypass of PIE is? got overwriting. Remember what full relro was SOOOO good at? ;DDD Back up at checksec.sh, ever wondered why firefox 0days for linux are never bothered with? Ill let you draw youre own (obvious) conclusions.
(speaking of...)
//Conclusion
Ok, maybe this wasn't a 1-2-3 guide like some of ya may have hoped, but I hope those of you who have read it and havnt looked into modern exploitation have learned a thing or two about defending from 0days, and perhaps a catalog of what you gotta crush in the modern world to write those very same 0days.
References: Too many to count, google a good keyword and I've probably read the results and commited its contribution to memory ;P props to all the underrated exploit writers who don't get the credit they deserve and the guys like the PaX team that have the balls to say, "F*ck your zero days! Bring it!"
Note: If anyone has any information on screwing over RELRO or exploiting PIE, I'd love if ya sent me links/article names/blogs/etc that may be of interest