So, lets dive into some libSSP stuff, already.
Understanding Code
A dearth of information is available at the LFS SSP hints. Additionally, we should keep the actual GLIBC SSP implementation handy for looking through the code
Let's start, in fact, with the implementation and information from the LFS. Looking at the default, we see that the GlibC unix SSP code does the following:
The above code is the static defined, always inlined, C code which does the actual canary initialization.
An interesting bit to note is the use of the strong_alias'd functions - __open, __close, and __read. There's no way we will be able to hook the linker at any point to override these functions via a re-alias. The linker won't accept this. However, we do have one possible attack vector. If we can prevent the linker from being able to open /dev/urandom, then we can force a well known canary 0x00000aff into the stack, and have a viable attack vector for stack overflows.
Test Harness
In order to continue these exercises, it will be useful to build a test harness program for us to use. Throughout this paper, we'll expand on the code to continually improve our understanding of the actual specifics of the LibSSP mechanisms. For this code, the following assumptions are made:
- A Linux based Intel PC, capable of running 64-bit and 32-bit software.
- Ubuntu 10.04 (up-to-date as of Wed. March 22, 2011)
- Access to the GNU C compiler collection
- Access to the GNU Debugger
The following test program will be our first stab:
We'll compile the above code with: gcc -fstack-protector-all -m32 -o stack stack.c and then use gdb to see the assembler code that was generated.
The bolded lines above are where all of the important magic happens. We see that the eax register becomes populated with the value stored in %gs:14, and then that value is pushed onto the stack at -0xc(%ebp). Then, the absolute value '0' is moved, 4 bytes at a time, onto the stack just "after" it. So, our stack looks like:
- 16 bytes of 0 (this corresponds to char vbuf[16] = {0};)
- Canary
- return ptr
The 64-bit version looks similar. The only real differences are the use of 64-bit registers (%rax, %rbp, etc.), and that the canary comes from %fs:0x28
So, lets run the beast and see what crashes we can invoke.