Date: Sun, 4 May 1997 12:49:30 -0400 (EDT) From: Brian Tao <taob@nbc.netcom.ca> To: FREEBSD-SECURITY <freebsd-security@freebsd.org> Subject: Buffer Overflows: A Summary (fwd) Message-ID: <Pine.GSO.3.95.970504124904.5841n-100000@tor-adm1.nbc.netcom.ca>
next in thread | raw e-mail | index | archive | help
---------- Forwarded message ---------- Date: Wed, 30 Apr 1997 01:03:17 -0500 From: Aleph One <aleph1@DFW.NET> To: BUGTRAQ@NETSPACE.ORG Subject: Buffer Overflows: A Summary This is a short summary of the buffer overflow discussion on BugTraq. It will hopefully server to answer questions in a concise manner, and reduce the list traffic to what it normally is. As mentioned by Theo de Raadt, Michael Shields, Tim Newsham, and others the only real solution to buffer overflows is fixing the defective programs. Anything else is a stopgap measure. This by no means implies you should not use one or more of the alternatives as fall back methods. The more defenses the better. Just don't depend on them. Again the thing to do is fix the offending code. The OpenBSD project and some other teams have done a great job in this area. They have systematically gone through their code base looking for possible vulnerabilities. Not only have the fixed dozens of possible holes, at the same time they have made their software more reliable. Reliability and security go hand in hand. Another option is to use a language that implements bounds checking such as Ada, Java, or Perl. Richard Jones and Paul Kelly have developed patches to gcc that implement some bounds checking in C ( http://www-ala.doc.ic.ac.uk/~phjk/BoundsChecking.html ). There also exists commercial products such as Purify that attempt to help you identify this and other bugs. BSDI, OpenBSD and other operating systems have also modified the linker to generate warning messages when a program uses dangerous functions. This is no panacea since overflows not only occur in standard libraries nor are all uses of dangerous functions incorrect, but they will flag a program as suspicious. The C compiler and/or lint could be modified to attempt to catch obvious buffer overflows. The disadvantage is that not all possible overflows can be detected and such a modifications are not trivial. It's been suggested that you could modify the dangerous functions in the C library to perform a stack integrity check before returning. If the check does not pass, it would print a warning message and exit. The downside is that this method will not catch all buffer overflows and would introduce a performance penalty. Alexandre Snarskii has developed just such a patch for FreeBSD. ( ftp://ftp.lucky.net/pub/unix/local/libc-letter ) The security axiom of "least privilege" would insure that even if a program is compromised the privilege obtained by doing so is minimal. This is the case in Trusted Systems or systems implementing POSIX.1e (formerly POSIX.6) capabilities. Thomas Ptacek has developed kernel patches for FreeBSD that shifted the privilege of binding to a privileged port from root to a new uid. There is also a project underway to make Linux POSIX.1e compliant. If such facilities are not available the programs should be coded in such as way as to use their privilege in small, easy to audit, sections of code and then discard them as soon as possible by means of setreuid(2). Marking the stack non-executable will catch most cut and paste exploits but may break certain programs under some architectures and will not catch exploits that do not depend on an executable stack. As an example the Internet worm fingerd overflow overwrote the string "/usr/bin/finger" with "/bin/sh" in the data segment. Casper Dik developed a script that modifies the Solaris kernel so that the stack no longer has execute permission. Solar Designer made available a patch for Linux that performs a similar functionality. Search the BugTraq archives for both of them. Other more obscure solutions involve architecture changes as noted by Shawn Instenes. Such as if only the CALL instructions could put a return address on the stack, or having the OS enforce a "stack window" which limits where you can write in the stack. Or as pointed out by Zygo Blaxell you could allocate automatic variables on the heap or some other place that is not the stack. David Holland noted that new architectures could simply have multiple stacks: one for call frames, and one for automatic storage. It was suggested that the kernel should check in the exec system call to determine if a shell was being executed. Such a check would be of little use as the attacker may execute a file of any name in the filesystem. This path of thinking does lead to an interesting defense that I believe would be of great use and should be implemented. Most daemons and utilities will not exec a program. Most will simply fork. In such cases a system call that disabled any further calls to exec would stop all exploits that attempted to use the exec system call. Instead the kernel could print a warning message and call exit. This scheme could be extended to define an interface for a program to disable any system call that it did not need thus reducing the attackers options. To conclude, as we all know security is a risk management game. There is no such thing as 100% security. Even if you perform code reviews and QA testing bugs will creep into software. So your best bet is a multilayered approach to security. Would you rather have a vendor's or programmer's word that the code you are running in your security sensitive installation is safe, or recompile said code using a compiler that checks for buffer overflows and inserts bounds checking code, and run it in a machine that marks its stack non-executable and that allows you to turn off unnecessary system calls? I think the choice is obvious. Aleph One / aleph1@dfw.net http://underground.org/ KeyID 1024/948FD6B5 Fingerprint EE C9 E8 AA CB AF 09 61 8C 39 EA 47 A8 6A B8 01
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.GSO.3.95.970504124904.5841n-100000>