Vulnerability Development mailing list archives

Re: stackguard-like embedded protection


From: antirez <antirez () linuxcare com>
Date: Sun, 10 Sep 2000 11:01:56 +0200

On Sat, Sep 09, 2000 at 05:51:20PM -0700, Crispin Cowan wrote:
In order to implement the stackshield like protection embedded in the code
I used a simple trick that's not so portable but that is ok for i386
and the other arch that stores the RET on the stack. I store a variable
like volatile unsigned char magic[1] at the end so I'll get the RET
with magic[5-6-7-8], now I can store it outside the stack, every time
I enter in a function I store the old return address in order to
allow recursion. This is not a stack smashing solution, I'm coding this
little header and writing my impression in order to hack arround this
for the first time. Maybe, after this didactic work, I'll suggest some
idea.

I don't understand this explanation.  Can you elaborate on how you achieve
recursion?  Either you are implementing an alternate stack, or you are supporting
only a limited amount of recursion.  But from your explanation, I can't tell which,
or how you do it.

Using a stackguard-like protection the tester (canary) is secret.
So you needs to store it in some other place. Stackshield like protection
stores the return address, that is less critical since if someone
write it is a problem, but for example a read-only access isn't a problem.
Expecially if you can access in the stack only at the saved RET of the
previous function (this isn't so good english maybe..., I hope you understand)

Example: /* sorry if I assumed that sizeof(int) == sizeof(void*) */

static int __stackback_save_ret;

/* arch-related magic number */
#ifdef __i386__
#define SSMAGIC 5
#endif

void __stackback_overflow(void)
{
        syslog(LOG_AUTHPRIV|LOG_WARNING,
                "Stackback detected stack corruption (PID: %d)\n", getpid());
        _exit(1);
}

#define stackback_before_vars \
        volatile unsigned char __stackback_magic[1]

#define stackback_safe_enter \
        volatile int __stackback_old_save_ret = __stackback_save_ret; \
        memcpy(&__stackback_save_ret, (void*)&__stackback_magic[SSMAGIC], sizeof(int))

#define stackback_safe_leave \
        if (__stackback_save_ret != *((int*)&__stackback_magic[SSMAGIC])) \
                __stackback_overflow(); \
        __stackback_save_ret = __stackback_old_save_ret

this is a function protected:

void f(void)
{
        stackback_before_vars; /* befor all declarations */
        char buffer[100];
        stackback_safe_enter    /* after variables declaration */

        foo(); /* also protected */

        stackback_safe_leave    /* before all the return, and at the end */
        return;
}

I didn't use a limited number of recursion, nor an alternative stack.
Just I store the old saved ret on the stack itself, but it is the last
variable, so it's hard to overwrite. Also if foo() is vulnerable
you can modify the address of saved f() RET, that's not so critical.

Is this approach in your opinion too insecure?

If I'm right in order to exploit this you need: two buffer overflows,
one in f() and one in foo(), that's hard, and also the overflow of
the nested function must allow you to overwrite a var before the buffer
itself, i.e. you must overwrite with the buffer a pointer and so on.
But maybe there is a clear and simple attack that I'm not considering.

Note that this kind of protection have some problem at least with
-ffomit-frame-pointer option.

regards,
antirez

--
Salvatore Sanfilippo, Open Source Developer, Linuxcare Italia spa
+39.049.80 43 411 tel, +39.049.80 43 412 fax
antirez () linuxcare com, http://www.linuxcare.com/
Linuxcare. Support for the revolution.


Current thread: