Wednesday, September 10, 2014

Address Space Layout Randomization in Linux 2.6+

Hi all, this post is intended as a primer for the Vortex wargames I will be hacking here in the coming weeks. If you want to follow along with the wargames, they can be found at www.overthewire.org. I figured this would be a good place to briefly review virtual memory and ASLR in the Linux kernel, since some of the vulnerabilities in Vortex will require us to use buffer overruns, and ASLR is one of the techniques used to prevent such attacks.

Let's start off with a claim that we will then verify below: Roughly all processes run in the same virtual memory space, and are given the illusion that they are the only program running on the computer.

What this means, quite literally, is that if you run a program and look at its start location in virtual memory, and then run another program and look at its location in virtual memory, they should be the same. Let's see if we can verify this by hand:

First, fire up a Linux terminal and type the following:
cat
but don't provide the cat program with any arguments (this should keep it running, so that we can go investigate its memory usage). Now, from a seperate terminal on the same computer, type:
ps -a | grep 'cat'

Read the man pages for more details on the commands ps and grep. This basically lists all of the processes running on your system, and then filters them for the word "cat". Now, you should have a result that looks similar to this:
28733 pts/3    00:00:00 cat

The first number, in this case 28733 (will likely be different when you run this), is the process id for the cat command that we ran a moment ago. Now, from the same terminal, go ahead and run:
cat /proc/28733/maps
Which will produce the following (note when you run the example, substitute the process id on your system in place of 28733):
00400000-0040b000 r-xp 00000000 08:03 7077907                            /bin/cat
0060a000-0060b000 r--p 0000a000 08:03 7077907                            /bin/cat
0060b000-0060c000 rw-p 0000b000 08:03 7077907                            /bin/cat
00e5d000-00e7e000 rw-p 00000000 00:00 0                                  [heap]
7f6d015f1000-7f6d018ba000 r--p 00000000 08:03 12067216                   /usr/lib/locale/locale-archive
7f6d018ba000-7f6d01a6f000 r-xp 00000000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7f6d01a6f000-7f6d01c6e000 ---p 001b5000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7f6d01c6e000-7f6d01c72000 r--p 001b4000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7f6d01c72000-7f6d01c74000 rw-p 001b8000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7f6d01c74000-7f6d01c79000 rw-p 00000000 00:00 0
7f6d01c79000-7f6d01c9b000 r-xp 00000000 08:03 28053004                   /lib/x86_64-linux-gnu/ld-2.15.so
7f6d01e85000-7f6d01e88000 rw-p 00000000 00:00 0
7f6d01e99000-7f6d01e9b000 rw-p 00000000 00:00 0
7f6d01e9b000-7f6d01e9c000 r--p 00022000 08:03 28053004                   /lib/x86_64-linux-gnu/ld-2.15.so
7f6d01e9c000-7f6d01e9e000 rw-p 00023000 08:03 28053004                   /lib/x86_64-linux-gnu/ld-2.15.so
7fffe41c9000-7fffe41ea000 rw-p 00000000 00:00 0                          [stack]
7fffe41ff000-7fffe4200000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]



That is a snapshot of the virtual memory in use by cat. A couple of things to note here are that memory starts at 0x00400000, and that the [stack] is located at 0x7fffe41c9000.
Great, let's do this entire process again, but for a different program (you can even do this while your instance of cat is still running):
vim
and then, from another terminal:
ps -a | grep 'vim'
cat /proc/29569/maps
which gives:
00400000-005d6000 r-xp 00000000 08:03 12059867                           /usr/bin/vim.basic
007d5000-007d6000 r--p 001d5000 08:03 12059867                           /usr/bin/vim.basic
007d6000-007ec000 rw-p 001d6000 08:03 12059867                           /usr/bin/vim.basic
007ec000-007f8000 rw-p 00000000 00:00 0
00972000-00a36000 rw-p 00000000 00:00 0                                  [heap]

...
...
7f6489602000-7f6489604000 rw-p 00023000 08:03 28053004                   /lib/x86_64-linux-gnu/ld-2.15.so
7fffbcbb0000-7fffbcbd1000 rw-p 00000000 00:00 0                          [stack]
7fffbcbff000-7fffbcc00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]


To note, the vim program also starts at 0x00400000! So both processes, vim and cat, start at the same location in virtual memory, even when they are both running at the same time. This is in general true of all processes. Note that I am using a 64-bit version of Linux, so the start location may be different on your system, but it should be the same for all of your processes. If you have been paying close attention, you may have noticed that the [stack] has moved from cat to vim, as it is now at 0x7fffbcbb0000. Let's run another instance of cat and see if the [stack] is still at 0x7fffe41c9000.
When I check on a new instance of cat, I find that its virtual memory looks like:
00400000-0040b000 r-xp 00000000 08:03 7077907                            /bin/cat
0060a000-0060b000 r--p 0000a000 08:03 7077907                            /bin/cat
0060b000-0060c000 rw-p 0000b000 08:03 7077907                            /bin/cat
00d0e000-00d2f000 rw-p 00000000 00:00 0                                  [heap]
7ffe3b35c000-7ffe3b625000 r--p 00000000 08:03 12067216                   /usr/lib/locale/locale-archive
7ffe3b625000-7ffe3b7da000 r-xp 00000000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7ffe3b7da000-7ffe3b9d9000 ---p 001b5000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7ffe3b9d9000-7ffe3b9dd000 r--p 001b4000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7ffe3b9dd000-7ffe3b9df000 rw-p 001b8000 08:03 28053024                   /lib/x86_64-linux-gnu/libc-2.15.so
7ffe3b9df000-7ffe3b9e4000 rw-p 00000000 00:00 0
7ffe3b9e4000-7ffe3ba06000 r-xp 00000000 08:03 28053004                   /lib/x86_64-linux-gnu/ld-2.15.so
7ffe3bbf0000-7ffe3bbf3000 rw-p 00000000 00:00 0
7ffe3bc04000-7ffe3bc06000 rw-p 00000000 00:00 0
7ffe3bc06000-7ffe3bc07000 r--p 00022000 08:03 28053004                   /lib/x86_64-linux-gnu/ld-2.15.so
7ffe3bc07000-7ffe3bc09000 rw-p 00023000 08:03 28053004                   /lib/x86_64-linux-gnu/ld-2.15.so
7fff2c34c000-7fff2c36d000 rw-p 00000000 00:00 0                          [stack]
7fff2c3ff000-7fff2c400000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]


 Same start address, but the stack has moved to 0x7fff2c34c000! Why is this? Well, this is the hallmark of Address Space Layout Randomization (ASLR). Linux kernels 2.6 and above randomize parts of virtual memory so that the stack is not always in the same place. But why do this? Well, when you try to perform a buffer overrun attack, one of your goals is to take control of a vulnerable program's stack. From there, you can steal control of the return address, and point it to the location of your malicious shellcode. However, if memory layout is randomized, then the relative locations of the stack and your shellcode will not remain constant, which will make it more difficult to jump to your shellcode! Don't worry if that doesn't make too much sense right now, as I will cover it in much greater detail when I move through the Vortex wargames (I may even do a brief tutorial on buffer overruns before that). Just know that there are ways around ASLR (known as NOP sleds).

That's all for this round. It feels great to be back on this blog again after so much time. I will be covering systems level stuff for a little while, and then might branch into some rootkit discussions, as well as memory forensics, which has really been catching my eye lately. Keep hacking.
ITNOT.
-G3n3s1s



No comments:

Post a Comment