mirror of https://github.com/fdiskyou/Zines.git
876 lines
48 KiB
Plaintext
876 lines
48 KiB
Plaintext
Improving Software Security Analysis using Exploitation Properties
|
|
12/2007
|
|
skape
|
|
mmiller@hick.org
|
|
|
|
Abstract
|
|
|
|
Reliable exploitation of software vulnerabilities has continued to become more
|
|
difficult as formidable mitigations have been established and are now included
|
|
by default with most modern operating systems. Future exploitation of
|
|
software vulnerabilities will rely on either discovering ways to circumvent
|
|
these mitigations or uncovering flaws that are not adequately protected.
|
|
Since the majority of the mitigations that exist today lack universal bypass
|
|
techniques, it has become more fruitful to take the latter approach. It is in
|
|
this vein that this paper introduces the concept of exploitation properties
|
|
and describes how they can be used to better understand the exploitability of
|
|
a system irrespective of a particular vulnerability. Perceived exploitability
|
|
is of utmost importance to both an attacker and to a defender given the
|
|
presence of modern mitigations. The ANI vulnerability (MS07-017) is used to
|
|
help illustrate these points by acting as a simple example of a vulnerability
|
|
that may have been more easily identified as code that should have received
|
|
additional scrutiny by taking exploitation properties into consideration.
|
|
|
|
1) Introduction
|
|
|
|
Modern exploit mitigations have become formidable opponents with respect to
|
|
the effect they have on reliable exploitation. Some of the more substantial
|
|
modern mitigations include GuardStack (GS), SafeSEH, DEP (NX), ASLR, pointer
|
|
encoding, and various heap improvements[8, 9, 10, 15, 24, 3, 4]. The fact
|
|
that there have been very few public exploits that have been able to
|
|
universally bypass all of these mitigations at once is a testament to the
|
|
resilience of these techniques working in concert with one another. It is
|
|
obvious that the absence of a given mitigation directly contributes to the
|
|
exploitability of the associated code. Likewise, it is also well known that
|
|
most mitigations have situations in which they will offer little to no
|
|
protection[5, 16, 18, 20, 2, 4]. For instance, in certain cases, it may be
|
|
possible to perform a partial overwrite on Windows Vista to defeat ASLR due to
|
|
the fact that only 15 bits of most 32-bit addresses may be affected by
|
|
randomization[2, 17]. Other mitigations also have situations where they may
|
|
not provide adequate coverage.
|
|
|
|
Given the fact that the majority of mitigations have known limitations, it
|
|
makes sense to consider where this information might be useful. In the field
|
|
of program analysis, whether it be manual, static, or dynamic, the question of
|
|
scoping is often pertinent. This question typically revolves around figuring
|
|
out what areas of code should be reviewed and what precedence, if any, should
|
|
be assigned to different regions. Typical approaches taken to accomplish this
|
|
often involve identifying code that straddles a trust boundary or performs
|
|
complex operations reachable from a trust boundary. However, depending on
|
|
one's perspective, this type of approach is insufficient in the face of modern
|
|
mitigations because it may result in areas of code being reviewed that are
|
|
adequately protected by all mitigations.
|
|
|
|
To help address this perceived deficiency, this paper introduces the concept
|
|
of exploitation properties and describes how they can be used to provide a
|
|
better understanding of exploitability of a system if a vulnerability is found
|
|
to be present. Regions of code that are found to have a number of distinct
|
|
exploitation properties may be more interesting from an exploitation
|
|
standpoint and therefore may warrant additional scrutiny from a program
|
|
analysis perspective. The use of exploitation properties may benefit both an
|
|
attacker and a defender. For example, companies may wish to perform targeted
|
|
reviews on areas of code that may be more trivially exploited in an effort to
|
|
prevent reliable exploits from being released in the future. Likewise, an
|
|
attacker searching for a vulnerability may wish to avoid auditing regions of
|
|
code that are likely to be more difficult to exploit.
|
|
|
|
Exploitation properties represent additional criteria that can be used when
|
|
attempting to better understand the security aspects of a program. Annotating
|
|
regions of code with exploitation properties makes it possible to use set
|
|
unions and intersections to identify the subset of interesting regions of code
|
|
for a particular analysis problem. For example, an attacker may wish to
|
|
determine the regions of code that may permit the use of traditional
|
|
stack-based buffer overflow techniques as well as permitting a partial
|
|
overwrite of a return address in order to defeat ASLR. Using these two
|
|
exploitation properties as criteria, a narrowed subset can be produced
|
|
which contains only those regions which meet both criteria by intersecting
|
|
those regions that have both exploitation properties. For the purpose of
|
|
this paper, the term narrowing is not used in the strict mathematical
|
|
sense; rather, this paper uses narrowing to describe the process of
|
|
constraining the scope of analysis through the use of specific criteria.
|
|
|
|
The concept of using automated analysis as a precursor to more strenuous
|
|
program analysis is certainly not new. There have been many tools ranging
|
|
from the simple detection of calls to strcpy to much more sophisticated forms
|
|
of static analysis. Still, the use of exploitation properties can be seen as
|
|
an additional set of data points which may be useful in the context of program
|
|
analysis given the hypothesis that most reliably exploitable security
|
|
vulnerabilities are being pushed into areas of code that are less affected by
|
|
mitigations.
|
|
|
|
The concept of exploitation properties is presented as follows. Section 2
|
|
categorizes and defines a limited number of concrete exploitation properties.
|
|
Section 3 provides a concrete example of using exploitation properties to help
|
|
identify the function that contained the ANI vulnerability. Section 4
|
|
describes some potential ways in which exploitation properties can be applied.
|
|
Section 5 gives a brief description of future work involving exploitation
|
|
properties.
|
|
|
|
2) Exploitation Properties
|
|
|
|
Exploitation properties describe the ease with which an arbitrary
|
|
vulnerability might be exploited. An understanding of a system's perceived
|
|
exploitability can provide useful insights when attempting to establish the
|
|
risk factors associated with it. An example of this can be seen in threat
|
|
modeling where the DREAD model of classifying risk includes a high-level
|
|
evaluation of exploitability as one of the risk factors[14]. It is important
|
|
to note that exploitation properties do not provide any indication that a
|
|
vulnerability exists; instead, they are only meant to convey information about
|
|
how easily a vulnerability could be exploited. The concept of an exploitation
|
|
property can be broken into different categories which are tied to the
|
|
configuration or context that the property is associated with. Examples of
|
|
these categories include platforms, processes, binary modules, functions, and
|
|
so on.
|
|
|
|
The following subsections provide concrete examples to better illustrate the
|
|
concept of an exploitation property. These examples are given by showing what
|
|
implications a property has with respect to exploitation as well as how a
|
|
property might be derived. It should be noted that the examples given in this
|
|
paper do not represent a complete, exhaustive set of exploitation properties.
|
|
|
|
2.1) Platform Properties
|
|
|
|
Exploitation properties associated with a platform are meant to illustrate how
|
|
easily a vulnerability may be exploited when a given platform configuration,
|
|
such as the operating system or architecture, is used. For example, Windows
|
|
2000 does not include support for enforcing non-executable pages. This
|
|
implies that any vulnerability found within an application that runs in the
|
|
context of the Windows 2000 platform may be exploited more easily. An
|
|
understanding of exploitation properties that are associated with a platform
|
|
may be useful when attempting to assess the risk of applications that might
|
|
run on multiple platforms. There are many other examples of exploitation
|
|
properties that are tied to platforms. In order to limit the scope of this
|
|
document, platform exploitation properties are not discussed at length.
|
|
|
|
2.2) Process Properties
|
|
|
|
Process exploitation properties carry some information about how easily
|
|
vulnerabilities found within the context of a running process may be
|
|
exploited. For example, Internet Explorer running on 32-bit versions of
|
|
Windows Vista do not make use of hardware-enforced DEP (NX) by default. This
|
|
means that any vulnerabilities found within code that runs in the context of
|
|
Internet Explorer will not be protected by non-executable regions. An
|
|
understanding of exploitation properties that are associated with a process
|
|
context can help to provide a better understanding of the risks associated
|
|
with code that may run in the context of a given process. In order to limit
|
|
the scope of this document, process exploitation properties are not discussed
|
|
at length.
|
|
|
|
2.3) Module Properties
|
|
|
|
Module exploitation properties are used to illustrate the effect that a
|
|
particular binary module has on ease of exploitation. This category of
|
|
properties is useful when attempting to identify binaries that may be more
|
|
easily exploited if a vulnerability is found within them or in code that
|
|
depends on them. This subsection describes two examples of module
|
|
exploitation properties.
|
|
|
|
2.3.1) No Support for ASLR
|
|
|
|
Windows Vista was the first major release of Windows to include a built-in
|
|
implementation of Address Space Layout Randomization (ASLR)[15,24]. In order
|
|
to head off potential application compatibility issues, Microsoft chose to
|
|
make ASLR an opt-in feature by requiring binaries to be compiled with a new
|
|
compiler switch (/dynamicbase)[21]. This compiler switch is responsible for
|
|
setting a bit (0x40) in the DllCharacteristics that are defined within a
|
|
binary. If this bit is set, the Windows kernel will attempt to randomize the
|
|
base address of the binary when it is mapped into memory the first time. If
|
|
the bit is not set, the binary will not have its base address randomized,
|
|
although it could be relocated in memory if the binary's preferred region is
|
|
already occupied by another allocation. As such, any binary that does not
|
|
support ASLR may be mapped at a predictable location within a process address
|
|
space at execution time. This can allow an attacker to make assumptions about
|
|
the address space which may make exploitation easier if a vulnerability is
|
|
found within any code that is mapped into the same address space as the module
|
|
of interest.
|
|
|
|
2.3.2) No Support for SafeSEH
|
|
|
|
With Visual Studio 2003, Microsoft introduced a compile-time change known as
|
|
SafeSEH which attempts to act as a mitigation for the SEH overwrite attack
|
|
vector[5,9]. SafeSEH works by adding a static list of known good exception
|
|
handlers that are considered valid as metadata within a given binary.
|
|
Binaries that support SafeSEH allow the exception dispatcher to perform
|
|
additional checks when dispatching exceptions. The most important check
|
|
involves determining if an exception handler that is found to exist within the
|
|
mapped region of a given binary is actually considered to be one of the safe
|
|
exception handlers. If the exception handler is not a safe exception handler,
|
|
the exception dispatcher can take steps to prevent it from being called. This
|
|
behavior works to mitigate the potential exploitation vector.
|
|
|
|
In order to communicate this information to the exception dispatcher, modern
|
|
PE files include fields in the load config data directory which hold the
|
|
offset of the safe exception handler table and the number of elements found
|
|
within the table. The load config data directory contains meta data that is
|
|
useful to the dynamic loader such as information about safe exception
|
|
handlers, the module's global security cookie address, and so on[13]. The
|
|
following output from dumpbin.exe illustrates what this might look like:
|
|
|
|
310751E0 Safe Exception Handler Table
|
|
1 Safe Exception Handler Count
|
|
|
|
Safe Exception Handler Table
|
|
|
|
Address
|
|
--------
|
|
310357D1 __except_handler4
|
|
|
|
Unfortunately, as with ASLR, the benefits offered by SafeSEH are not complete
|
|
unless every binary that is loaded into an address space has been compiled to
|
|
make use of SafeSEH. If a binary has not been compiled to make use of
|
|
SafeSEH, an attacker may be able to use any address found within the binary's
|
|
memory mapping as an exception handler in conjunction with an SEH overwrite.
|
|
|
|
2.4) Function Properties
|
|
|
|
Function exploitation properties convey information about how a function
|
|
contributes to the exploitability of an application. For example, a function
|
|
might make it possible to use certain exploitation techniques that might
|
|
otherwise be prevented if mitigations were present. Alternatively, a function
|
|
might simply assist in the exploitation process. Function exploitation
|
|
properties are especially useful because they provide more detailed
|
|
information than exploitation properties that are derived from the platform,
|
|
process, or module context.
|
|
|
|
2.4.1) Absence of GuardStack
|
|
|
|
The GuardStack (GS) support included with versions of the Microsoft Visual
|
|
Studio compiler since 2002 offers a compile-time mitigation to traditional
|
|
stack-based buffer overflows[23]. It supports this through a combination of a
|
|
random canary inserted into a stack frame at runtime and an intelligent stack
|
|
frame layout algorithm. The random canary is pushed onto the stack when a
|
|
function is called and then popped off the stack and validated prior to
|
|
function return. If the canary does not match the expected value, it is
|
|
assumed that a stack-based buffer overflow occurred and that the process
|
|
should be terminated.
|
|
|
|
Since the initial release of GS support a number of techniques have been
|
|
described that could be used to bypass or weaken it[5, 16, 20]. While these
|
|
techniques were at one time useful or have not yet been fully realized, the
|
|
author assumes that most would agree that the GS implementation provided by
|
|
the most recent compiler is robust (with the exception of SEH). There is
|
|
currently no publicly known universal bypass technique for GS that the author
|
|
is aware of. Given this assumption, functions that are protected by GS become
|
|
less interesting from the standpoint of identifying stack-based buffer
|
|
overflows. On the other hand, functions that are not protected by GS can
|
|
instantly be qualified as interesting targets for review. This is especially
|
|
true with binaries that have been compiled with GS support but contain a
|
|
number of functions that the compiler has chosen not to compile with GS
|
|
protections. This choice is made by taking into account certain conditions such
|
|
as the presence or absence of local variables that are declared as fixed-size
|
|
arrays.
|
|
|
|
As previous research has illustrated[27], it is possible to identify functions
|
|
that have not been compiled to use GS through the use of simple static
|
|
analysis tools. It is also possible to further refine the approaches
|
|
described in previous research if one has symbols and one assumes that the
|
|
most recent compiler was used. This can be accomplished by analyzing the call
|
|
graph of an executable and noting the set of functions that do not call
|
|
securitycheckcookie. Considered another way, the same set of functions can be
|
|
identified by taking the set of all functions contained within a binary less
|
|
the subset that call securitycheckcookie. The set of functions that is
|
|
identified by either approach can be annotated with an exploitation property
|
|
that indicates that they may contain stack-based buffer overflows that would
|
|
not be hindered by GS.
|
|
|
|
It may also be prudent to take the compiler version that was used into
|
|
consideration when analyzing binaries. This is important due to the fact that
|
|
older versions of the compiler used a GS implementation that could be
|
|
trivially defeated in certain circumstances[16]. For example, previous versions
|
|
of GS did not layout the stack frame in a manner that would prevent an
|
|
attacker from overwriting other local variables and function arguments. In
|
|
scenarios where this occurred and an overwritten local variable or parameter
|
|
was dereferenced (such as by invoking a function pointer), the mitigation
|
|
offered by GS would be meaningless. Thus, a secondary exploitation property
|
|
could involve identifying functions where attacks such as the one described
|
|
above could be possible.
|
|
|
|
2.4.2) Partial Overwrite Feasibility
|
|
|
|
One of the unique consequences of implementing Address Space Layout
|
|
Randomization (ASLR) on Windows is the limitation that the system allocation
|
|
granularity imposes on the number of bits that can be randomized within most
|
|
memory allocations. In particular, the allocation granularity used by Windows
|
|
enforces strict 16-page alignment for the base addresses of most memory
|
|
mappings in user-mode. This restriction means that it is only possible to
|
|
introduce entropy into the low 15 bits of the high-order 16 bits of a 32-bit
|
|
memory mapping[17]. While this may sound odd at first glance, the high-order two
|
|
bits are not randomized due to the divide between kernel and user-mode. This
|
|
assumes that a machine is booted without /3GB. The low-order 16 bits remain
|
|
unchanged relative to the high-order bits. This caveat means that it may be
|
|
possible to perform a partial overwrite of an address and thus bypass the
|
|
security features offered by ASLR[2]. However, the ability to perform a partial
|
|
overwrite also relies on the presence of useful code or data within a region
|
|
that is relative to the address that is being overwritten.
|
|
|
|
To visualize how this type of information might be useful, consider a scenario
|
|
where an attacker is performing a partial overwrite of a return address on the
|
|
stack. In this situation, it is often necessary for one or more useful
|
|
opcodes to be present at an address that is 16-page relative to the return
|
|
address. For example, consider a scenario where the function may have a
|
|
vulnerability that would permit a partial overwrite. In this example, is
|
|
called by and . In order to permit the use of a partial overwrite, a useful
|
|
opcode must be found within the same 16-page aligned region that either or
|
|
reside on. If a useful opcode is present, an exploitation property can be
|
|
attached to in order to indicate that a partial overwrite may be feasible due
|
|
to the presence of a useful opcode within the same 16-page aligned region as
|
|
either or . For example, consider the following pseudo-disassembly
|
|
illustrating a case where the call f instruction in is on the same 16-page
|
|
region as a useful opcode:
|
|
|
|
... useful jmp on same 16-page region 0x14c1XXXX
|
|
0x14c1fc04 jmp esp
|
|
... entry point to h()
|
|
0x14c1a910 push ebp
|
|
0x14c1a911 mov ebp, esp
|
|
0x14c1a914 call f
|
|
... entry point to y(), not on same 16-page region
|
|
0x137f44c8 push ebp
|
|
|
|
While this captures the basic concept, a better approach might be to view a
|
|
binary in a different way. For example, consider the following approach to
|
|
drawing the same conclusion: for each code region that contains a useful
|
|
opcode, identify the subset of functions that are called from call sites
|
|
within the same 16-page aligned region as the useful opcode. This has the
|
|
effect of annotating all of the child functions that could potentially
|
|
leverage a partial overwrite of the return address with respect to a
|
|
particular collection of opcodes.
|
|
|
|
One important point that must be made about this exploitation property is that
|
|
is entirely dependent upon the definition of "useful code or data".
|
|
Exploitation is very much an art and it goes without saying that attempting to
|
|
constrain the approaches that an attacker might make use of is likely to be
|
|
folly. However, defining a known-set of useful opcodes and using that set as
|
|
a base with which to draw the above conclusion can be said to be better than
|
|
not doing so at all.
|
|
|
|
2.4.3) Function or Parent Registers an Exception Handler
|
|
|
|
One of the unique exploitation vectors that exists in 32-bit programs that run
|
|
on Windows is known as an SEH overwrite[5]. An SEH overwrite makes it possible
|
|
to gain control of execution flow by overwriting an exception registration
|
|
record on the stack. From an exploitation perspective, the act of registering
|
|
an exception handler within a function opens up the possibility of making use
|
|
of an SEH overwrite. Since exception handlers are chained, the act of
|
|
registering an exception handler also implicates any functions that are
|
|
children of a function that registers the exception handler. This makes it
|
|
possible to define an exploitation property that illustrates the possibility
|
|
of an SEH overwrite being abused within the scope of a specific set of
|
|
functions. Detecting this property can be as simple as signaturing the
|
|
compiler generated code that is used to generate and register an exception
|
|
handler within a function. An example of two functions, and , that would
|
|
meet this criteria can be seen below:
|
|
|
|
void f() {
|
|
__try {
|
|
g();
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
}
|
|
|
|
void g() {
|
|
...
|
|
}
|
|
|
|
In addition to this information being useful from an SEH overwrite
|
|
perspective, it may also benefit an attacker in situations where an exception
|
|
handler simply swallows any exceptions that are dispatched without crashing
|
|
the process[1]. In the example given above, any exception that occurs in the
|
|
context of will be swallowed by without necessarily crashing the process.
|
|
This behavior may allow an attacker to retry their exploitation attempt
|
|
multiple times, thus enabling a bruteforce attack that would otherwise not be
|
|
feasible. This can make defeating ASLR more feasible.
|
|
|
|
2.4.4) Function is an Exception Handler
|
|
|
|
The introduction of SafeSEH as a modern compile-time mitigation has caused the
|
|
particulars of how exception handlers are implemented to become more
|
|
interesting. This has to do with the fact that SafeSEH restricts the set of
|
|
exception handlers that may be called by the exception dispatcher to those
|
|
that are specified as being valid within the scope of a given binary. As
|
|
discussed previously in this paper, SafeSEH prevents traditional SEH
|
|
overwrites from being able to use any address as the overwritten exception
|
|
handler. While this is effective in its primary intent, there is still the
|
|
possibility that a valid exception handler can be abused to make exploitation
|
|
more feasible[1]. This scenario is restricted to EH3 and prior exception
|
|
handlers as EH4 includes a check of a cookie before dispatching exceptions.
|
|
As such, it may be useful to flag the regions of code that are associated with
|
|
EH3 and prior exception handlers, including language-specific exception
|
|
handlers, as being potentially interesting from an exploitation perspective.
|
|
|
|
Unfortunately, as with ASLR, the benefits offered by SafeSEH are not complete
|
|
unless every binary that is loaded into a process address space has been
|
|
compiled to make use of SafeSEH. If a binary has not been compiled to make
|
|
use of SafeSEH, an attacker may be able to use any address found within the
|
|
binary's memory mapping as an exception handler in the context of an SEH
|
|
overwrite. This may make exploitation more feasible.
|
|
|
|
3) Case Study: MS07-017
|
|
|
|
The animated cursor (ANI) vulnerability was discovered by Alexander Sotirov in
|
|
late 2006 and patched by Microsoft with the MS07-017 critical update in April,
|
|
2007 . Apart from being a client-side vulnerability that was exposed through
|
|
web-browsers and other mediums, the ANI vulnerability was one of the first
|
|
notable security issues that affected Windows Vista. It was notable due to
|
|
the simple fact that even though Microsoft had touted Windows Vista as being
|
|
the most secure operating system to date, the exploits that were released for
|
|
the ANI vulnerability were very reliable. These exploits were able to ignore
|
|
or defeat the protections offered by mitigations such as GS, DEP, and even
|
|
Vista's newest mitigation: ASLR.
|
|
|
|
To better understand how this was possible it is important to dive deeper into
|
|
the details of the vulnerability itself. gives a brief description of the
|
|
ANI vulnerability and some of the techniques that were used to successfully
|
|
exploit it. Following this description, illustrates how exploitation
|
|
properties, in combination with another class of properties, can be used to
|
|
detect functions that may contain vulnerabilities similar to the ANI
|
|
vulnerability. This is meant to help illustrate the perceived benefits of
|
|
applying the concept of exploitation properties to aide in the process of
|
|
identifying regions of code that may deserve additional scrutiny based on
|
|
their perceived exploitability.
|
|
|
|
3.1) Background
|
|
|
|
While the ANI vulnerability was certainly unique, it was not the first time
|
|
the animated cursor code was found to have a security issue. Microsoft patched
|
|
an issue that was almost exactly the same as MS07-017 with MS05-002 roughly
|
|
two years prior. In both cases, the underlying security issue was related to
|
|
a failure to properly validate input that was derived from the contents of an
|
|
animated cursor file. Alexander Sotirov provided much of the initial research
|
|
on the ANI vulnerability and also gave an excellent write-up to its effect[22].
|
|
This paper will only attempt to highlight the flaw.
|
|
|
|
The vulnerability itself was found in user32!LoadAniIcon which is responsible
|
|
for processing a number of different chunks that may be contained within an
|
|
animated cursor file. Each chunk is a TLV (Type-Length-Value) as described
|
|
by the following structure:
|
|
|
|
struct ANIChunk
|
|
{
|
|
char tag[4]; // ASCII tag
|
|
DWORD size; // length of data in bytes
|
|
char data[size]; // variable sized data
|
|
}
|
|
|
|
Keeping this structure in mind, the flaw itself can be seen in the abbreviated
|
|
pseudo-code below as modified slightly from Sotirov's original write-up:
|
|
|
|
01: int LoadAniIcon(struct MappedFile* file, ...) {
|
|
02: struct ANIChunk chunk;
|
|
03: struct ANIHeader header; // 36 byte structure
|
|
04: while (1) {
|
|
05: // read the first 8 bytes of the chunk
|
|
06: ReadTag(file, &chunk);
|
|
07: switch (chunk.tag) {
|
|
08: case 'anih':
|
|
09: // read chunk.size bytes into header
|
|
10: ReadChunk(file, &chunk, &header);
|
|
|
|
On line 6, the chunk header is read into the local variable chunk using
|
|
ReadTag which populates the chunk's tag and size fields. If the chunk's tag
|
|
is equal to 'anih', the data associated with the chunk is read into the header
|
|
local variable using ReadChunk on line 10. The problem is that ReadChunk uses
|
|
the size field of the chunk as the amount of data to read from the file.
|
|
Since header is a fixed-size (36 byte) data structure and the chunk's size can
|
|
be variable, a trivial stack-based buffer overflow may occur if more than 36
|
|
bytes are specified as the chunk size. In terms of the vulnerability, that's
|
|
all there is to it, but the implications from an exploitation perspective are
|
|
where things start to get interesting.
|
|
|
|
When attempting to exploit this vulnerability it may at first appear that all
|
|
attempts to do so would be futile. Given Vista's security push, an attacker
|
|
would be justified in thinking that surely the LoadAniIcon function is
|
|
protected by a GS cookie. This point is especially justified considering the
|
|
majority of all binaries shipped with Windows Vista have been compiled with GS
|
|
enabled[27]. However, there are indeed circumstances where the compiler will
|
|
choose to not enable GS for a specific function. As chance would have it, the
|
|
compiler chose not to enable GS for the LoadAniIcon function because of the
|
|
simple fact that it does not contain any characteristics that would suggest
|
|
that a stack-based buffer overflow might be possible (such as the use of
|
|
stack-allocated arrays). This means that an attacker is able to make use of
|
|
exploitation techniques that are associated with traditional stack-based
|
|
buffer overflows. While this drastically increases the chances of being able
|
|
to produce a reliable exploit, there are still other mitigations that are of
|
|
potential concern.
|
|
|
|
Another mitigation that might be concerning in most circumstances is
|
|
hardware-enforced DEP (NX). This would generally prevent an attacker from
|
|
being able to run arbitrary code within regions that are not marked as
|
|
executable (such as the stack and the heap). However, as fate would have it,
|
|
Internet Explorer is configured to not run with DEP enabled. This immediately
|
|
removes this concern from the equation for exploits that attempt to trigger
|
|
the ANI vulnerability through Internet Explorer. With DEP out of the picture,
|
|
ASLR becomes a weakened but still potentially significant hurdle.
|
|
|
|
While it may appear that ASLR would be challenging to defeat in most
|
|
circumstances, this particular vulnerability provides an example of two
|
|
different ways in which ASLR can be bypassed. The simplest approach, as taken
|
|
by Sotirov, involves making use of the fact that Internet Explorer is not
|
|
compiled with support for ASLR and therefore can be found at a fixed address
|
|
within the address space. This allows an attacker to make use of opcodes
|
|
contained within iexplore.exe's memory mapping. A second approach, as taken
|
|
by the author, involves using a partial overwrite to ignore the effects of
|
|
ASLR completely. The details relating to how a partial overwrite works were
|
|
explained in 2.4.2. In either case, an attacker is able to reliably defeat Vista's
|
|
ASLR.
|
|
|
|
To compound the problem, the particulars of the context in which this
|
|
vulnerability occur make it easier to exploit even without the presence of
|
|
mitigations. This improved reliability comes from the fact that the
|
|
LoadAniIcon function is wrapped in an exception handling context that simply
|
|
swallows exceptions that are encountered. This makes it possible for an
|
|
exploit to fail without actually crashing the process, thus allowing the
|
|
attacker to try multiple times without having to worry about making a mistake
|
|
that crashes the process. When all is said and done, the simplicity of the
|
|
vulnerability and the ease with which mitigations could be bypassed are what
|
|
lead to the ANI vulnerability being quite unique. Given the fact that this
|
|
vulnerability can be so easily exploited, it is prudent to describe how it
|
|
could have been detected as being a high risk function.
|
|
|
|
3.2) Detection
|
|
|
|
The ease of exploitability associated with the ANI vulnerability makes it an
|
|
obvious candidate for study with respect to the exploitation properties that
|
|
have been described in this paper. It should be possible to use extremely
|
|
simple criteria to accomplish two things. First, the criteria must identify
|
|
the LoadAniIcon function. Second, the criteria should be unique enough to
|
|
limit the size of the narrowed subset. Reducing the subset size is beneficial
|
|
as it may permit the use of more complex program analysis tools which can
|
|
further constrain or explicitly identify instances of vulnerabilities.
|
|
Determining the specific criteria that is needed to identify the LoadAniIcon
|
|
function can help illustrate how one can make use of exploitation properties.
|
|
Given the description of the ANI vulnerability, one can easily deduce some of
|
|
the more interesting properties that it has.
|
|
|
|
An exploitation property that one might immediately observe is that the
|
|
LoadAniIcon function does not make use of GS (2.4.1). This makes it possible to
|
|
define criteria which states that only functions that have not been compiled
|
|
with GS should be considered. Functions that have been compiled with GS are
|
|
inherently less interesting for the purpose of this exercise due to the fact
|
|
that they are less likely to contain exploitable vulnerabilities.
|
|
|
|
A second property that the ANI vulnerability had with regard to exploitation
|
|
was that it was possible for an attacker to make use of a partial overwrite to
|
|
defeat ASLR. The exploitation property described in 2.4.2 illustrates how one can
|
|
make this determination statically. In the case of the ANI vulnerability, a
|
|
partial overwrite can be performed by making use of a jmp [ebx] that is
|
|
located within the same 16-page aligned region as the caller of LoadAniIcon.
|
|
Thus, any functions that could potentially make use of a partial overwrite can
|
|
be used as additional criteria.
|
|
|
|
At this point, a subset can be produced that is constrained to the regions of
|
|
code that are annotated with the GS and partial overwrite exploitation
|
|
properties. It is possible to further refine the set of functions that should
|
|
ultimately be considered by studying the form that the ANI vulnerability took.
|
|
The first point to note is that the stack-based buffer overflow occurred when
|
|
writing beyond the bounds of a struct that was allocated on the stack.
|
|
Furthermore, the overflow did not actually occur in the immediate context of
|
|
the LoadAniIcon itself. Instead, the overflow was triggered by passing a
|
|
pointer to the stack-allocated struct as a parameter when calling the function
|
|
ReadChunk.
|
|
|
|
Based on these data points it is possible to define a third criteria. In this
|
|
case, the third criteria is not an exploitation property but is instead an
|
|
example of a vulnerability property. While not discussed in detail in this
|
|
paper, many examples of vulnerability properties exist, though perhaps not
|
|
categorized as such. A vulnerability property can be thought of as an
|
|
annotation that illustrates whether or not a region of code has a form that is
|
|
similar to that seen in vulnerabilities or has the potential of being a
|
|
vulnerability. The complexity of a vulnerability property, as with the
|
|
complexity of an exploitation property, can range from highly sophisticated to
|
|
very simplistic.
|
|
|
|
For the purpose of this paper, a vulnerability property can be used that is
|
|
very simple and imprecise but nevertheless effective at further narrowing the
|
|
set of functions that should be reviewed. This property is based on whether
|
|
or not a function passes a pointer to a stack-allocated variable as a
|
|
parameter to a child function. This property is directly derived from the
|
|
general form that the ANI vulnerability takes. At a minimum, a region of code
|
|
that matches this form suggests that a vulnerability could be present.
|
|
|
|
Using these three properties, it should be possible to easily identify both
|
|
the function that contains the ANI vulnerability as well as other functions
|
|
that could contain similar vulnerabilities. However, it is important to note
|
|
that this process does not produce functions that definitely have
|
|
vulnerabilities. This can be plainly seen by the fact that both the
|
|
vulnerable and fixed versions of the LoadAniIcon should be detected by the
|
|
criteria described above. While this may seem to run counter to the purposes
|
|
of this paper, it is important for the reader to remember that the goal of
|
|
using these exploitation properties is not to identify specific instances of
|
|
vulnerabilities. Instead, the goal is to identify regions of code that might
|
|
warrant additional scrutiny due to the relative ease with which a
|
|
vulnerability could be exploited if one is found to be present.
|
|
|
|
3.3) Test Case
|
|
|
|
The author developed an analysis tool as an extension to Microsoft's Phoenix
|
|
framework in order to test the ideas described in this paper[12]. Unfortunately,
|
|
the current release (July 2007 SDK) of Phoenix requires private symbol
|
|
information for native binaries. This limitation prevented the author from
|
|
being able to run the analysis tool across the vulnerable version of
|
|
user32.dll. In lieu of this ability, the author chose to generate a binary
|
|
containing test cases that closely mirror the form of the function containing
|
|
the ANI vulnerability.
|
|
|
|
Using these test cases, the author used the features provided by the analysis
|
|
tool to determine the exploitation and vulnerability properties described in
|
|
the previous section and to identify the resulting subset of functions meeting
|
|
all criteria. This was accomplished by first attempting to identify the
|
|
subset of functions that do not contain GS within the scope of the target
|
|
binary. After identifying the subset of functions without GS, a second subset
|
|
was taken which consists of the functions that pass a pointer to a
|
|
stack-allocated local variable as a parameter to a child routine. This was
|
|
accomplished by using Phoenix's static single assignment (SSA) and alias
|
|
implementations to collect the requisite data flow information[12,25]. Using this
|
|
data flow information, it is possible to perform backwards data flow analysis
|
|
to determine the potential storage location of the parameter being passed at
|
|
each point along a given data flow path starting from the operand associated
|
|
with a parameter at a call site. The analysis terminates either when a fixed
|
|
point is reached or when it is determined that a pointer to a stack-allocated
|
|
variable could be passed as the parameter.
|
|
|
|
While the previous section described the potential for using the partial
|
|
overwrite exploitation property to detect the function containing the ANI
|
|
vulnerability[6], it is not possible to create a meaningful parallel between the
|
|
test binary and that of the ANI vulnerability. This is due in part to the
|
|
fact that while it would certainly be possible to artificially place a useful
|
|
opcode at a specific location in the test binary, it would not add any value
|
|
beyond showing that it is possible to detect useful opcodes within the same
|
|
16-page aligned region as the caller of a given function. The author feels
|
|
that this point is somewhat moot given the fact that it has already been
|
|
proven that a partial overwrite can be used with the ANI vulnerability. The
|
|
only additional benefit that it could offer in this case would be to help
|
|
further constrain the resultant set size. However, without being able to run
|
|
this analysis against the vulnerable version of user32.dll, it is not possible
|
|
to draw meaningful conclusions at this point in time.
|
|
|
|
3.4) Results
|
|
|
|
The results of running the analysis tool against the test binary produced the
|
|
expected behavior. To illustrate this, it is helpful to consider a sampling
|
|
of the functions that were analyzed. The following functions have a form that
|
|
is similar to the ANI vulnerability. These functions also match the criteria
|
|
described in the previous subsection. Specifically, these functions do not
|
|
make use of GS and pass a pointer to a stack-allocated local variable (var) to
|
|
a child function:
|
|
|
|
int tc_df_pass_local_ptr_to_callee() {
|
|
int var;
|
|
tc_df_pass_local_ptr_to_callee_func(&var);
|
|
return 0;
|
|
}
|
|
int tc_df_pass_local_ptr_to_callee_alias() {
|
|
int var;
|
|
int *p = &var;
|
|
tc_df_pass_local_ptr_to_callee_func(p);
|
|
return 0;
|
|
}
|
|
int tc_df_pass_local_ptr_to_callee_alias_struct(
|
|
struct _foo *foo) {
|
|
int var;
|
|
foo->ptr = &var;
|
|
return tc_df_pass_local_ptr_to_callee_func(
|
|
foo->ptr);
|
|
return 0;
|
|
}
|
|
|
|
Additionally, a handful of different test functions were also included in the
|
|
target binary in an effort to ensure that other scenarios were not improperly
|
|
detected as matching the criteria. Some examples of these functions include:
|
|
|
|
int tc_df_pass_local_to_callee_alias() {
|
|
int var = 2;
|
|
int p = var;
|
|
tc_df_pass_local_to_callee_func(p);
|
|
return 0;
|
|
}
|
|
int tc_df_pass_local_to_callee_deref() {
|
|
int var = 2;
|
|
int *p = &var;
|
|
tc_df_pass_local_to_callee_func(*p);
|
|
return 0;
|
|
}
|
|
int tc_df_pass_heap_ptr_to_callee(struct _foo *foo) {
|
|
tc_df_pass_local_ptr_to_callee_func(&foo->val);
|
|
return 0;
|
|
}
|
|
|
|
When running the analysis tool against the target binary, the following output
|
|
is shown:
|
|
|
|
>PhaseRunner.exe detectani.xml dfa.exe
|
|
Running phase: ANI Detection ... 1 target(s)
|
|
|
|
Displaying 3 normalizables at the
|
|
ProgramElement.Method granularity...
|
|
|
|
00001: dfa!tc_df_pass_local_ptr_to_callee_alias
|
|
00002: dfa!tc_df_pass_local_ptr_to_callee
|
|
00003: dfa!tc_df_pass_local_ptr_to_callee_alias_struct
|
|
|
|
While this unfortunately does not prove that these techniques could be used to
|
|
identify the function containing the ANI vulnerability, it does nevertheless
|
|
hint at the potential for detecting the function containing the ANI
|
|
vulnerability using its suggested exploitation and vulnerability properties.
|
|
As an side, another interesting way in which this type of detection can be
|
|
accomplished is through the use of Language Integrated Queries (LINQ) which
|
|
are now supported in Visual Studio 2008[11]. For instance, a simple LINQ
|
|
expression for the above narrowing operation can be expressed as:
|
|
|
|
var matches =
|
|
from
|
|
Method method in engine.GetScopeMethods()
|
|
where
|
|
!method.IsGuardStackEnabled() &&
|
|
method.IsPassingStackLocalPtrToChild()
|
|
select method;
|
|
|
|
foreach (var method in matches)
|
|
Console.WriteLine("{0} matches", method);
|
|
|
|
4) Potential Uses
|
|
|
|
Program analysis is one area that may benefit from the use of exploitation
|
|
properties. In particular, an auditor can make use of exploitation properties
|
|
to assist in the process of identifying regions of code that should be audited
|
|
more closely or with greater precedence. This determination can be made by
|
|
using exploitation properties to understand the ease of exploitation
|
|
associated with specific binaries or functions. By combining this information
|
|
with other data that is collected either manually or automatically, an auditor
|
|
can get a better understanding of the security aspects that are associated
|
|
with a system. This is beneficial both to an attacker and a defender. An
|
|
attacker can identify regions of code that would be easier to exploit and thus
|
|
devote more time to auditing those regions. Likewise, a defender can use this
|
|
information to the same extent but for different purposes. This type of
|
|
information is especially useful to a defender who needs to balance the cost
|
|
associated with performing security reviews because it should offer a better
|
|
understanding of what the business cost might be if a vulnerability is found
|
|
in a region of code. This cost can be derived from the negative publicity and
|
|
response effort needed to cope with a flaw that is found publicly in a region
|
|
of code that is widely exploited. For example, consider some of the Windows
|
|
flaws that have lead to wormable issues and the cost they have had relative to
|
|
other issues.
|
|
|
|
Exploitation properties may also benefit the security community by helping to
|
|
identify ways in which future mitigations can be applied. This would involve
|
|
analyzing regions of code that could be more easily exploited in an effort to
|
|
determine what other forms of mitigations could help to protect these regions,
|
|
if any. This information could be fed back to the compiler to make it
|
|
possible for mitigations to be enabled that might otherwise be disabled by
|
|
default. For example, a function that by default would not have GS but is
|
|
subsequently found to be highly exploitable may benefit from having the
|
|
compiler insert GS.
|
|
|
|
5) Future Work
|
|
|
|
While this paper has defined exploitation properties and described a handful
|
|
of concrete examples, it has not attempted to formally define the correlation
|
|
between exploitation properties and the exploitation techniques they are
|
|
associated with. Future research will attempt to concretely define this
|
|
relationship as it should lead to a better understanding of the variables that
|
|
permit the use of various exploitation techniques. Using more formal
|
|
definitions of exploitation properties, a larger scale case study can be
|
|
completed which collects data about the effect of using exploitation
|
|
properties to improve program understanding for a variety of purposes. The
|
|
author views exploitation properties as being one component in a larger model.
|
|
This larger model could be used to join major areas of study within computer
|
|
security including attack surface analysis, vulnerability analysis, and
|
|
exploitation analysis to form a more complete understanding of the true risks
|
|
associated with a system.
|
|
|
|
6) Conclusion
|
|
|
|
This paper has introduced the general concept of exploitation properties and
|
|
described how they can be used to better understand the exploitability of a
|
|
system. The purpose of an exploitation property is to help convey the ease
|
|
with which a vulnerability might be exploited if one is found to be present.
|
|
Exploitation properties can be broken down into different categories based on
|
|
the configuration or context that a given property is associated from. These
|
|
categories include operating platforms, running processes, binary modules, and
|
|
functions.
|
|
|
|
Exploitation properties can be used to provide an alternative understanding of
|
|
an application's attack surface from the perspective of which areas would be
|
|
most trivially exploited. This can allow an attacker to focus on finding
|
|
security issues in code that would be more easily exploited. Likewise, a
|
|
defender can draw the same conclusions and direct resources of their own at
|
|
reviewing the associated code. It may also be possible to use this
|
|
information to augment existing mitigations or to come up with new
|
|
mitigations. A contrived example based on the form of the ANI vulnerability
|
|
was used to illustrate an automated approach to extracting exploitation
|
|
properties and using them to help identify a constrained subset of regions of
|
|
code that meet a specific criteria. Future research will attempt to better
|
|
define the extent of exploitation properties and their uses.
|
|
|
|
[1] Dowd, M., Metha, N., McDonald, J. Breaking C++ Applications.
|
|
https://www.blackhat.com/presentations/bh-usa-07/Dowd_McDonald_and_Mehta/Whitepaper/bh-usa-07-dowd_mcdonald_and_mehta.pdf
|
|
|
|
[2] Durden, Tyler. Bypassing PaX ASLR Protection. July, 2002.
|
|
http://www.phrack.org/issues.html?issue=59&id=9
|
|
|
|
[3] Howard, Michael. Protecting against Pointer Subterfuge (Kinda!).
|
|
http://blogs.msdn.com/michael_howard/archive/2006/01/30/520200.aspx
|
|
|
|
[4] Johnson, Richard. Windows Vista: Exploitation Countermeasures.
|
|
http://rjohnson.uninformed.org/
|
|
|
|
[5] Litchfield, David. Defeating the Stack Based Buffer Overflow Prevention
|
|
Mechanism of Microsoft Windows 2003 Server.
|
|
http://www.nextgenss.com/papers/defeating-w2k3-stack-protection.pdf
|
|
|
|
[6] Metasploit. Exploiting the ANI vulnerability on Vista.
|
|
http://blog.metasploit.com/2007/04/exploiting-ani-vulnerability-on-vista.html
|
|
|
|
[7] Microsoft Corporation. Microsoft Security Bulletin MS05-002. Jan, 2005.
|
|
http://www.microsoft.com/technet/security/Bulletin/MS05-002.mspx
|
|
|
|
[8] Microsoft Corporation. /GS (Buffer Security Check).
|
|
http://msdn2.microsoft.com/en-us/library/8dbf701c(VS.80).aspx
|
|
|
|
[9] Microsoft Corporation. /SAFESEH (Image has Safe Exception Handlers).
|
|
http://msdn2.microsoft.com/en-us/library/9a89h429.aspx
|
|
|
|
[10] Microsoft Corporation. A detailed description of the Data Execution
|
|
Prevention (DEP) feature. http://support.microsoft.com/kb/875352
|
|
|
|
[11] Microsoft Corporation. The LINQ Project.
|
|
http://msdn2.microsoft.com/en-us/netframework/aa904594.aspx
|
|
|
|
[12] Microsoft Corporation. Phoenix. http://research.microsoft.com/phoenix/
|
|
|
|
[13] Microsoft Corporation. Microsoft Portable Executable and Object File
|
|
Format Specification.
|
|
http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.doc
|
|
|
|
[14] Microsoft Corporation. Threat Modeling. June, 2003.
|
|
http://msdn2.microsoft.com/en-us/library/aa302419.aspx
|
|
|
|
[15] PaX Team. ASLR. http://pax.grsecurity.net/docs/aslr.txt
|
|
|
|
[16] Ren, Chris et al. Microsoft Compiler Flaw Technical Note.
|
|
http://www.cigital.com/news/index.php?pg=art&artid=70
|
|
|
|
[17] Rahbar, Ali. An analysis of Microsoft Windows Vista's ASLR. Oct, 2006.
|
|
http://www.sysdream.com/articles/Analysis-of-Microsoft-Windows-Vista's-ASLR.pdf
|
|
|
|
[18] skape, Skywing. Bypassing Windows Hardware-enforced DEP.
|
|
http://www.uninformed.org/?v=2&a=4&t=sumry
|
|
|
|
[19] skape. Preventing the Exploitation of SEH Overwrites.
|
|
http://www.uninformed.org/?v=5&a=2&t=sumry
|
|
|
|
[20] skape. Reducing the Effective Entropy of GS Cookies.
|
|
http://www.uninformed.org/?v=7&a=2&t=sumry
|
|
|
|
[21] Skywing. Vista ASLR is not on by default for image base addresses.
|
|
http://www.nynaeve.net/?p=100
|
|
|
|
[22] Sotirov, Alexander. Windows Animated Cursor Stack Overflow
|
|
Vulnerability. March, 2007.
|
|
http://www.determina.com/security.research/vulnerabilities/ani-header.html
|
|
|
|
[23] Wikipedia. Stack-smashing protection.
|
|
http://en.wikipedia.org/wiki/Stack-smashing_protection
|
|
|
|
[24] Wikipedia. Address space layout randomization.
|
|
http://en.wikipedia.org/wiki/ASLR
|
|
|
|
[25] Wikipedia. Static single assignment form.
|
|
http://en.wikipedia.org/wiki/Static_single_assignment_form
|
|
|
|
[26] University of Wisconsin. Wisconsin Program-Slicing Project's Home Page.
|
|
http://www.cs.wisc.edu/wpis/html/
|
|
|
|
[27] Whitehouse, Ollie. Analysis of GS protections in Microsoft Windows
|
|
Vista. http://www.symantec.com/avcenter/reference/GS_Protections_in_Vista.pdf
|