On Fri, Jan 18, 2002 at 09:20:16PM +0100, Vincent wrote: > Hi all ! > > I'm working on buffer overflows these days, and more precisely the possible > methods to avoid them. > It seems that the most used tools to prevent exploits based on buffer > overflows are Libsafe, OpenWall, StackGuard... and maybe Saint Jude. > > Has anyone any interesting comments about theses methods ?
I would like to comment on another method, if you don't mind. I few years ago I was after buffer overflows just as you. What I wanted was to make a programme which parses the C (or whatever) source code and checks if it is possible a buffer overflow to occur if the programme is fed suitable input data. The idea was simple: 1. For each code block (what is put in curly braces ("{", "}") in C) check what condition(s) should be met so that an overflow occurs. 2. Then exclude those conditions at which the block is not entered at all. 3. Repeat this procedure until the main () function's block is finished. 4. Do this for all blocks in the source code. Of course this may be hard to achieve if the, let's say, C code is mixed with assembler or even machine code; however, it seems applicable for most "normal" programmes. A few examples: /* Fool a programme using the above idea: */ typedef void (*VoidFunc) (void); int main (void) { char machine_code [] = "\x00\x01"; VoidFunc machine_func = (VoidFunc) machine_code; machine_func (); return (0); } /* End of example 1. */ /* Overflow that would be caught: */ #include <stdlib.h> #include <string.h> int main (int argc, char *argv[]) { /* Always enered. */ /* argv has argc elements (by definition). */ char *buf; unsigned int str_len1, str_len2, c; if ( argc != 3 ) { /* Entered when argc != 3. */ return (1); /* The execution of the enclosing block is terminated. */ } /* Reached when !(argc != 3) <=> argc == 3. */ str_len1 = strlen (argv [0]); /* Overflow when: 1. 0 > argc-1 <=> 0 > 2. */ /* => No overflow. */ str_len2 = strlen (argv [1]); /* Overflow when: 1. 1 > argc-1 <=> 1 > 2. */ /* => No overflow. */ buf = (char*) malloc (sizeof (char) * (str_len1+str_len2)); /* buf has (sizeof (char)*(str_len1+str_len2)) / sizeof (char) == (str_len1+str_len2) elements. */ for ( c = 0; c < str_len1; c++ ) { /* Entered when c < str_len1. */ buf [c] = argv [0][c]; /* Overflow when: 1. c >= (str_len1+str_len2) 2. 0 > argc-1 <=> 0 > 2. 3. c > strlen (argv [0]) <=> c > str_len1. */ /* => No overflow. */ } /* Reached when c == str_len1. */ for ( c = 0; c < str_len2; c++ ) { /* Entered when c < str_len2. */ buf [c+str_len1] = argv [1][c]; /* Overflow when: 1. c+str_len1 >= (str_len1+str_len2) <=> c >= str_len2. 2. 1 > argc-1 <=> 1 > 2. 3. c > strlen (argv [1]) <=> c > str_len2. */ /* => No overflow. */ } /* Reached when c == str_len2. */ buf [c+str_len1] = '\0'; /* Overflow when: 1. c+str_len1 >= (str_len1+str_len2) <=> c >= str_len2 */ /* => Overflow, because of 1. */ return (0); /* End of processing. */ } /* End of example 2. */ I have wasted so much of your time in the hope that someone might get interested and volunteer for creating such a tool. I myself gave up before finishing even the C parser, since I was on my own and the project required kilobytes of code. Thanks, and sorry for the time I took, -- Pav