Skip to content

Introduction

In the last section we looked how programs allocate memory when calling functions, this time we will examine what happens when a value stored on the stack overflows.

Overflowing Data on the Stack

When a C program defines a Variable, space is allocated on the stack for the data. So in our example above theString[10], ten 'slots' of memory on the stack will be allocated.

If there are multiple variables, then space will be allocated for all of them sequentially on the stack, consider the following code:

char theString[10];
int firstNumber;
int secondNumber;

Space on the stack for each of the variables would be allocated:

  • 10 Bytes, for theString variable.
  • 4 Bytes, for the firstNumber variable.
  • 4 Bytes, for the secondNumber variable.

So our stack could conceivably look like this

Memory Address (Decimal) Variable
0 TheString
10 firstNumber
14 secondNumber

Stack Variable Allocation

Note

The order of the variables in the code, may not necessary correspond to the order on the stack. The compiler may optimise the variable order to let variable addresses align and improve efficiency. This has bitten me in interesting ways in the past.

Now for the interesting part, Lets start adding some data

  • We set the firstNumber to 42
  • We set the secondNumber to 6005
  • We set the String to "FooBar"

Now most of this is reasonably obvious, when we add data to the String the program

  • Lookup the address for the start of the variable on the stack (Address 0)
  • Write the 6 bytes of data sequentially, starting from that address. (Ie address slots 0-6)

This Looks Something Like This

Non Overflow Stack

What about those Integers

So why the heck are the integers stored in that weird way? Isnt 2A,00,00,00 a huge number?

Its to do with the day numbers are stored it the x86 architecture. Number are stored in a "Little Endian" format. This means that the "Least significant Byte" is stored first

The quick and dirty way of working out endianness is split our number into byte pairs, then reverse them For example with `0x12345678

  • Split into pairs 12 34 56 78
  • Reverse order 78 56 34 12

You can Read more about endianness

Important

To make things even more confusing, This only apply's to data on the stack, Registers store things as the actual (big endian) number. This usually only makes a difference in the debugger. But its something to watch for.

Overflowing the stack

This is great, but so far we haven't broken anything. However if we try to write more items than we have space for we get a problem, as there are no checks done on the length of the expected data.

  • Set the Values of the Integers
  • Write "TheEvilString" (13 Bytes) into the buffer

Overflowed Buffer

For example if we write "TheEvilString" we end up writing to address slots (0-13), this will overwrite the first Three bytes of the value stored in the firstNumber variable, with the last three characters of our string. This (once we do the endianness calculations) makes the value become 6.7 Million.

How we can use this to break programs.

More importantly, its not just variables that are stored on the stack. Recall from the previous article, that the stack frame also contains a Return Address, that is used to tell the program the next instruction to execute when the function ends.

This address is also not protected, and can be overwritten by the overflow. This is at the core of the buffer overflow attack, if we can control what happens when the function exits, then we can tell the program what to do.

You can see a video demonstrating this

Back to top