[LWN Logo]

Date:	Thu, 28 Jan 1999 08:48:18 +0000
From:	Crispin Cowan <crispin@CSE.OGI.EDU>
Subject:      Re: w00w00 on Heap Overflows
To:	BUGTRAQ@NETSPACE.ORG

Shok wrote:

> Subject: w00w00 on Heap Overflows
>
> This is a PRELIMINARY BETA VERSION of our final article! We apologize for
> any mistakes.  We still need to add a few more things.

An excellent article.  Thanks for writing it.  My comments here are intended to
help you improve it.


>    3. There is a "StackGuard" (developed by Crispin Cowan et. al.), but
>       no equivalent "HeapGuard".

We've been working on it since last March.  It turns out to be substantially more
difficult to implement than StackGuard.  We are "almost" done.  I won't predect a
release date, because I'll just be wrong :-)


>    4. Using a heap/bss-based overflow was one of the "potential" methods
>       of getting around StackGuard.  The following was posted to BugTraq
>       by Tim Newsham several months ago:
>
>         > Finally the precomputed canary values may be a target
>         > themselves.  If there is an overflow in the data or bss segments
>         > preceding the precomputed canary vector, an attacker can simply
>         > overwrite all the canary values with a single value of his
>         > choosing, effectively turning off stack protection.

I'll expand on some of the more detailed exchanges between myself, Tim Newsham,
and Thomas Ptacek.  There are several variations on attack techniques here.  The
attacker must achieve three things:

  1. Inject code into some executable portion of the victim program's address
     space
  2. Use a buffer overflow to corrupt an adjcent code pointer to point to the
     injected code.  "Code pointer" can be:
        o return address in an activation record (classic stack smash)
        o function pointer (as found in the SuperProbe exploit)
        o longjmp buffer (as found in the Perl 5.003 exploit)
  3. Wait for the victim program to dereference the corrupted pointer

The injected code can be in the stack, heap, or static data area.  The
overflowable buffer and the buffer that receives the injected code do NOT have to
be one and the same; that just simplifies the attack.  The overflowable buffer
needs to be adjacent to, and most often lower than, the code pointer.  The
overflowable buffer and the code pointer can also be in the stack, heap, or
static data areas.

The classic stack smash uses a single buffer, overflows it to corrupt the
adjacent activation record, and simultaneously injects the attack code.  Control
transfers to the attacker when the function returns because the activation record
now points to the attack code.  StackGuard prevents this attack by doing an
integrity check on the stack just before each function return.

An attack that can beat Solar Designer's non-executable stack, but is caught by
StackGuard, is to use two buffers:  inject the attack code into the heap or
static data areas, and use a classic stack smash to point the return address at
the heap or static buffer.

An attack that can beat StackGuard, but does not get past Solar Designer's patch,
also uses two buffers.  Again, use two buffers.  Inject the attack code into a
buffer on the stack, and use a buffer overflow anywhere to corrupt a function
pointer other than an activation record (i.e. function pointer or longjmp
buffer).

StackGuard and Solar Designer's patch are compatible and can be used in
combination.  Together, they stop all of the above attacks.  An attack that beats
both StackGuard and Solar Designer's patch has to inject the attack code into
either the heap or static data area, and point to it with a code pointer that is
not an activation record.

The enhanced StackGuard that we're working on will provide integrity protection
for function pointer and longjmp code pointers.

Thanks very much for the working examples.  They will come in very handy in
testing the enhanced StackGuard.

>  Now for some case studies!  Our two "real world" vulnerabilities will be
>  OpenBSD/Solaris' tip and BSDI's crontab.  The BSDI crontab vulnerability
>  was discovered by mudge of L0pht (see L0pht 1996 Advisory Page).  We're
>  reusing it because it's a textbook example of a heap-based overflow
>  (though we will use our own method of exploitation).

This is even more exciting:  real, live examples.


> Possible Fixes (Workarounds)
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  Obviously, the best prevention for heap-based overflows is writing good
>  code!  Similar to stack-based overflows, there is no real way of
>  preventing heap-based overflows.

Clearly.  In the mean time, there's still lots of vulnerable code out there ...


>  We can get a copy of the bounds checking gcc/egcs (which should locate
>  most potential heap-based overflows) developed by Richard Jones and Paul
>  Kelly.  This program can be downloaded from Richard Jone's homepage
>  at http://www.annexia.demon.co.uk.  It detects overruns that might be
>  missed by human error.  One example they use is: "int array[10]; for (i =
>  0; i <= 10; i++) array[i] = 1".  I have never used it.

We tried it.  We found it to be unable to compile and RUN even moderately complex
programs.  If anyone has succeeded in getting the Jones & Kelly compiler, or any
other bounds-checking compiler, to compile and run complex, real-world code, I
would love to hear about it.


>  We can always make a non-executable heap patch (as mentioned early, most
>  systems have an executable heap).  During a conversation I had with Solar
>  Designer, he mentioned the main problems with a non-executable would
>  involve compilers, interpreters, etc.

This is problematic, breaking more code than a non-executable stack does.  You
could further extend it by making the static data area non-executable, with more
problems.  These techniques are not fully effective, however, because there is
yet another overflow technique that does not require injecting any code.  An
example was posted to Bugtraq about a year ago.  The idea is to set up parameters
in appropriate variables, and then point the code pointer directly at some code
that already exists in the victim program.  No amount of restricting
executability of segments will deal with this problem.  However, both
bounds-checking and StackGuard-style integrity checks will address the problem.


>  Likewise, another possibility is to make a "HeapGuard", which would be
>  the equivalent to Cowan's StackGuard mentioned earlier.  He (et. al.)
>  also developed something called "MemGuard", but it's a misnomer.

You're right; MemGuard was a distraction.  It turned out to be not much more than
a lame version of "electric fence", so we dropped it completely.


>  Its function is to prevent a return address (on the stack) from being
>  overwritten (via canary values) on the stack.  It does nothing to prevent
>  overflows in the heap or bss.  They do, however, mention the possibility
>  of adding such features in the future.

Yup.  Thanks for the plug.  We appreciate your accurate reporting on StackGuard's
capabilities.


>  L0pht: Internet Explorer 4.01 vulnerablity (dildog), BSDI crontab
>  exploit (mudge), etc.

L0pht has a web page promoting a tool called "SLint" (Security Lint), but it's
just a teaser: it says nothing about the checks that SLint actually performs.
I'd love to hear more details about SLint.  Anyone from the L0pht listening?

Crispin
-----
 Crispin Cowan, Research Assistant Professor of Computer Science, OGI
    NEW:  Protect Your Linux Host with StackGuard'd Programs  :FREE
       http://www.cse.ogi.edu/DISC/projects/immunix/StackGuard/

                 Support Justice:  Boycott Windows 98