Wednesday, November 25, 2009

Finding Potential Buffer Overflows









































Prev don't be afraid of buying books Next






























Finding Potential Buffer
Overflows



One naive approach for finding buffer overflows
is simply to supply long arguments to a program and see what
happens. Some of the "application security" tools use this
simplistic approach. You too can do this by typing in long requests
to a Web server or an FTP server, or crafting weird e-mail headers and submitting them to a sendmail
process. This kind of black box testing can be effective at times,
but it is very time-consuming.



A much better way to test for buffer overflows
is to find API calls that are vulnerable by using static analysis
techniques. Using either source code or disassembled binary, this
scanning can be performed in an automated fashion. Once you find
some potential vulnerabilities with static analysis, you can use
black box testing to attempt to exercise them.





Exception Handling Hides Errors



One thing you should be aware of when
dynamically testing for possible overflows is that exception
handlers may be in use. Exception handlers will intercept some
violations, and thus it may not be apparent even if you do cause an
interesting overflow. If the program appears to recover from a
possible attempt to cause an overflow, and there is no external
indication of the event, then determining whether your probing is
having any effect is difficult.



Exception handlers are special blocks of code
that are called when an error occurs during processing (which is
precisely what happens when a buffer overflow occurs). On the x86
processor, exception handlers are stored in a linked list and they
are called in order. The top of the exception handler list is
stored at an address pointed to by FS:[0]. That is, the FS
register points to a special structure called the thread
information block, and the first element of the structure
(FS:[0]) is the exception handler.



You can determine whether an exception handler
is being set up by using the following instructions (the order of
these instructions may vary depending on the phase of the moon, so
your mileage will vary with this trick):







mov eax, fs:[0]
push SOME_ADDRESS_TO_AN_EXCEPTION_HANDLER
push eax
mov dword ptr fs:[0], esp






If you believe that an exception handler might
be masking an error you have caused, you can always attach to the
process with a debugger and set a break point on the exception
handler address.





Using a Disassembler



A superior approach to probing around in the
dark with dynamic testing methods is to use static analysis
techniques to find overflow targets. One excellent place to start is with a
disassembly of the binary. A quick look for static strings that
contain formatting characters such as %s with a
cross-reference back to where they are consumed provides plenty of
attack fodder.



If you approach things this way, you will
usually see static strings referenced as an offset:







push offset SOME_LOCATION






If you see this kind of code before a string
operation, check to determine whether the address points to a
format string of some kind (indicated by %s). If the
offset turns out to be a format string, next check the source
string to determine whether it happens to be a user-controlled
string. You can use boron tagging to help find these
things out (see Chapter 6). If the offset is
used as the source of the string operation (and there is no
user-supplied input), this location is most likely not vulnerable
because the user cannot directly control the data.



If the target of the string operation is on the
stack, you might see it referenced as an offset from EBP. For
example:







push [ebp-10h]






This kind of structure indicates use of stack
buffers. If the target of the operation is on the stack, then an
overflow will be relatively easy to exploit. If there is a call to
strncpy() or something similar that specifies the size of
the destination buffer, you might want to check that the size is at
least one less than the actual buffer length. We will explain this
further later, but the basic idea is that you might ferret out an
off-by-one error where you can exploit the stack. Lastly, for any
calculations made with reference to a length value, check for
signed/unsigned conversion errors (which we will also explain
further later).















































Amazon






No comments: