views:

255

answers:

6

Hello guys,

Can some one please tell me an approach for finding security flaws in a given code. For ex: in a given socket program. Any good examples or good book recommendations are welcome.

Thanks & Regards,

Mousey

A: 

I took a security class where we used a commercial product called Fortify 360, which did static analysis of C++ code. We ran it against an old-old-old version of OpenSSL, and it found loads of stuff, and provided guidance to rectify the flaws (which, by the way, the latest version of OpenSSL had resolved).

At any rate, it is a useful commercial tool.

kbrimington
+4  A: 

The lowest hanging fruit in this category would be to simply search the source for functions which are commonly misused or are difficult use safely such as:

  • strcpy
  • strcat
  • sprintf
  • gets

then start looking at ones that are not inherintly too bad, but could be misused. Particularly anything that writes to a buffer can potentially be hazardous if misused.

  • memcpy
  • memmove
  • recv/read
  • send/write
  • the entire printf family should always have a constant for the format string

NOTE: all of these (except gets) can be used correctly, so don't think it's a flaw just because the function is used, instead take a look at how it is used. Also note that gets is always a flaw.

NOTE2: this list is not exhaustive, do a little research about commonly misused functions and how they can be avoided.

As far as tools, I recommend things like valgrind and splint

Evan Teran
@Evan Teran Thank you very much. Also I would like to know how to find denial of service flaws
mousey
DoS attacks can be caused by a number of different issues. It can be deadlocks, logic bugs, crashes, or just having a design that is easily overwhelmed. For example having a server use a thread per client socket can often be DoS'd simply because it doesn't scale well on many OSes.
Evan Teran
Or even simpler, using blocking sockets with no timeout or upperlimit of characters can allow a DoSer to keep a connection alive and slowly exhaust all available sockets. There are really tons of ways to get attacked :-/.
Evan Teran
@Evan Teran Can you recommend a good book for learning these things please
mousey
@mousey: It is slightly dated but still has good advise (along with doing a good job of explaining how high level code translates to assembly): "Hacking: The Art of Exploitation, 2nd Edition". One of the chapters is pretty much a primer on C, if you are already very competent with C, you can skip that one.
Evan Teran
@Evan Teran Thank you very much.
mousey
Technically, `gets` is not always a flaw. If `stdin` was replaced by `freopen` with a file your program created in which it knows the maximum line length, it's safe. Yes this is a stretch, but it's partly to illustrate the extreme lengths you'd have to go to in order to ensure the safety of `gets`... ;-)
R..
BTW, I would add `strncpy` to the list of dangerous functions...
R..
I am able to find how all those functions fail except read/rcv and send/write. Can you please explain by an example.
mousey
@mousey: if you do something as simple as trying to calculate the buffer size and do so incorrectly, it can lead to memory corruption. For example, R..'s example of an integer overflow/underflow could make you think you can enough space, then you attempt to read into the surprisingly small buffer....game over.
Evan Teran
+1  A: 

Here's a book recommendation: Writing Secure Code. Demonstrates not only how to write secure code, but also common pitfalls and practices that expose security holes. It's slightly dated (my copy says it was published in 2002), but the security concepts it teaches are still quite applicable even 8 years later.

htw
@htw Is it for windows at application level or its applicable at kernel level too ? Also the book looks to concentrate on .Net Is it a good one for a C++ programmer too ?
mousey
Actually, there's only one chapter on .NET security—most of it is geared towards C programmers, specifically those using the native Win32 APIs. Is it applicable to the kernel level? I'd say so. While it is geared towards application developers, some of the stuff the book covers is definitely low-level enough to apply to kernel programming.
htw
@htw thank you very much
mousey
[Rob Slade's review](http://victoria.tc.ca/int-grps/books/techrev/bkwrsccd.rvw) is mixed ("some useful, but lots missing").
Gilles
+3  A: 

One major topic that wasn't covered in Evan's answer is integer overflows. Here are some examples:

wchar_t *towcs(const char *s)
{
    size_t l = strlen(s)+1;
    mbstate_t mbs = {0};
    wchar_t *w = malloc(l*sizeof *w), *w2;
    if (!w || (l=mbsrtowcs(w, (char **)&s, l, &st))==-1) {
        free(w);
        return 0;
    }
    return (w2=realloc(w, l*sizeof *w)) ? w2 : w;
}

Here, a giant string (>1gig on 32-bit) will make multiplication by the size (I'm assuming 4) overflow, resulting in a tiny allocation and subsequent writes past the end of it.

Another more common example:

uint32_t cnt;
fread(&cnt, 1, 4, f);
cnt=ntohl(cnt);
struct record *buf = malloc(cnt * sizeof *buf);

This sort of code turns up in reading file/network data quite a lot, and it's subject to the same sort of overflows.

Basically, any arithmetic performed on values obtained from an untrusted source, which will eventually be used as an allocation size/array offset, needs to be checked. You can either do it the cheap way (impose arbitrary limits on the value read that keep it significantly outside the range which could overflow, or you can test for overflow at each step: Instead of:

foo = malloc((x+1)*sizeof *foo);

You need to do:

if (x<=SIZE_MAX-1 && x+1<=SIZE_MAX/sizeof *foo) foo = malloc((x+1)*sizeof *foo);
else goto error;

A simple grep for malloc/realloc with arithmetic operators in its argument will find many such errors (but not ones where the overflow already occurred a few lines above, etc.).

R..
+1  A: 

Some source code constructs you can keep an eye out for are:

  • Functions that don't do bounds checking. Evan covered it pretty well.
  • Input validation & sanitization, or lack thereof.
  • NULL pointer dereferencing
  • fork()s, execve()s, pipe()s, system() called with non-static parameters (or worse, with user input).
  • Objects shared between threads with inappropriate storage durations (pointers to automatic variables or even "dead" objects in thread-local storage).
  • When dealing with file manipulation, make sure correct variable types are used for the return results of functions. Make sure they're checked for errors. Make no assumptions about the implementation - permissions of created files, uniqueness of filenames, etc.
  • Poor sources of randomness (for encryption, communication, etc.) should be avoided.
  • Simple or obvious mistakes (perhaps out of carelessness) should be fixed anyway. You never know what's exploitable, unless it is.

Also, are the data protected? Well, if you don't care, that's fine. :-)

Some tools that you can consider are:

  • valgrind : exposes memory flaws, which in large applications are usually critical.
  • splint : a static checker
  • fuzzing frameworks
  • RATS : a free, open-source tool. Its authors' company was acquired by Fortify.
Michael Foukarakis
great. Thank you very much.
mousey
A: 

Some of the OpenBSD folk just recently published a presentation on their coding practices.

pra