Channels ▼
RSS

Open Source

Anatomy of a Stack Smashing Attack and How GCC Prevents It


SSP in Action

Let's have a look at this situation in a debugger. We start a debugging session on our previously built vuln-with-ssp:

gdb -q ./vuln-with-ssp

On the (gdb) prompt, a command list will show the following:

(gdb) list
2
3       void vuln(const char *str)
4       {
5         char buf[20];
6         strcpy(buf, str);
7       }
8
9       int main(int argc, char *argv[])
10      {
11        vuln(argv[1]);

With break 5 we set a break point at line 5. Now I’ll start the program with an overflowing argument:

run 'perl -e 'print "X"x40''

The program starts and stops immediately at line 6 because of the break point. The stack is at that time completely initialized but "unsmashed" because the dangerous strcpy() is not yet invoked.

Listing Three tells us in line movq %rax, -8(%rbp) that the canary is addressed -8 bytes relative to the base pointer (register rbp). So we can list this position in memory by invoking x/2 $rbp-8 in our gdb session:


(gdb) x/2x $rbp-8
0x7fffffffe5e8: 0xc4671b00      0x0c3b5a5b


The whole stack frame of subroutine vuln() has, according to line subq $48, %rsp of Listing Three, a size of $48 bytes (decimal: 72 bytes). So let's list the whole stack frame:

(gdb) x/18x $rbp-72
0x7fffffffe5a8: 0xf7dd5750      0x00007fff      0x00008000      0x00000000
0x7fffffffe5b8: 0x004005e0      0x00000000      0x00000000      0x00000000
0x7fffffffe5c8: 0xffffe92e      0x00007fff      0x00000000      0x00000000
0x7fffffffe5d8: 0x00400625      0x00000000      0xf7a8daa8      0x00007fff
0x7fffffffe5e8: 0xc4671b00      0x0c3b5a5b

The last line shows the canary again. Also interesting is the current stack trace because it gives us an insight into the return address. The bt command let us list it:

(gdb) bt
#0  vuln (str=0x7fffffffe92e 'X' ) at vuln.c:6
#1  0x00000000004005ba in main (argc=2, argv=0x7fffffffe6f8) at vuln.c:11

Besides the argument (str=0x7fffffffe92e), which holds the string with 40 times X, we see the address in the main() function from which vuln() was called. The address is 0x00000000004005ba.

A look at the base pointer's address also tells us that value is the return address:


(gdb) x/4x $rbp
0x7fffffffe5f0: 0xffffe610      0x00007fff      0x004005ba      0x00000000

If we take into account that we are on a little-endian system (an x86 processor), the last two values, 0x004005ba and 0x00000000, show us the saved return address as well.

Now I’ll execute the strcpy() statement with gdb's command step. strcpy() copies the given string of 40 times X into the much-too-little buffer buf. The stack trace now looks different:

(gdb) bt
#0  0x00007ffff7af9560 in strcpy () from /lib/libc.so.6
#1  0x00007ffff7dec4ef in ?? () from /lib64/ld-linux-x86-64.so.2
#2  0x00007ffff7df22f5 in ?? () from /lib64/ld-linux-x86-64.so.2
#3  0x0000000000400582 in vuln (str=0x7fffffffe92e 'X' )
    at vuln.c:6
#4  0x00000000004005ba in main (argc=2, argv=0x7fffffffe6f8) at vuln.c:11
(gdb) x/4x $rbp
0x7fffffffe5f0: 0x58585858      0x58585858      0x58585858      0x58585858

The return address was overwritten, but so was the canary:


(gdb) x/2x $rbp-8
0x7fffffffe5e8: 0x58585858      0x58585858

Command c lets me continue the program and SSP detects the smashing:


(gdb) c
Continuing.
*** stack smashing detected ***: /home/omueller/ssp/vuln-with-ssp terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x37)[0x7ffff7b61667]
/lib/libc.so.6(__fortify_fail+0x0)[0x7ffff7b61630]
/home/omueller/ssp/vuln-with-ssp[0x400596]
/home/omueller/ssp/vuln-with-ssp[0x400500]
======= Memory map: ========
...

Where Does the Canary Come From?

The canary's prototype is read from %fs:40 as seen in Listing Three. But where does it come from? Where does the initialization originate?

There is a function __guard_setup() provided by gcc that sets up the canary prototype. The code is similar to this:

fd = open ("/dev/urandom", 0);
if (fd != -1) {
   ssize_t size = read (fd, &__guard, sizeof(__guard));
   close (fd) ;
   if (size == sizeof(__guard)) return;
}
/* If a random generator can't be used, the protector switches the guard
   to the "terminator canary" */
__guard[0] = 0; __guard[1] = 0; __guard[2] = '\n'; __guard[3] = 255;

The canary is read from /dev/random, and changes from execution to execution. Thus, it's hard to guess for an attacker (one cannot simply include the canary with a payload).

If /dev/random is not available, the SSP fills the prototype with terminator characters, which cannot be transferred by a payload. strcpy(), for example, would expect the end of string while reading a null byte.

The use of prologues and epilogues to create a canary to detect intentional stack overflows is one of the key tools in preventing this kind of attack.


Oliver Mueller works as freelance IT consultant, IT trainer and IT manager. His preferred subjects are: software engineering, UNIX, Linux, Java EE, and mobile platforms, as well as integration and migration of legacy systems (z/OS, OpenVMS).


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video