Stack Canaries

Buffer Overflow prevention

Stack Canaries are very simple - at the beginning of the function, a random value is pushed on the stack. Before the program executes ret, the current value of that variable is compared to the initial: if they are the same, no buffer overflow has occurred.

If they are not, the attacker attempted a buffer overflow to control the return pointer and the program crashes, often with a ***stack smashing detected*** error message.

On Linux, stack canaries end with00. This is so that they null-terminate any strings in case you make a mistake when using print functions, but it also makes them easier to spot.

   address     |   values
---------------+------------------------------------------------------------------
               |   +---------------- HelloWorld stack frame -----------------+
               |   | +------------ stack marge -------------+ +-- canary --+ |
   0xffffd264  |   | | 0x00000000   0x00000000   0x00000000 | | 0x54869500 | | 
               |   | +--------------------------------------+ +------------+ |
               |   +---------------------------------------------------------+
               |   +-------------------- main stack frame -------------------+
               |   | +-saved ebp -+ +-saved eip -+ +---- function params ---+|
   0xffffd274: |   | | 0xffffd298 | | 0x565561dd | | 0x00000001  0x00000002 ||
               |   | +------------+ +------------+ +------------------------+|

Add the parameter -fno-stack-protector using gcc in order to disable stack canary when compiling the binary

Bypassing canaries

Leak

The main aim is to read the value, which can differ from binary to binary. One simple option is to use a format string if it is present, as the canary, like other local variables, is on the stack and can be easily leaked off the stack through this method.

After the canary has been determined, the correct canary value can be rewritten when an overflow occurs.

Bruteforce

The canary is generated randomly for each process at run-time.

For a 32-bits process, there is 4294967296 possibilities, then by injecting random 4 bytes there is a quasi-null but non null possibility to bypass it. On linux there is only 3 bytes to retrieve which is only 16777216 possibilities.

For a 64-bits process there is 1.844674407e+19 possibilities... So this is impossible.

There is still a situation where the canary can be bruteforce: when the process make a fork().

When the process make a fork()the entire process is exactly duplicate, canary included. Then it's possible to guess the canary one byte at a time.

             |   Canary
    Buffer   | 42 52 18 42
 ------------|-------------|
 4141...4141 | 00 52 18 42 | <-- Crash
 4141...4141 | 01 52 18 42 | <-- Crash
 ...         | ...         |
 4141...4141 | 42 52 18 42 | <-- No crash

Last updated