Bugtraq mailing list archives
Re: machine independent protection from stack-smashing attack
From: John Viega <viega () LIST ORG>
Date: Tue, 15 Aug 2000 08:26:56 -0700
On Tue, Aug 15, 2000 at 01:55:47PM +0900, Hiroaki Etoh wrote:
On 2000/08/11 01:05:57 John Viega wrote:In particular, you fall prone to the problem that Crispan recently had to fix with StackGuard; the canary is not bound to the actual return address, so in some cases it is possible to "jump" the canary. You are using boundary canarys instead of xor canarys. Sure, you're lining up arrays next to each other, but that doesn't solve every case. Consider the following example, slightly modified from the StackGuard page: foo(char * arg) { char * p[1]; // a vulnerable pointer char a[25]; // the buffer that makes the pointer vulnerable p[0] = arg; gets(a); // using gets() makes you vulnerable gets(p[0]); // this is the good part }ProPolice generates the following activation record for the above program. | arg | return address | previous frame pointer | GUARD | array a | array *p | It means that you can not change the value of char *p[0] after the buffer overflow of the array a. This protection is derived from the analysis of the vulnerability of XOR random canary protection. I will post the vulnerability memo after Crispan's permission.
Okay. So you're placing all character arrays at the beginning of a function, and then the rest of the arrays next. That's definitely a lot better than what we thought you were doing. However, it just isn't as complete a solution as StackGuard (w/ XOR canaries) is. What if I have a multidimensional array of characters that I treat as an array of fixed-size strings? Where do you put that in your ordering? Then there are all the cases where the user takes the address of a non-pointer variable and uses it as a pointer. Then there is the problem of strings in stack allocated structs. Ultimately, the protection model you have put forward is definitely a lot better than nothing. I will agree that the cases that allow for attacks probably aren't all that common. But as a programmer, I would prefer to not have to wory about return address modification at all. ProPolice doesn't afford me that. I am willing to believe at this point that StackGuard probably does, though.
As for the portability of ProPolice, ProPolice uses a termination canary if it fails to open the device "/dev/random". I think the terminator canary protection introduced by Crispin Cowan is as safe as the random canary protection IF the previous frame pointer of the activation record is protected. Speaking the implementation of ProPolice, When ProPolice fails to open the device "/dev/random", it uses a series of characters "00", "00", "0a" and "ff" as a terminator canary. I think this is portable.
Of course, if you're memcpy'ing out of argv, off the network or out of an environment variable, then a terminator canary won't work. There are other situations where it won't work. Again, you're only stopping the most common problems of this type, and not all problems, which is why I'd much rather use StackGuard. In short, your attempts to gain better portability when compared to StackGuard leave you with a technology where a lot can go wrong. Yes, it probably won't be possible for things to go wrong in most cases, but when it is possible, the rarity of the occurance doesn't matter. I don't think portability was ever much of an issue for StackGuard (as long as you stick to GCC). The only thing StackGuard has to do that isn't strictly portable is add a small bit of asm to the function prologue and epilogue. That code is incredibly easy to port, though! If a reasonably talented person (e.g., someone who has done a reasonable amount of compiler work, such as a GCC maintainer) had a good asm reference for any architecture, it would be incredibly easy to write the code for that architecture. Heck, in the average case, you could probably even get away without testing your changes. Of course, canaries requiring randomness need a reasonable entropy source. And if you don't use an XOR canary w/ StackGuard, then ProPolice protection would definitely be better. Thankfully, something like TrueRand is pretty portable. John
Current thread:
- machine independent protection from stack-smashing attack Hiroaki Etoh (Aug 09)
- Re: machine independent protection from stack-smashing attack John Viega (Aug 10)
- Re: machine independent protection from stack-smashing attack Yarrow Charnot (Aug 15)
- Re: machine independent protection from stack-smashing attack Ariel Waissbein (Aug 18)
- PRNGs (was Re: machine independent protection from stack-smashing attack) John Viega (Aug 18)
- Re: PRNGs (was Re: machine independent protection from stack-smashingattack) Crispin Cowan (Aug 18)
- Re: PRNGs (was Re: machine independent protection from stack-smashingattack) Andrea Glorioso (Aug 21)
- Re: PRNGs (was Re: machine independent protection from stack-smashingattack) John Viega (Aug 22)
- Re: machine independent protection from stack-smashing attack Yarrow Charnot (Aug 15)
- Re: machine independent protection from stack-smashing attack John Viega (Aug 10)
- Re: machine independent protection from stack-smashing attack Gerardo Richarte (Aug 18)
- <Possible follow-ups>
- Re: machine independent protection from stack-smashing attack Hiroaki Etoh (Aug 15)
- Re: machine independent protection from stack-smashing attack John Viega (Aug 15)
- Re: machine independent protection from stack-smashing attack der Mouse (Aug 18)