Re: Automatic discovery of shellcode address

From: Joel Eriksson (je-vulndevat_private)
Date: Fri Mar 28 2003 - 00:46:20 PST

  • Next message: Jeremy Junginger: "WebDAV Exploit Lab"

    On Sat, Mar 22, 2003 at 12:18:34AM +0000, steveat_private wrote:
    > Hi,
    > 
    >   I've been playing around with LD_PRELOAD under Linux to modify
    >  some functions commonly susceptible to buffer overflows, strcpy,
    >  sprintf, etc.
    [snip]
    >   After that it's endgame - it's just a matter of working out where
    >  your shellcode may be placed and the magic offsets to modify to
    >  point to it.
    > 
    >   Whilst this isn't terribly difficult it's a time consuming and
    >  fragile process.  (Maybe that's just me!)
    
    Maybe. :-) What's wrong with simply using gdb to find out? It's
    not hard, and the binary does not have to be dynamically linked ..
    
    >   It occurs to me that if you know where the buffer in memory which
    >  you're overflowing is, (in the case of sprintf, strcpy etc), you
    >  might be able to cheat.
    > 
    >   Knowing the direction the stack goes down all you need to do
    >  is overwrite the memory with:
    > 
    >  	# shellcode
    > 	# address of the start of the buffer x 1000
    > 
    >   If the start of the buffer being copied to is know then stick the
    >  shellcode there, and afterwards just append that address, so that
    >  all the likely return pointers are left sticking at your shellcode
    >  in a known location.
    
    This is a common technique, yes, but very ugly. :-) If it is a local
    exploit, then why put the shellcode in the buffer you're overflowing
    at all? If you put your shellcode in the environment or in a command
    line argument instead, and know how the stack is laid out, then you
    can calculate the exact address where the shellcode will be placed.
    Of course, this method cannot be used when the stack is not executable
    or when the stack base is randomized (like with PaX).
    
    In a linux/x86 local exploit I would usually do something like:
    
    ---
    ...
    int main(int argc, char **argv)
    {
    	unsigned long addr = 0xC0000000 - 4;
    	char *envp[] = { shellcode, NULL };
    	char *prog = "/path/to/vulnerable/prog";
    	addr -= strlen(prog) + 1;
    	addr -= strlen(shellcode) + 1;
    	... 
    	execle(prog, arg0, ..., argN, NULL, envp);
    ---
    
    In the example above I made it really simple for me and just replace
    the environment with a single value, the shellcode. Notice that there
    is nothing that requires environment strings to contain a '='.
    
    What if we have to preserve the environment? No problem. Actually, we
    can even preserve the environment and put our shellcode in argv[0] and
    still calculate the exact address it will be placed on:
    
    ---
    int main(int argc, char **argv)
    {
            unsigned long addr = 0xC0000000 - 4;
            extern char **environ;
            register char **p;
            char *args[NUM_ARGS+1];
            char *prog = "/path/to/vulnerable/prog";
    	...
            addr -= strlen(prog) + 1;
            for (p = environ; *p != NULL; p++)
                    addr -= strlen(*p) + 1;
            for (p = args; *p != NULL; p++)
                    addr -= strlen(*p) + 1;
    	...
            execv(prog, args);
    ---
    
    Now anyone with half a brain should be able to figure out how to calculate
    the address if we put the shellcode in arbitrary arg or environment variable
    instead.
    
    Adapting the approach mentioned above to for instance *BSD/x86 is as simple
    as changing 0xC0000000 (the base address of the stack) to 0xBFC00000. Well
    almost anyway, in *BSD we may need to subtract up to three bytes depending
    on alignment, we can either calculate this or do it the easy way and just
    add three NOP's to the beginning of our shellcode.
    
    >   How do you get the address of the buffer in the first place?
    >  Use LD_PRELOAD to modify 'strcpy', 'sprintf' to display the address
    >  they're writing to.  Simple.
    > 
    >   (OK LD_PRELOAD doesn't work for setuid binaries, but typically 
    >  copying the target to your machine will work, and you're safe as
    >  the displayed addresses won't change).
    > 
    >   Does this sound reasonable, or am I imagining things?
    
    Sure, nothing wrong with the technique in itself, but I don't find
    it terribly useful either since there are better ways to do it.
    
    > Steve
    > ---
    > www.steve.org.uk
    
    -- 
    Joel Eriksson <jeat_private>
    -------------------------------------------------
    Security Research & Systems Development at Bitnux
    PGP Key Server pgp.mit.edu, PGP Key ID 0x529FDBD1
    A615 A1E1 3CA2 D7C2 CFEA 47B4 7EF7 E6B2 529F DBD1
    -------------------------------------------------
    
    
    



    This archive was generated by hypermail 2b30 : Fri Mar 28 2003 - 08:27:25 PST