Bugtraq mailing list archives

Re: Future of buffer overflows ?


From: Gerardo Richarte <core.lists.bugtraq () CORE-SDI COM>
Date: Mon, 30 Oct 2000 21:53:26 -0300

Thomas Dullien wrote:

So it is possible to have readable, non-executable memory pages, at a
not too bad performance hit of up to 10%. This is very cool.

        This is not a new concept. It's been out there for a while now...

Does this mean buffer overflows and format string vulnerabilities are
dead ?

        I'll hung from here.

        As you said, this is not true, it's just a little trickier to
exploit a "return address on the stack" buffer overflow bug.
        You showed us a way to do it (by returning to exec() with "pre
pushed" arguments)

        here I'll show two different approaches to exploit this bugs in
"protected" systems.

        The first approach is simple, it's not too different to what you
described, but will serve as introduction:

        Feed a return address and arguments so the RET "calls" memcpy(),
and use this memcpy() to move the buffer to some place in memory where
you can jump latter. Then tell memcpy() to return to this new place,
clarifying:

        [buffer] &caller                ; before overflow

        a standard exploit, with executable stack makes:

        [buffer] &buffer                ; returning to buffer

        RET jumps to &buffer

        you described:

        [/bin/sh] &system xxxx &buffer  ; calling system("/bin/sh")

        what's this?

        RET jumps to &system, &buffer is the argument for system,
so, this is a perfect and legal system("/bin/sh") without executing any
code in the stack (this requires that you know the address of system...
which doesn't change on the same platform, same libc version, same more
things)

        what's xxxx up there for?
        it's where system() returns, we can use it.

        I said:

        [code] &memcpy &place &place &buffer

        what?

        translated into:

        memcpy(&buffer,&place)
        jmp &place              ; place()

        memcpy() copies from buffer to a useful place where you can
write and execute (is there a place like this?), then, it returns
to address on top of the stack: out first &place, jumping to the copy.

        This can be useful in some platform, I don't know, it can be
used (the memcpy()) to overwrite the GOT, or destructors table, etc, etc.


        The second option... let's call it "pop&ret"

        Here I present a way to code any program, or almost any program,
in a way such that it can be fetched into a buffer overflow in a platform
where the stack (and any other place in memory, but libc) is executable:

        Why can't we make more than a call with arguments and a call
without arguments, like in memcpy(), place()?
        The problem is that the arguments for memcpy() are in the stack,
in the place where the return address from place() should be.
        But we can return to better places, this is the idea:


        Almost every function [in libc] ends with:

pop3:
        pop     something
pop2:
        pop     something       ; some pops into regs
pop1:
        pop     something
        ret

        or

        pop     something
        pop     something       ; some pops into regs
        pop     something
popbp:
        pop     ebp
        mov     esp,ebp
        ret

        suppose we called gets(), that consumes 1 argument, we
can code something like:

        while (1) {
                gets(buffer);
                system(buffer);
        }

        like this:      

[buffer] &gets &pop1 &buffer &system &pop1 &buffer &popbp buffer+BUF_SIZE

        what?

        yes!

        first RET jumps to gets() with &buffer as argument.
        gets() RET jumps to pop1
        pop1 consumes gets() argument from stack and RETs to system
        system's argument is buffer.
        system's RET jumps to pop1, it consumes 1 argument, jumps to popbp
        yeah!
        popbp pops buffer+BUF_SIZE (the address of our first return addr)
        makes esp point to our first return address...
        returns: everything starts again.

        got it?

        you can call functions with more that a single argument by
jumping to pop2 or pop3 (or whatever you need as long as you can find it
in libs... you can look for:

        add     sp,10h
        ret

        if you have to consume too many arguments from the stack)

        actually, this while() {} may or may not work (the stack may
get overwritten by the called function... but the while is not the point,
is it?)

        ok, this is from the top of my head, this code is not tested, it's
not bullet proof, but the method has been tested (and used) successfully in our labs...

        richie

PS: We are preparing an article on [really] Advanced Buffer Overflows,
so... stay tuned!

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