Aleph1, it's okay if you decide not to forward this to the list -- there
has been a lot said on the subject already. However, I'll try to only
mention new stuff now. This is not meant to start another thread.
> -=[ Defeating Solar Designer's Non-executable Stack Patch ]=-
First, thanks for posting this, it's nice to see that exploiting buffer
overflows really becomes an art. ;-) (However, I should admit that there
were some very nice exploits not related to my patch too, and even before
my patch appeared.)
I agree with most of what you say, but it looks like a few corrections are
needed. (Why didn't you send me this article for a review before posting it,
I don't mind posting exploits for my own stuff, as you could already see.;-)
> If the vulnerable application uses a procedure from shared library, the text
> segment will contain an appropriate procedure linkage table entry, which we
> can merrily use. For instance, if lpr used "system", then Solar Designer's
> exploit for lpr would work fine: instead of finding "system" in libc, we
I mentioned this on linux-kernel when discussing this stuff before my BugTraq
post with return-into-libc exploits. What's really new in your post is the
great idea to return into strcpy(), which is very likely to be present. :-)
> Information stored in /proc/pid/maps is... ahm... not always accurate.
> Code can be executed in data segment, even if you issue
> mprotect(...,...,PROT_READ) call. In fact, it can be bare PROT_WRITE or
That's since x86 doesn't have execution permission bit on pages. (I'm using
segment-based protection in my patch, not page-based.)
Now, to the question -- why I left other data areas executable:
1. It can't be fixed in Linux for x86 right now.
Since on x86 we can't use page-based protection for that, we would
need to set the code segment's limit to a different value for each
process. Right now Linux/x86 keeps user segment descriptors in GDT
(Global Descriptor Table, for those not familiar with x86), which
means that we would have to set the limit on every task switch. The
right approach would be to move user descriptors to the local table,
LDT, but this will break some user-level applications (dosemu) if I
just do this in my patch.
AFAIK, this is going to change in Linux 2.2 or 2.3, then I will
likely update my patch to allow non-executable data areas other
than the stack. This change will also allow me to get rid of using
Ring 2. :-)
2. There're more programs that generate code in malloc()ed areas than those
that generate it on the stack. These will break.
Well, this is not much of a reason not to support non-executable
data areas. These programs can be made to work again by setting
the ELF header flag on them.
> In Designer exploits, a shell was invoked using "system" call, which after
> completion returns onto the stack ( and segfaults ). This caused exploit
> attempt logging. In exploit no 1 we execute our code using execve, so
> everything is clean and tidy.
I was using system() for a reason: it has only one parameter, so that there
could be only 8 different alignments to try. It was possible to make it
return into exit() with the cost of increasing the number of alignments to 12.
It didn't seem to be worth doing, since you could always kill the vulnerable
program from the privileged shell, and nothing would get logged.
> First idea is to patch kernel so that instructions in data segment cannot be
> executed. Solar Designer patch does simply
> (retaddr & 0xF0000000) == 0xB0000000
> comparison to detect whether code is returning into stack; it would be a
> time-consuming job to check if we're returning into a data segment. Anyway,
This has nothing to do with performance. The check you quoted is only for
exploit attempt logging, it's not what makes the stack non-executable.
> Section IX. Local vs remote exploit
> These two pieces of code are local. The idea of the first one can
> be materialized into a remote exploit; all we need is a copy of an attacked
> program to examine. Even all possible versions of it can be tried by a
> determined hacker. The second one requires a very high accuracy, which
It's not always possible to try all versions: there're network clients run
by humans who are not going to be trying again and again, and there're some
non-respawning daemons. But in general you're right: it's often possible,
just not always.
In general, these types of exploits require more time for the attacker to
apply to a particular system. This is enough to make less attacks succeed,
since some admins will more likely notice the attack in time than they
would when running with executable stack.
> b) we force LD_BIND_NOW - like dynamic linking, which enables us to
> mprotect GOT non-writable
> It's probably a linker issue, but if we can mmap PLT in the lowest 16MB,
These two are interesting ideas, I'll think more of them later.
And finally here's a tiny FAQ for those confused (if this gets to the list):
Q: Is it possible to bypass the patch?
Q: Is there still a reason to use the patch?
Q: Should I fix known buffer overflow vulnerabilities when using the patch?
A: Yes to all three questions. Read secure-linux.doc.
Signed,
Solar Designer