coverage guided fuzzing
play

Coverage-Guided Fuzzing Dynamic Static Smart Coverage Structure - PowerPoint PPT Presentation

Coverage-Guided Fuzzing Dynamic Static Smart Coverage Structure Algorithms Security Testing Andreas Zeller, Saarland University Our Goal We want to cause the program to fail We have seen random (unstructured) input


  1. Coverage-Guided Fuzzing Dynamic Static 
 Smart 
 Coverage Structure Algorithms Security Testing Andreas Zeller, Saarland University

  2. Our Goal • We want to cause the program to fail • We have seen • random (unstructured) input • structured (grammar-based) input • generation based on grammar coverage

  3. A Challenge class Roots { 
 // Solve ax 2 + bx + c = 0 
 public roots(double a, double b, double c) 
 { … } // Result: values for x 
 double root_one, root_two; 
 } • Which values for a, b, c should we test? 
 assuming a, b, c, were 32-bit integers, we’d have (2 32 ) 3 ≈ 10 28 legal inputs 
 with 1.000.000.000.000 tests/s, we would still require 2.5 billion years

  4. The Code // Solve ax 2 + bx + c = 0 
 public roots(double a, double b, double c) 
 { 
 double q = b * b - 4 * a * c; 
 if (q > 0 && a ≠ 0) { 
 Test this case // code for handling two roots 
 } else if (q == 0) { 
 and this // code for handling one root 
 } else { 
 and this! // code for handling no roots 
 } 
 }

  5. The Test Cases // Solve ax 2 + bx + c = 0 
 public roots(double a, double b, double c) 
 { 
 double q = b * b - 4 * a * c; 
 if (q > 0 && a ≠ 0) { 
 Test this case (a, b, c) = (3, 4, 1) // code for handling two roots 
 } else if (q == 0) { 
 and this (a, b, c) = (0, 0, 1) // code for handling one root 
 } else { 
 and this! (a, b, c) = (3, 2, 1) // code for handling no roots 
 } 
 }

  6. A Defect // Solve ax 2 + bx + c = 0 
 public roots(double a, double b, double c) 
 { 
 double q = b * b - 4 * a * c; 
 if (q > 0 && a ≠ 0) { 
 // code for handling two roots 
 } ↯ else if (q == 0) { 
 (a, b, c) = (0, 0, 1) x = (-b) / (2 * a); 
 } code must handle a = 0 else { 
 // code for handling no roots 
 } 
 }

  7. The Idea Use the program to guide test generation

  8. The Ingredients Dynamic Static 
 Smart 
 Coverage Structure Algorithms

  9. The Ingredients Dynamic Static 
 Smart 
 Coverage Structure Algorithms

  10. Expressing Structure // Solve ax 2 + bx + c = 0 
 public roots(double a, double b, double c) 
 { 
 double q = b * b - 4 * a * c; 
 if (q > 0 && a ≠ 0) { 
 // code for handling two roots 
 } else if (q == 0) { 
 x = (-b) / (2 * a); 
 } else { 
 // code for handling no roots 
 } 
 }

  11. Control Flow Graph public roots(double a, double b, double c) • A control flow graph expresses paths of program execution double q = b * b - 4 * a * c; • Nodes are basic blocks – q > 0 && a != 0 sequences of statements with // code for two roots one entry and one exit point q == 0 • Edges represent control flow – // code for one root the possibility that the program execution proceeds // code for no roots from the end of one basic block to the beginning of return another

  12. Structural Testing public roots(double a, double b, double c) • The CFG can serve as an double q = b * b - 4 * a * c; adequacy criterion for test q > 0 && a != 0 cases // code for two roots • The more parts are covered (executed), the higher the q == 0 chance of a test to uncover a // code for one root defect // code for no roots • “parts” can be: nodes, edges, paths, conditions… return

  13. Control Flow Patterns while ( COND ) do for BODY BODY INIT while ( COND ) while ( COND ) COND BODY ; do { BODY BODY if ( COND ) } while ( COND ); INCR THEN-BLOCK ELSE-BLOCK for ( INIT; COND; INCR) if ( COND ) BODY ; THEN-BLOCK; else ELSE-BLOCK ;

  14. cgi_decode /** 
 /** 
 * @title cgi_decode 
 * @title cgi_decode 
 * @desc 
 * @desc 
 * Translate a string from the CGI encoding to plain ascii text 
 * Translate a string from the CGI encoding to plain ascii text 
 * ’+’ becomes space, %xx becomes byte with hex value xx, 
 * ’+’ becomes space, %xx becomes byte with hex value xx, 
 * other alphanumeric characters map to themselves 
 * other alphanumeric characters map to themselves 
 * 
 * 
 * returns 0 for success, positive for erroneous input 
 * returns 0 for success, positive for erroneous input 
 * 1 = bad hexadecimal digit 
 * 1 = bad hexadecimal digit 
 */ */ int cgi_decode(char *encoded, char *decoded) int cgi_decode(char *encoded, char *decoded) { 
 { 
 char *eptr = encoded; 
 char *eptr = encoded; 
 char *dptr = decoded; 
 char *dptr = decoded; 
 A int ok = 0; int ok = 0;

  15. B while (*eptr) /* loop to end of string (‘\0’ character) */ 
 while (*eptr) /* loop to end of string (‘\0’ character) */ 
 { 
 { 
 char c; 
 char c; 
 C c = *eptr; 
 c = *eptr; 
 if (c == ’+’) { /* ‘+’ maps to blank */ 
 if (c == ’+’) { /* ‘+’ maps to blank */ 
 E *dptr = ’ ’; *dptr = ’ ’; } else if (c == ’%’) { /* ’%xx’ is hex for char xx */ 
 } else if (c == ’%’) { /* ’%xx’ is hex for char xx */ 
 D int digit_high = Hex_Values[*(++eptr)]; 
 int digit_high = Hex_Values[*(++eptr)]; 
 G int digit_low = Hex_Values[*(++eptr)]; int digit_low = Hex_Values[*(++eptr)]; if (digit_high == -1 || digit_low == -1) 
 if (digit_high == -1 || digit_low == -1) 
 I ok = 1; /* Bad return code */ ok = 1; /* Bad return code */ else 
 else 
 H *dptr = 16 * digit_high + digit_low; *dptr = 16 * digit_high + digit_low; } else { /* All other characters map to themselves */ 
 } else { /* All other characters map to themselves */ 
 *dptr = *eptr; 
 *dptr = *eptr; 
 F } } ++dptr; ++eptr; 
 ++dptr; ++eptr; 
 L } } *dptr = ‘\0’; /* Null terminator for string */ 
 *dptr = ‘\0’; /* Null terminator for string */ 
 M return ok; 
 return ok; 
 } }

  16. int cgi_decode(char *encoded, char *decoded) A A { char *eptr = encoded; char *dptr = decoded; int ok = 0; B while (*eptr) { B False True C char c; C c = *eptr; if (c == '+') { False True D D E E *dptr = ' '; elseif (c == '%') { } True False else F G F G int digit_high = Hex_Values[*(++eptr)]; *dptr = *eptr; int digit_low = Hex_Values[*(++eptr)]; } if (digit_high == -1 || digit_low == -1) { False True H I H I else { ok = 1; } *dptr = 16 * digit_high + digit_low; } L ++dptr; L ++eptr; M M *dptr = '\0'; } return ok; }

  17. int cgi_decode(char *encoded, char *decoded) “test” A ✔ A { char *eptr = encoded; char *dptr = decoded; int ok = 0; B ✔ while (*eptr) { B False True C ✔ char c; C c = *eptr; if (c == '+') { False True D E D E ✔ *dptr = ' '; elseif (c == '%') { } False True else F F G G ✔ int digit_high = Hex_Values[*(++eptr)]; *dptr = *eptr; int digit_low = Hex_Values[*(++eptr)]; } if (digit_high == -1 || digit_low == -1) { True False H I H I ok = 1; else { } *dptr = 16 * digit_high + digit_low; } ✔ L ++dptr; L ++eptr; M ✔ *dptr = '\0'; M } return ok; }

  18. int cgi_decode(char *encoded, char *decoded) “test” “a+b” A ✔ A { char *eptr = encoded; char *dptr = decoded; int ok = 0; B ✔ while (*eptr) { B False True C ✔ char c; C c = *eptr; if (c == '+') { False True D D E E ✔ ✔ *dptr = ' '; elseif (c == '%') { } True False else F G ✔ F G int digit_high = Hex_Values[*(++eptr)]; *dptr = *eptr; int digit_low = Hex_Values[*(++eptr)]; } if (digit_high == -1 || digit_low == -1) { False True H I H I else { ok = 1; } *dptr = 16 * digit_high + digit_low; } ✔ L ++dptr; L ++eptr; M ✔ M *dptr = '\0'; } return ok; }

  19. int cgi_decode(char *encoded, char *decoded) “test” “a+b” A ✔ A { char *eptr = encoded; “%3d” char *dptr = decoded; int ok = 0; B ✔ while (*eptr) { B False True C ✔ char c; C c = *eptr; if (c == '+') { False True D D E E ✔ ✔ *dptr = ' '; elseif (c == '%') { } True False else F G ✔ F ✔ G int digit_high = Hex_Values[*(++eptr)]; *dptr = *eptr; int digit_low = Hex_Values[*(++eptr)]; } if (digit_high == -1 || digit_low == -1) { False True H I ✔ H I else { ok = 1; } *dptr = 16 * digit_high + digit_low; } ✔ L ++dptr; L ++eptr; M ✔ M *dptr = '\0'; } return ok; }

  20. int cgi_decode(char *encoded, char *decoded) “test” “a+b” A ✔ A { char *eptr = encoded; “%3d” char *dptr = decoded; int ok = 0; “%g” B ✔ while (*eptr) { B False True C ✔ char c; C c = *eptr; if (c == '+') { False True D D E E ✔ ✔ *dptr = ' '; elseif (c == '%') { } True False else F G ✔ F ✔ G int digit_high = Hex_Values[*(++eptr)]; *dptr = *eptr; int digit_low = Hex_Values[*(++eptr)]; } if (digit_high == -1 || digit_low == -1) { False True H I ✔ ✔ H I else { ok = 1; } *dptr = 16 * digit_high + digit_low; } ✔ L ++dptr; L ++eptr; M ✔ M *dptr = '\0'; } return ok; }

  21. Test Adequacy Criteria • How do we know a test suite is "good enough"? • A test adequacy criterion is a predicate that is true or false for a pair ⟨ program, test suite ⟩ • Usually expressed in form of a rule – 
 e.g., "all statements must be covered"

  22. Statement Testing • Adequacy criterion: each statement 
 (or node in the CFG) must be executed at least once • Rationale: a defect in a statement can only be revealed by executing the defect • Coverage: # executed statements 
 # statements

Recommend


More recommend