Overflow and stack protection

We have mentioned that program exploitation refers to techniques that allow us to “make a program do something unexpected and not planned”. How is this possible?

  • Programs are complex and it is hard to foresee all possible situations;
  • Programming errors can be exploited to obtain unexpected behaviour;
  • When a program is extended to incorporate new functionalities it might happen that these introduce new breaches, since new behaviours (initially unexpected) are introduced.

In general, code does not always do only what the programmer had in mind …

Example 1: off-by-one

in OpenSSH it was discovered a ‘off-by-one’ bug

instead of

This code checks that a channel id is in the expected range. The bug allowed for accessing a memory cell (through overflow that we study in this class), obtaining root privileges.

Example 2: path traversal

Microsoft IIS webserver checked the presence of ‘\’ in the file names to avoid ‘path traversals’ into disallowed directories. When the server was extended to support Unicode developers forgot to check for %5c, that corresponds to ‘\’. Translation from Unicode happened after the backslash check, so ‘path traversal’ attacks were possible.

Buffer Overflow

A buffer overflow occurs when a program overruns a buffer boundary and overwrites adjacent memory. This anomaly frequently happens in C programs. C language, in fact, leaves to the programmer the responsibility of preserving data integrity: there are no checks that variables are stored in the relative allocated memory. This produces very fast programs but run-time errors, such as overflows, are possible.

Example (Overwriting variables)

The following program allocates an integer variable value and two buffers of size 8, buffer1 and buffer2. It prints the variable location and content using %p, %s and %d (plus %08x for hexadecimal format). Then the argument from the command line is copied into buffer1 (line 18). This can clearly go beyond the boundaries of buffer1 in case the argument is bigger than 8. The idea is to observe what happens. To this purpose the program prints again the location and content of the three variables.

Try to execute the program passing a string of gradually increasing size. For example: ‘A’, ‘AA’, ‘AAA’, and so on.

  • Observe the overflow in the output;
  • Increase the length until the program crashes;
  • Try to compile the program with option -fno-stack-protector and observe the difference. This option disables protection against overflows on the stack (see below).

To understand what happens in the above example it is good to recall how programs are mapped into memory:

Without stack protector, variables typically appears on the stack as they had been pushed, i.e., in reverse order: buffer2, buffer1 and value. Thus when an overflow on buffer1 occurs, this overwrites value but not buffer2.

Stack protector rearranges the position of variables. With -fstack-protector (which is usual enabled by default) the compiler put value before any array so that it cannot be overwritten by overflows. In this specific example it also swaps the relative position of the two buffers but this may vary depending on the compiler and on the alignment of variables on the stack. The following picture illustrates:

Now that you have a better understanding of the relative position of variables you can rerun the example to observe how values are overwritten.

A first exploit: changing program flow

Overwriting variables is, per se, critical. Sometimes it can cause interesting changes in the program flow. Next example shows how this could happen and how variable rearrangement may prevent attacks.

We compile the program with no stack protector (option -fno-stack-protector) and we experiment with inputs of increasing size:

What is happening here? As before, if we give a string longer than the buffer we have an overflow. Next variable in memory is overwritten. In particular auth_flag, becomes different from 0 (which in C means ‘true’). Function check(argv[1]) returns true and the user is authenticated.

Let us see with gdb what is going on on the stack:

Exercise

Set stack protector on and observe that the attack is prevented. Notice the special message given by the program when a long input is given. The overflow does not overwrites the auth_flag because of the rearrangement discussed above. Moreover the program detects the overflow. We will discuss how this is possible during the next class.

Leave a Reply

Your email address will not be published. Required fields are marked *