Next: Preventing Return Address Changes
Up: Detecting Return Address Change
Previous: Detecting Return Address Change
The Canary defense is sufficient to stop most buffer overflow attacks
that are oblivious to the canary. In fact, simply changing the
compiler's calling conventions is sufficient to stop most buffer overflow
attacks [8]. Most current buffer overflow attacks are
quite brittle, making specific, static assumptions about the layout of
the stack frame. However, it is not very hard for attackers to develop
buffer overflows that are insensitive to minor changes in the stack
frame layout [17]:
- To adapt to changes in the location of the return address
relative to the buffer being overflowed, the attacker can repeat the
new value several times in the input string.
- To adapt to imprecision in the offset of the injected code from
the current program counter, the attacker can inject attack code
consisting of many NOPs, and simply jump to somewhere in the
middle of the NOP sequence. Control flow will then drop down to
the attack code.
- To adapt to changes in alignment, the attacker need only guess 4
times at most to get the alignment correct.
It is also possible to write attacks specifically designed to
overcome StackGuard. There are two ways to overcome the Canary method of detecting
buffer overflows:
- Skip over the canary word. If the attacker can locate a poorly
checked copy of an array of structs, which have alignment
requirements, and are not big enough to fulfill the alignment
requirements while densely packing the array, then it is possible that
the copy could occur such that the canary word is in one of the holes
left in the array. We expect this form of vulnerability to be
rare, and difficult to exploit.
- Simulate the canary word. If the attacker can easily guess the canary
value, then the attack string can include the canary word in the
correct place, and the check at the end of the function. If the canary
word is completely static, then it is very easy to guess. This
form of attack is problematic.
To deal with easily-guessed canaries, we use randomly chosen canary
values. Our current implementation enhances the crt0 library to
choose a set of random canary words at the time the program starts.
These random words are then used as distinct random canary words, one
per function in the object code. While it is not impossible to
guess such a canary value, it is difficult: the attacker must be able
to examine the memory image of the running process to get the randomly
selected word. Even so, a determined attacker could break such a
defense eventually; we discuss our approach to this problem in
Section 3.3.
Next: Preventing Return Address Changes
Up: Detecting Return Address Change
Previous: Detecting Return Address Change
Crispin Cowan
Tue Dec 9 16:04:30 PST 1997