software security
play

Software Security Dynamic analysis and fuzz testing Bhargava - PowerPoint PPT Presentation

Software Security Dynamic analysis and fuzz testing Bhargava Shastry Prof. Jean-Pierre Seifert Security in Telecommunications TU Berlin SoSe 2016 1 / 21 Introduction What is this lecture about? How do we find bugs in programs? ... by


  1. Software Security Dynamic analysis and fuzz testing Bhargava Shastry Prof. Jean-Pierre Seifert Security in Telecommunications TU Berlin SoSe 2016 1 / 21

  2. Introduction What is this lecture about? How do we find bugs in programs? ... by executing an open-source program ... applies to binary code in principle Let’s recap Last lecture, we discussed static analysis → Find bugs without program execution How does it compare with Dynamic analysis? Pros and cons? 2 / 21

  3. Motivation Why do this? Find an input to the program that leads to undefined/insecure behavior Typically, we are looking for an input that crashes a program Program crashes provide an entry point to craft exploits → Not all program crashes are exploitable Technically, this is just another way to find bugs in programs 3 / 21

  4. Outline Fuzz testing Black-box vs. White-box testing Dynamic analysis Limitations Conclusion 4 / 21

  5. Example 1 Which input make this program crash? 1 #i n c l u d e < s t d i o . h > 2 #i n c l u d e < u n i s t d . h > 3 #i n c l u d e < s t d l i b . h > 4 #i n c l u d e < s t r i n g . h > 5 6 i n t main ( i n t argc , char ∗ argv [ ] ) { 7 8 char buf [ 2 0 ] ; 9 10 while ( AFL LOOP (1000) ) { 11 memset ( buf , 0 , 20) ; 12 i f ( read (0 , buf , 19) < 0) { 13 p e r r o r ( ” read ” ) ; 14 return 1 ; 15 } 16 17 i f ( buf [ 0 ] != ’ p ’ ) 18 p r i n t f ( ” f i r s t l e t t e r i s not p \ n” ) ; 19 e l s e i f ( buf [ 1 ] != ’w ’ ) 20 p r i n t f ( ” second l e t t e r i s not w \ n” ) ; 21 e l s e i f ( buf [ 2 ] != ’ n ’ ) 22 p r i n t f ( ” t h i r d l e t t e r i s not n \ n” ) ; 23 e l s e 24 abort () ; 25 26 p r i n t f ( ” buf c o n t a i n s %s \ n” , buf ) ; 27 } 28 0 ; return 29 } 5 / 21

  6. 1 #i n c l u d e < s t d i o . h > 2 #i n c l u d e < u n i s t d . h > 3 #i n c l u d e < s t d l i b . h > 4 #i n c l u d e < s t r i n g . h > 5 6 i n t main ( i n t argc , char ∗ argv [ ] ) { 7 8 char buf [ 2 0 ] ; 9 10 while ( AFL LOOP (1000) ) { 11 memset ( buf , 0 , 20) ; 12 ( read (0 , buf , 19) < 0) { i f 13 p e r r o r ( ” read ” ) ; 14 1 ; return 15 } 16 17 ( buf [ 0 ] != ’ p ’ ) i f 18 p r i n t f ( ” f i r s t l e t t e r i s not p \ n” ) ; 19 ( buf [ 1 ] != ’w ’ ) e l s e i f 20 p r i n t f ( ” second l e t t e r i s not w \ n” ) ; 21 ( buf [ 2 ] != ’ n ’ ) e l s e i f 22 p r i n t f ( ” t h i r d l e t t e r i s not n \ n” ) ; 23 e l s e 24 abort () ; 25 26 p r i n t f ( ” buf c o n t a i n s %s \ n” , buf ) ; 27 } 28 return 0 ; 29 } pwn 1 1 Pwn is a leetspeak slang term derived from the verb own, as meaning to appropriate or to conquer to gain ownership. - Wikipedia 6 / 21

  7. Fuzz testing aka Fuzzing Idea attributed to Prof.Barton Miller (Miller, Fredriksen, & So, 1990) . . . i n the F a l l of 1988 , t h e r e was a w i l d midwest thunderstorm . . . With the heavy rain , t h e r e was n o i s e on the ( d i a l − up ) l i n e and that n o i s e was i n t e r f e r i n g with my a b i l i t y to type s e n s i b l e commands to the s h e l l . − Prof . M i l l e r Feed random inputs to a program → No knowledge of program internals Idea bore very good initial results → crash or hang between 25-33% of the Unix utility programs 7 / 21

  8. Let’s fuzz! 8 / 21

  9. Black-box testing Black-box testing treats the program under test as a black-box (opaque to tester) This means the testing framework feeds random inputs to the program However, random inputs alone are unlikely to trigger bugs x = 1000 / ( input + 100000 ) , how long will it take the fuzzer to feed input = − 100000? Fuzzing, in its initial form, was conceived as a black-box testing technique Ever since, it has evolved into a white box testing technique State of the art fuzzers like afl (Zalewski, n.d.) “learn” from program behavior 9 / 21

  10. White-box testing While-box testing treats the PUT as a white-box (transparent to tester) Program internals can be used to reduce input search space Techniques: Program coverage guided fuzzing, Concolic execution etc. However, these need a model that abstracts program behavior for generating inputs Uses program instrumentation to realize the model = ⇒ Access to program binary or source code Instrumentation may be static (compile-time) or dynamic (run-time) 10 / 21

  11. Coverage guided fuzzing Fuzz inputs based on program coverage information For instance, retain only those input mutations that lead to new coverage 11 / 21

  12. Example Each colour indicates a different program path 1 #i n c l u d e < s t d i o . h > 2 #i n c l u d e < u n i s t d . h > 3 #i n c l u d e < s t d l i b . h > 4 #i n c l u d e < s t r i n g . h > 5 6 i n t main ( i n t argc , char ∗ argv [ ] ) { 7 8 . . . 9 . . . 10 11 i f ( buf [ 0 ] != ’ p ’ ) 12 // buf [ 0 ] != ’ p ’ 13 p r i n t f ( ” f i r s t l e t t e r i s not p \ n” ) ; 14 e l s e i f ( buf [ 1 ] != ’w ’ ) 15 // buf [ 0 ] == ’ p ’ && buf [ 1 ] != ’w ’ 16 p r i n t f ( ” second l e t t e r i s not w \ n” ) ; 17 e l s e i f ( buf [ 2 ] != ’ n ’ ) 18 // buf [ 0 ] == ’ p ’ && buf [ 1 ] == ’w ’ && buf [ 2 ] != ’ n ’ 19 p r i n t f ( ” t h i r d l e t t e r i s not n \ n” ) ; 20 e l s e 21 // buf [ 0 ] == ’ p ’ && buf [ 1 ] == ’w ’ && buf [ 2 ] == ’ n ’ 22 abort () ; 23 24 . . . 25 . . . 26 } 12 / 21

  13. Instrumentation But how does the fuzzer know which program path was taken? Answer: Instrument the program What does the instrumentation look like? cur_location = random-number; shared_mem[cur_location ˆ prev_location]++; prev_location = cur_location >> 1; Each branch point indexes a byte in global state State captures number of times branch point taken Comparing state changes per input, it is possible to filter seemingly redundant inputs 13 / 21

  14. Thought experiment Is the state captured by the instrumentation good enough? In other words, can you think of an example where the instrumentation might discard potentially crashing inputs Only a heuristic → But, turns out to be very good in practice 14 / 21

  15. Type of instrumentation Program instrumentation can be done at compile-time or at run-time Compile-time instrumentation incurs low performance overhead Checking logic can be optimized before-hand Slow down only because of additional instructions and associated I/O But, hard to encode checking logic for dynamic language features in general Run-time instrumentations incurs relatively high overhead Checking logic needs to be inserted at program run time Typically implemented using binary translation = ⇒ very slow Since instrumentation occurs at run time, dynamism (e.g., indirect branches) can be handled relatively easily Rest of the lecture looks at dynamic analyses that use compile-time instrumentation 15 / 21

  16. Dynamic analysis Why bother if a good fuzzer gives us crashing inputs? A normal program crash happens only when there is a serious problem Example: Segmentation fault, assertion failure, stack canary failures etc. But, it does not uncover latent faults Example: Heap corruption, stack corruption but canary intact etc. Dynamic analysis can help uncover latent faults Can be used in conjunction with a fuzzer for proactive security audits 16 / 21

  17. AddressSanitizer AddressSanitizer (Serebryany, Bruening, Potapenko, & Vyukov, 2012) is an instrumentation framework for detecting multiple classes of memory corruption faults Heap/stack buffer overflows, use-after-free bugs Idea is similar to coverage guided fuzzing i.e., insert bounds checks by instrumenting the program Each word of addressable heap maps to a byte of shadow memory Uses custom memory allocation functions to set shadow byte during allocation Uses shadow lookups during load and store instructions to detect faults e.g. loading from/storing to unaddressable memory location 17 / 21

  18. ASan Instrumentation Every 8-byte aligned word on x86 64 has 9 states First n bytes 0 ≤ n ≤ 8 are addressable, rest not = ⇒ 1 shadow byte for 8 bytes of application memory Instrumentation looks like char *shadow = MemToShadow(addr); if (*shadow && *shadow <= func(addr)) ReportError(addr) ... 18 / 21

  19. Limitations Fuzz testing and dynamic analysis covered in the lecture are program-input centric This means, if a fuzzed input cannot uncover a program path, bugs in that program path cannot be found Data on false negatives (bugs missed) by fuzzers is hard to come by Exception: Recent research on bug insertion (Dolan-Gavitt et al., 2016) Preliminary results show that only 10% of inserted bugs found by a SotA fuzzer Future: Use symbolic execution to maximize path coverage? Awaiting a public study of efficacy 19 / 21

  20. Conclusions Dynamic analysis attempts to uncover bugs during program execution We discussed fuzz testing and program instrumentation Discussed techniques and tools remain relevant for real-world security audits Anecdotal evidence shows that over 90% of C/C++ bugs found using a white-box fuzzer Recent data on bugs missed by fuzzing tells us that there is room for improvement 20 / 21

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend