Vulnerability Development mailing list archives

Re: Buffer Overflows


From: Gerardo Richarte <gera () corest com>
Date: Tue, 30 Mar 2004 15:58:07 -0300

. npguy wrote:
Hi,

ESP points the current address of the stack frame. The address is very importnat to exploit the return address.

Take an example of overwriting the return address with JMP ESP instruction simply change the flow of the program by jumping to the current pointing address of ESP (Stack Pointer). In our case the ESP points within our buffer next to the Return address. So JMP ESP will point in the next index of our buffer i.e the overflowed buffer.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaxxxxSSSSSSSSSSSSSSSSSSSSSSSSS
                                   |  ^
    +--msvcrt.dll---+              |  |
    |               |              |  |
| JMP ESP<------------------+ | | | | | | +--------------------------+ | |
    +---------------+

        This is really a nice trick that's being used lately, mostly on windows boxes. A slight variation of this is to 
put the shellcode before the return address (in the overflown buffer itself) and then after the return address put a 
relative jump (or call, so you can just pop the address of the shellcode... which will anyway be in esp, so why pop it?) 
anyway:

        This nice trick can be used on any platform/any os, however, the availability AND RELIABILITY of the trick varies. The 
big question is "Where are you going to find the right code to jump to?"

In short: The trick is good for closed source software, if you use it correctly. The trick is no good for open source 
software (when the concepts apply)

In Long:

        I would draw a line separating closed source vs. open source software. And mostely, those open source OSes 
where people actually compile their own stuff (specially libraries).

        On closed source software, where only the vendor can compile the binaries and libraries, you could, at least 
theoretically, gather all the different versions of the libraries (per version, per service pack, per language, per 
architecture, per etc...) and build a single database with all the possibly usefull addresses. Today people is doing this 
for windows, an example of an open database like this is the one in metasploit's site, there are also closed/private 
databases like this.
        
        Theoretically, the base address where libraries are loaded may vary from machine to machine, however, this is not really 
common in windows, where each dll has an assigned base address, and whenever is possible, the dlls are loaded at this address. 
But, if you check the base address for the same library across different languages, you'll realize that in this case, the 
base address may vary. So, you'll need a more complete database.

        Another example of "Closed source OS" (quotes because you can get some of the sources for solaris, at least 
there was an open source version of solaris 8, for the source sharing community, or something like that).
        So, I was saying, for solaris you could also create a database of known good addresses, however, the base address 
for libraries varies from binary to binary, so your data must be of relative addresses rather than absolute (how you would 
do it in windows). And then, for each binary you exploit, you must figure out the base address of the library where you ware 
jumping to. In our tests (some real exploit), we used this with really good success. Meaning we've been able to write 
the exploit with one address, then turned to use the database for known addresses, and suddenly the exploit passed all QA 
tests on the other versions of solaris, which I found reall amazing :-)

        On the other hand, where the user can compile his own libraries, this is absolutely different, because for some wierd 
cosmic reason, binaries compiled on different boxes rearely have the same addresses. So, there is no theorical way of 
constructing a database of known addresses for self compiled binaries/libraries... however, it's still possible to 
bruteforce the addresses, specially when the code you are looking for is really common (like pop/ret, or just ret). But I'm 
not sure if I would recomend this.

        However, if you are targeting known distros with known binaries, the trick can still be used.

        Remember to think before coding :-)
        Sometimes it's good, sometimes it's not. Sometimes is better to target a library, sometimes it's better to target 
the binary itself... Sometimes, it's just better to target the PE or ELF header :-)

        gera

PS: I'd like to point out that this technique is called return to libc (libc for historical reasons). Or in short 
ret2libc or better, ret2code. This same ideas about closed vs. open source software, and addresses databases apply to 
original ret2code exploitation, where it was used not to improve the reliability of an exploit but rather to bypass some 
code execution restrictions, like non-executable stack.


Current thread: