/***************************************************************************** FunctionFault.c: Interposition library to capture function calls from the libc and attack the system by returning invalid values By: Miguel Torres Computer Science, Mississippi State University September 2003 Based on: Profiling and tracind gynamic library usage via interposition (Timothy Curry) Generation of application level audit data via library interposition (Kuperman and Spafford, 1999) The Thesis work by German Florez at the CCSR at Mississippi State University ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "signal.h" #include // For Random Generation #include "randomlib.h" // Sets the Seeds for the random generator #define RANDOM (double)random()/RAND_MAX //#define RANDOM (double)random((time(NULL))%31328)/RAND_MAX #define INIT_RANDS \ srand(time(NULL)); \ RandomInitialise((int)(time(NULL)*RANDOM)%31328,(int)(time(NULL)*RANDOM)%30081); // Probability of start an attack #define KILLPROC_ 1 // from 1 to 100 #define SLEEPPROC_ 10 // from 1 to 100 // WEIBULL DISTRIBUTION PARAMETERS A>0, B>0 #define _ALPHA 1.0 #define _BETA 1.0 // Attack of Libc functions void attackKillorSleep(); #define TRUE 1 #define FALSE 0 static int DoProfile=TRUE; #ifdef ATTACK // Attacks the fopen function FILE *fopen(const char *filename, const char *mode) { // data referent to the real function typedef FILE*(*function_type) (const char *filename, const char *mode); static function_type function=NULL; static char* function_name="fopen"; static int first_time=TRUE; FILE *retval; // Search for the next function that fits the especification of function_name if (!function){ function = (function_type) dlsym(RTLD_NEXT,function_name); } // If the profiling is active if (DoProfile){ // Attack DoProfile =FALSE; #ifdef PRINT_OUTPUT printf("_FopenProfiling\n"); fflush(stdout); #endif /* ** Seed the random number generator with the current time ** of day if we haven't done so yet. */ if( first_time ){ first_time = FALSE; // Random Generation INIT_RANDS } // Attack of Libc functions attackKillorSleep(); retval = ((*function)(filename,mode)); // Attack DoProfile = TRUE; } else //do not profile, only execute retval = ((*function)(filename,mode)); return (retval); } /* Closes a stream. fclose closes the named stream. All buffers associated with the stream are flushed before closing. System-allocated buffers are freed upon closing. Buffers assigned with setbuf or setvbuf are not automatically freed. */ int fclose(FILE *stream) { typedef int(*function_type) (FILE *stream); static function_type function=NULL; static char* function_name="fclose"; static int first_time=TRUE; int retval; if (!function){ function = (function_type) dlsym(RTLD_NEXT,function_name); } if (DoProfile){ // Attack DoProfile =FALSE; #ifdef PRINT_OUTPUT printf("_FcloseProfiling\n"); fflush(stdout); #endif /* ** Seed the random number generator with the current time ** of day if we haven't done so yet. */ if( first_time ){ first_time = FALSE; // Random Generation INIT_RANDS } // Attack of Libc functions attackKillorSleep(); retval = ((*function)(stream)); // Attack DoProfile = TRUE; } else //do not profile, only execute retval = ((*function)(stream)); return (retval); } /*Description Writes to a stream. fwrite returns a NULL pointer randomly. */ size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream) { // The actual function typedef size_t(*function_type) (const void *ptr, size_t size, size_t n, FILE *stream); static function_type function=NULL; static char* function_name="fwrite"; // Sets the seed for the random number generator size_t retval; static int first_time=TRUE; if (!function){ function = (function_type) dlsym(RTLD_NEXT,function_name); } #ifdef PRINT_OUTPUT printf("_W %d\n",DoProfile); fflush(stdout); #endif if (DoProfile){ #ifdef PRINT_OUTPUT printf("_WProfiling\n"); fflush(stdout); #endif /* ** Seed the random number generator with the current time ** of day if we haven't done so yet. */ if( first_time ){ first_time = FALSE; // Random Generation INIT_RANDS } // Attack of Libc functions attackKillorSleep(); //execute the funtion and then profile retval = ((*function)(ptr,size,n,stream)); // Attack DoProfile = TRUE; } else //do not profile, only execute retval = ((*function)(ptr,size,n,stream)); return (retval); } /* Reads data from a stream. fread does not read randomly and returns NULL */ size_t fread(void *ptr, size_t size, size_t n, FILE *stream) { typedef size_t(*function_type) (const void *ptr, size_t size, size_t n, FILE *stream); static function_type function=NULL; static char* function_name="fread"; // Sets the seed for the random number generator static int first_time=TRUE; size_t retval; if (!function){ function = (function_type) dlsym(RTLD_NEXT,function_name); } #ifdef PRINT_OUTPUT printf("_R %d\n",DoProfile); fflush(stdout); #endif if (DoProfile){ // Attack DoProfile =FALSE; #ifdef PRINT_OUTPUT printf("_WProfiling\n"); fflush(stdout); #endif /* ** Seed the random number generator with the current time ** of day if we haven't done so yet. */ if( first_time ){ first_time = FALSE; // Random Generation INIT_RANDS } // Attack of Libc functions attackKillorSleep(); //execute the funtion and then profile retval = ((*function)(ptr,size,n,stream)); // Attack DoProfile = TRUE; } else //do not profile, only execute retval = ((*function)(ptr,size,n,stream)); return (retval); } /* malloc allocates a block of size bytes from the memory heap. It allows a program to allocate memory explicitly as it's needed, and in the exact amounts needed this function also randomly returns a NULL value. */ void* malloc (size_t size) { typedef void*(*function_type) (size_t size); static function_type function=NULL; static char* function_name="malloc"; static int first_time=TRUE; void* retval; if (!function){ function = (function_type) dlsym(RTLD_NEXT,function_name); } #ifdef PRINT_OUTPUT printf("_MA %d\n",DoProfile); fflush(stdout); #endif if (DoProfile){ // Attack DoProfile =FALSE; #ifdef PRINT_OUTPUT printf("_MAProfiling %d\n",DoProfile); fflush(stdout); #endif /* ** Seed the random number generator with the current time ** of day if we haven't done so yet. */ if( first_time ){ first_time = FALSE; // Random Generation INIT_RANDS } // Attack of Libc functions attackKillorSleep(); //execute the funtion and then profile retval = ((*function)(size)); // Attack DoProfile = TRUE; } else //do not profile, only execute retval = ((*function)(size)); return (retval); } /* Copies a block of n bytes. memcpy is available on UNIX System V systems. memcpy copies a block of n bytes from src to dest. If src and dest overlap, the behavior of memcpy is undefined. */ void *memcpy(void *dest, const void *src, size_t n) { typedef void*(*function_type) (void *dest, const void *src, size_t n); static function_type function=NULL; static char* function_name="memcpy"; void* retval; static int first_time=TRUE; if (!function){ function = (function_type) dlsym(RTLD_NEXT,function_name); } #ifdef PRINT_OUTPUT printf("_MC %d\n",DoProfile); fflush(stdout); #endif if (DoProfile){ // Attack DoProfile = FALSE; #ifdef PRINT_OUTPUT printf("_MCProfiling %d\n",DoProfile); fflush(stdout); #endif /* ** Seed the random number generator with the current time ** of day if we haven't done so yet. */ if( first_time ){ first_time = FALSE; // Random Generation INIT_RANDS } // Attack of Libc functions attackKillorSleep(); //execute the funtion and then profile retval = ((*function)(dest, src, n)); // Attack DoProfile = TRUE; } else //do not profile, only execute retval = ((*function)(dest, src, n)); return (retval); } /* void attackKillorSleep() attacks a function by delaying its execution or by killing the process that calls it*/ void attackKillorSleep(){ /* Store the original parent id*/ int originalPID=getpid(); double randNumber = RandomDouble(0.0,100.0); #ifdef PRINT_OUTPUT printf("First (kill):%d\n",randNumber); fflush(stdout); #endif if(randNumber<=KILLPROC_){ /* KILL THE PARENT PROCESS */ kill(originalPID,SIGKILL); } else{ randNumber = RandomDouble(0.0,100.0); #ifdef PRINT_OUTPUT printf("Second (sleep): %d\n",randNumber); fflush(stdout); #endif if(randNumber<=SLEEPPROC_){ /* HALTS THE PARENT PROCESS FOR A SPECIFIC AMOUNT OF TIME between 3 to 10 seconds */ kill(originalPID,SIGSTOP); randNumber = RandomWeibull(_ALPHA,_BETA); #ifdef PRINT_OUTPUT printf("Time to sleep: %d\n",randNumber); fflush(stdout); #endif usleep ((int)randNumber*1000000); kill(originalPID,SIGCONT); } } } #endif