It is impossible to completely prevent vulnerabilities from being introduced during the development of large-scale software projects. As long as human beings write software code, mistakes that lead to imperfections in software will be made – no software is perfect. Some imperfections simply prevent the software from functioning exactly as intended, but other bugs may present vulnerabilities.

Manual code reviews performed by developers and testers, in concert with automated tools such as fuzzers and static analysis tools, are very helpful techniques for identifying vulnerabilities in code. But these techniques cannot find every vulnerability in large scale software projects. As developers build more functionality into their software, their code becomes more and more complex. The challenge of finding vulnerabilities in very complex code is compounded by the fact that there are an infinite number of ways that developers can make coding errors that can create vulnerabilities, some of which are very, very subtle.

Have you ever wondered what a vulnerability looks like? To illustrate how subtle a security vulnerability can be, the following small code sample contains a vulnerability that is difficult to find using code reviews or tools or both.

Figure 1: An example of a software vulnerability

Can you spot the problem(s) in Figure 1? The developer who wrote this code intended to have the code check whether the user running the program should be denied access to the program or if they should be granted access. The problem in this code is that the function (AccessCheck()) that the developer is using to decide whether to grant access to the user, can fail for many reasons, many of which are not conditions related to denying access. For example, if the application runs out of memory for any reason during this operation, the function could return an “out of memory” error instead of the “access denied” error that the developer was expecting. Because the developer only checks for an “access denied” error, this code will grant access to the user if any error other than “access denied” error is returned. This is, therefore, a vulnerability that could potentially be exploited if an attacker could create the right conditions.

Trustworthy Computing’s Security Science team studied the root causes of the most severe vulnerabilities in Microsoft software, those that enable remote code execution (RCE), and were known to be exploited between 2006 and 2013. The root cause of a vulnerability plays a key role in defining the set of exploitation techniques that an attacker can use when developing an exploit. As a result, the level of difficulty in developing an exploit is heavily dependent on the type of vulnerability that is being exploited. In terms of risk management, the root cause of a vulnerability can be an important factor in influencing the likelihood that an exploit will be developed. As Figure 2 illustrates, there have been some noteworthy shifts in the classes of vulnerabilities that are known to have been exploited.

Figure 2: The root causes of exploited Microsoft remote code execution CVEs, by year of security bulletin, as published in the Microsoft Security Intelligence Report volume 16

A clear shift can be seen in the declining percentage of exploits for stack corruption vulnerabilities, such as stack-based buffer overflows, which accounted for 54.2 percent of known exploited Microsoft remote code execution CVEs in 2007 but accounted for just 5.0 percent in 2013. This decline isn’t accidental. In 2006 Microsoft deprecated a subset of the C runtime library to remove functions that were known to present security threats, with a focus on buffer overruns. At first this requirement was simply articulated in the form of a list of bad APIs, but it changed over time to become a header file (Banned.h) that could be used in conjunction with a compiler to help provide an automated method of sanitizing source code. This became a requirement in the Microsoft Security Development Lifecycle, which developers at Microsoft use to develop software.

This vulnerability class has historically been the most likely to be exploited, but has declined considerably since its 2007 peak. Two other factors that could also be contributing to this decline are the increasing prevalence of exploit mitigations for stack corruption issues (such as /GS and SafeSEH) and the increasing effectiveness of static analysis tools designed to detect such vulnerabilities.

Another shift can be seen in Figure 2, in the increasing number of use-after-free vulnerabilities that have been exploited. This vulnerability class includes issues that arise because of incorrect management of object lifetimes. One reason for this increase is that client-side vulnerabilities have become a prime focus for attackers, and object lifetime issues are a common vulnerability class encountered in applications.

Exploits that leveraged cases where dynamic-link libraries (DLLs) were loaded in unsafe ways were seen as a small percentage of cases from 2009 to 2012, but not in 2013.  These vulnerabilities can arise when the application loads a DLL from a directory that can be written to by a lesser privileged user.

The introduction of technologies such as Data Execution Prevention (DEP) and Address Space Layout Randomization (ASLR) has also affected the way attackers attempt to exploit vulnerabilities. Figure 3 shows the techniques used in exploits targeting vulnerabilities in Microsoft products that were discovered over the past two years.

Figure 3: Techniques used by exploits targeting Microsoft products, January 2012–February 2014, as published in the Microsoft Security Intelligence Report volume 16

This data suggests that the increasing prevalence of DEP and ASLR has forced attackers to identify new techniques that can be used to exploit vulnerabilities even when ASLR and DEP are enabled. An increasing number of exploits attempt to bypass ASLR by relying on images that have not opted into ASLR or by taking advantage of a vulnerability to disclose information about the layout of an application’s address space.

Requiring attackers to bypass DEP and ASLR makes developing exploits more difficult and expensive, which has likely been a major factor in the 70 percent reduction in the number of remote code execution vulnerabilities that were exploited in Microsoft software over the past three years. Increased adoption of recent versions of Internet Explorer and EMET could help contribute to this positive trend, as developing effective exploits becomes even more difficult.

Tim Rains
Trustworthy Computing