Kragen wrote: > On Wed, 5 Aug 1998, Crispin Cowan wrote: > > <randomizing stack locations> > > It is also faster than the StackGuard approach, but probably not as effective. > > In particular, if the attacker uses the technique mentioned above, then they > > don't have to point the return address at a fixed point within the stack. > > StackGuard, on the other hand, will detect any buffer overflow that corrupts > > the return address. > As has occasionally been pointed out before, buffer overflows don't > need to overwrite a return address to be dangerous. If you can > overwrite a pointer to a function, a pointer to a structure containing > a pointer to a function, etc., you can still execute arbitrary code. We're working on an extension to StackGuard to address that problem. The idea is to place canaries next to other data structures that you care about. This is hard, because you have to mess with the compiler's type system, but we're part-way through doing it. > Randomizing stack locations can make all of these a little more difficult. Depending on the flavor of stack randomization, it might. The original proposal here is to start the stack at a random location, and otherwise leave it alone. That's easy to do, but will do absolutely nothing to prevent an overflow that, say, changes credential information. It mostly makes it hard to aim code pointers at injected code fragments, because you don't know their absolute address. If you can inject a BIG overflow, then you can use Aleph's NOP hack to partially overcome that problem. You can also inject your attack code into a static buffer and aim your code pointer at that. There's multiple parts to this problem, and each technique treats one or more parts of the problem: * array bounds: if you can prevent buffer overflows, you stop the problem at the source * critical data structures: if you can prevent or detect corruption of critical data structures (i.e. code pointers such as the stack return address, function pointers, longjmp buffers, etc., and other critical structures such as credential information, file paths, etc.) then you can prevent the attack from being exploited * injectable code: the attacker can inject code into ANY buffer without overflowing it. If you can make the absolute address of all such buffers hard to find, then it is hard for the attacker to point code pointers at the buffer with the attack code * resident code: the attacker doesn't necessarily have to inject code if the right code is already resident in the victim program. For instance, if the program already does "exec(mumble)" somewhere in there, then there is code in there that calls the exec() system call. The attacker can alter data and then jump to that resident code. > The bounds-checking folks are optimistic that bounds-checking can be > made much faster. ATM, it's 50%-80% overhead in general. That's interesting. Why do they think they can make such huge strides in the cost of bounds checking? I'd be impressed if they could make huge strides in stability, so that a bounds-checking C compiler could actually compile and run a sophisticated program. I have been unable to reproduce the BIND experiment where a bounds-checked BIND was said to run, but very slowly. Our experience with the Jones & Kelly bounds-checking compiler is that non-trivial programs compiled with it just die. I would be very happy to be pointed to a bounds-checking compiler that is stable. I mean no disrespect to Jones & Kelly, as I understand that bounds-checking is VERY difficult in C, and I'm impressed with how far they got with it. Crispin
This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:11:44 PDT