“buffer overflow” What does this mean? Coercing a program to write outside the bounds of an allocated object “The write overflows” etc Actually some nuance here
to characterize “easy” vs. “hard” bugs Consider: Bugs you care about will exist in reaction to input you provide Read a program carefully, at each step ask yourself what decision it is making, and if it is because of your input The further into a program you get from where your data is used, the harder the bug
is input into the program read/recv/recvfrom Trace the use of that data Build a model for the data the program receives Start playing “what-if” games What if this was <0 or >MAX_SIGNED
you only have a binary, run it! Your debugger can help you answer some questions potentially faster than IDA “Where does the program input data?” Breakpoint on recv “Where is the buffer that is read first used?” Break-on-access on buffer passed to recv
else’s code is almost identical to looking for bugs in code that you wrote “Yeah but I wrote the code, so I know what it’s doing” How’s that working out for you? What tools do you use when you debug your own programs? Try and achieve understanding of what your target program is doing
these are logical errors which lead to memory errors void foo(int handle) { int count,i; struct entry *entry_array; read(handle, &count, 4); entry_array = malloc(count*sizeof(struct entry)); for(i = 0; i < count; i++) { entry_array[i].bar = … count comes from outside This multiplication could overflow and wrap around Then, entry_array is much smaller than we think and this will walk into other memory
Find locations where input-controlled (or input- influenced) variable ‘x’ is used to dereference into memory Search for example where some value of ‘x’ results in an out of bounds read or write Then you have found a vulnerability
using a pointer value returned by malloc() after passing it to the free() function is very bad Exactly why will come later “use-after-free” is a pattern that could be re-stated as “use of object after lifetime expires” As a rule I think we can agree this is pretty gauche
of the program to find them You’re not just looking for states, but, conditions and paths In the WebKit example did you see a free()? Look at the program and try and conceive of possible paths through a program where a value would be used after deletion
programmers Sometimes we try and bolt garbage collection into C One tactic is reference counting, attach an atomic integer to every object and increment it when some piece of code takes ownership of the object Frequently a source of bugs when someone forgets to increment a reference counter when they should Frequently a source of impossible-to-find memory leaks when someone forgets to decrement BORING
the fun of finding UAFs or heap corruption but with events happening at nondeterministic orderings Track events that happen in different threads, consider all possible orderings of those events Use a debugger
“convince” it that some security invariant has been met when it has not No general class, pattern, or scheme It’s not always about memory corruption or shell games If you can send the right sequence to a remote system that sends you a flag, that’s all that matters
finding all of these bugs automatically, in the real world” Some of our best technologies are dynamic This is a way of saying “it sucks” Static systems have a lot of limitations For further reading, check out Regehr’s integer overflow checker, MS Research SLAM, Static Driver Verifier
think Hopper might be okay but I’m too committed to IDA to back out now You want help visualizing control flow You want to get the “shape” of a program into your head IDA is interactive Rename things Create comments
Programs Reverse engineering Program understanding Bugs Exploits Shells Retire to crime island Game day top tip: delegate stages of this pipeline to key teammates
frequently identify how to change the code so the vulnerability is no longer there Can you apply these changes to the original program image? Depends but almost always this answer is ‘yes’ Binary patching – add extra invariants, conditionals
refers to addresses that would be nudged by insert Inserting the code patch would destroy relative addresses used after the location where the patch was made Another solution is needed… Program address space
The software piracy world has been modifying executable file formats since there were executable file formats Tools exist for adding code sections or expanding the sizes of existing sections Straightforward algorithm then emerges Detour old code to new section Have new logic Jump back to end of old code that you removed
about real programs Some person wrote these programs to have specific bugs They (usually) try and scope it so that it is tractable for a weekends work It is a “game”