The stack can be protected against buffer overflows.
Stack protection with canaries

Like in a coal mine, a canary can provide an indication if something goes wrong. Here, a canary is a defined values which is added between the buffer (where an attacker will start writing the payload) and the SFP Stack Frame Pointer and RP Return pointer. To overwrite the RP Return Pointer, an attacker has to overwrite the canary as well. In the function epilog, the canary is always validated. If it contains not the expected value, the program terminates.
Microsoft calls canaries security cookies (?!).
If SSP Stack Smashing Protection is active and a process terminates because of SSP, the error message will be the following:
*** stack smashing detected ***: <unknown> terminated
Types of canaries
- A null canary contains only null bytes. (
0x00000000) - A terminator canary contains “bad characters” for many functions like linebreak, binary zero, carriage return, etc. (e.g.
0x000a0dff) - A random canary consists out of random bytes which are defined when the process starts.
- To determine a random canaries value, an attacker could try to guess the first byte 0x03 by overwriting only one byte after the buffer. If the program execution stops, then this byte was wrong. If not, the value was guesses and he can repeat it until the whole canary is known.

- To determine a random canaries value, an attacker could try to guess the first byte 0x03 by overwriting only one byte after the buffer. If the program execution stops, then this byte was wrong. If not, the value was guesses and he can repeat it until the whole canary is known.
Canaries in action
Let’s see how a canary works by disassembling a function with gdb.
... 0x08048541 <+18>: mov eax,DWORD PTR [ebp+0x8] 0x08048544 <+21>: mov DWORD PTR [ebp-0x2c],eax 0x08048547 <+24>: mov eax,DWORD PTR [ebp+0xc] 0x0804854a <+27>: mov DWORD PTR [ebp-0x30],eax 0x0804854d <+30>: mov eax,DWORD PTR [ebp+0x10] 0x08048550 <+33>: mov DWORD PTR [ebp-0x34],eax 0x08048553 <+36>: mov eax,gs:0x14 0x08048559 <+42>: mov DWORD PTR [ebp-0xc],eax ... 0x080485ab <+124>: mov edx,DWORD PTR [ebp-0xc] 0x080485ae <+127>: xor edx,DWORD PTR gs:0x14 0x080485b5 <+134>: je 0x80485bc <testfunc+141> 0x080485b7 <+136>: call 0x80486b0 <__stack_chk_fail_local> 0x080485bc <+141>: mov ebx,DWORD PTR [ebp-0x4]
In the first block, the canary is written. The second block is at the end of a function and checks the canary. To see the canary, we can add a breakpoint at the last instruction of the “canary prolog” at 0x08048559 and inspect the content of the eax register, which then contains the canary.
gdb-peda$ break *0x08048559 Breakpoint 1 at 0x8048559 gdb-peda$ run AAAAAAAAAAAAAAAAAAA BBB CCC ... Breakpoint 1, 0x08048559 in testfunc () gdb-peda$ x/i $eip => 0x8048559 <testfunc+42>: mov DWORD PTR [ebp-0xc],eax gdb-peda$ i r $eax eax 0xff0a0000 0xff0a0000 <= Canary
Let’s try it again with eight A’s — which still should be possible.
gdb-peda$ run AAAAAAAA BBBB CCCC ... Breakpoint 2, 0x0804856d in testfunc () gdb-peda$ x/20x $esp 0xffffd480: 0xffffd4b4 0xffffd709 0x00000000 0x0804853b 0xffffd490: 0xf7fb3c40 0xffffd717 0xffffd712 0xffffd709 0xffffd4a0: 0x080499f0 0xf7ffd940 0xf7e0ff65 0x0804851c 0xffffd4b0: 0x080486e0 0x41414141 0x41414141 0xff0a0000 0xffffd4c0: 0xf7fb33fc 0x080499f0 0xffffd4e8 0x08048621
Here are our A’s and the canary lies behind it. Good. Now lets try to further overwrite the stack and set the proper canary.
gdb-peda$ run "AAAAAAAA `echo -e '\x00\x00\x0a\xffAAAAAAAASSSSRRRR'`" BBBBBBBB CCCCCCCC ... Breakpoint 2, 0x0804856d in testfunc () gdb-peda$ x/20x $esp 0xffffd470: 0xffffd4a4 0xffffd6ee 0x00000000 0x0804853b 0xffffd480: 0xf7fb3c40 0xffffd713 0xffffd70a 0xffffd6ee 0xffffd490: 0x080499f0 0xf7ffd940 0xf7e0ff65 0x0804851c 0xffffd4a0: 0x080486e0 0x41414141 0x41414141 0x41ff0a20 0xffffd4b0: 0x41414141 0x53414141 0x52535353 0x00525252
That is not our canary. Bad. The problem is that our binary zeros were not copies because strcpy sees them as terminators.
Leave a Reply
You must be logged in to post a comment.