Every complex software program has costly security vulnerabilities. These are the vulnerabilities that allow viruses and worms to thrive and that allow criminals to grab personal financial data from websites. Ideally, security is designed into a program, and the program is coded by developers trained in secure programming. Yet, even when this philosophy is adhered to, security flaws creep in as mistakes are made, and complex software interactions go unnoticed.
Security researchers have developed a way to perform vulnerability testing during the development process: application penetration testing. Application penetration testing is a way to break into a software application to uncover its security flaws. Programmers and testers can use this little-known technique to find security flaws in their programs while they’re in development.
This article will teach you how to prioritize your security testing, how to build a lab environment for security testing, and how to actually stage attacks to uncover application security flaws.
Prioritize Security Testing
Application penetration testing, like code review, is still a mostly manual process. Therefore, prioritizing the risk of program interfaces and features is crucial for finding the most serious security flaws first. To come up with this prioritized list, I recommend threat modeling. (See sidebar on p. 32 for an in-depth look at threat modeling.) In threat modeling, potential risks are hypothesized based on an understanding of the application's design, not on how an application was meant to be used. An example threat might be "authentication process accepts data from anonymous users and passes it to the SQL server." The output of threat modeling is a list of threats. In this example, if the program properly validates input, it will have mitigated this threat, which then would not be considered a vulnerability.
Once hypothesized, the threats then are ranked according to how easy they are to attack and the seriousness of the impact of that attack. The risks that are easiest to attack but whose exploitation yields the greatest impact are the threats that should be focused on first during staged attacks, where the identified threats will be attacked to determine if they are actual vulnerabilities.
Build A Lab Environment
Note that a "threat" is only a potential "vulnerability." We need to determine which threats on our prioritized list are, in fact, vulnerabilities. To do this, we need to stage some application attacks. The best place to do this is in a lab environment so that every aspect of an attack can be controlled. Typically, this will include an isolated network that is instrumented and under our control, so we can stage any potential network attacks. The software should be installed on an instrumented machine. This is similar to the hardware and software that a developer would use to debug the application. In a client-server application, we want to have both the client and server software installed on instrumented machines so we can control every input.
It is important to be able to generate any arbitrary network traffic. Many applications make the assumption that the network input they receive is well formed. Attackers can exploit this assumption to get a program to perform erroneous processing on the malicious input they provide. This erroneous processing often leads to buffer overflows, a common vulnerability.
Common security mechanisms used by programs that communicate over the network are authentication and session management. These allow the application to verify that incoming data was actually sent by a user who has been validated by the application. In order to modify the data sent to such a program, it is often easier to perform a man-in-the-middle class of attack than to replicate all the authentication and session management processing in an attack program. To perform this type of attack and instrument the network, a network hub should be used to connect the lab machines to the lab network.
The application should be installed on the most popular user platform. We want to make sure we first find the security issues that impact the most customers. For client-server applications, this may be a different platform for the server software and the client software. The application should be installed with its default settings. The vast majority of users are going to be running in this configuration. While finding security issues in custom configurations is valuable, this is a lower priority than uncovering the security flaws that will impact most customers.
We want to have maximum visibility into what the application is doing at any given time. Network activity, file input and output, registry access, interprocess communication, and user input are typical threat paths that need to be monitored and manipulated. Common debugging and OS monitoring tools should be installed on the machines running the software under test. Table 1 lists some tools that are useful for performing application penetration testing on Windows programs.
Stage An Attack
Now that our priorities have been established and our lab environment created, it's time to penetrate that application. To to that, I'll use a network attack. Network attacks are relevant to applications that use the network for any communications, whether client to server, server to client, or peer to peer. The network interfaces to a program are the highest risk threat paths, so they should guide the attacks that are attempted first. Remember that all security testing should follow the priorities that are ranked during threat modeling.
There are two main ways to attack an application through the network. The first and easiest is to use a debug proxy to manipulate the network traffic between the client and the server software under test. The second method is to develop a custom client or custom server that can communicate to the client and server application under test. The custom client or server is more work to develop but can produce better test coverage.
A debug proxy sits between two programs that are communicating with the network and allows network data to be intercepted, modified, and then sent to the intended destination. Parts of the data are changed, deleted, or added to with the intention that the program on the receiving end will not properly process the modified data and will fault.
A debug proxy is designed specifically for the network protocol that the application is using to communicate over the network. To select the specific debug proxy you need to employ for an application, exercise the application and monitor its communication over the network with a network monitor such as Ethereal. If the protocol used is an Internet standard or a popular nonstandard protocol, Ethereal should be able to decode the protocol and tell you what it is.
One of the most popular network protocols today is the Hyper Text Transfer Protocol (HTTP). It is used by all Web applications and many other non-Web-based programs. Many debug proxies have been written for HTTP, and it is most useful to use one that has been designed specifically for application penetration testing. Examples are Achilles, WebProxy, and WebScarab.
The debug proxy I am illustrating sits between the Web browser and the Web application, allowing any part of the HTTP protocol to be manipulated. The data manipulated could be HTTP header values, such as cookies, or HTTP body values, such as the form values used in a Web form. For example, an attacker could manipulate the session identifier that many Web applications place in cookies. Some developers assume that it is not possible for an attacker to manipulate cookie values. Our debug proxy enables us to change the session identifier an application may store in a cookie. Then we test whether the developer put the proper security mechanisms in place. Figure 2 is a picture of the debug proxy request editor screen.
The debug proxy has intercepted a Web transaction and is displaying the details in an editor. The cookie that contains the session identifier is highlighted. You, acting as the attacker, can now edit the cookie and send the modified data to the Web application. Changing the cookie to "sessionid=1002" may trick the application into thinking you are a different authenticated user. After you submit the modified data, the debug proxy will display the results in the Web browser. You then can see if you get an error message or unexpected result. If the Web application starts acting as if you are another user, you have found a security vulnerability. It really is that easy.
With a Web debug proxy you will want to test for some of the other common classes of vulnerabilities:
For more information about how to stage these attacks, see the Open Web Application Security Project.
Some applications use their own custom network protocol or other network protocol where there is no off-the-shelf debug proxy available to manipulate the network data. In these cases you will need to write some code to test the network interface. While programming skills are required for this, most of the time you don't need to write a client from scratch. Sometimes test harnesses are available that with minimal work can be extended to send malicious data that will trigger vulnerabilities. If the protocol is standard, someone in the open source community may have developed an open source client that you can modify.
First, use a network monitor and any available product documentation to determine what protocol the application is using. Then do a search of available open source programs to find a suitable client. Because the program will need to be modified, it is important that the program is open source and not just a different closed source client.
Find the places in the code where the individual data fields are generated by the client and modify the program to substitute malicious data. This malicious data should stress the application under test and uncover different classes of problems. Table 2 lists several vulnerability classes with examples of data that could reveal a vulnerability if the program doesn't handle the data properly.
You will want to try injecting this malicious data and its variations for every network data input. When using Unicode encodings for the characters in the input data it is important to determine whether input checks can be bypassed. For instance, you would encode the "." character used for path traversal as "%c0%ae". For large and complex applications with many inputs, this can be a long and tedious process, but if you don't do it now, the real attackers might later!
If you must build a custom client from scratch to test your network application, you might want to start with a fault injection toolkit like SPIKE from Immunity. SPIKE is a free open source program that allows you to quickly build your own custom protocol tester. SPIKE comes already built to test HTTP, RPC, and SMB and is readily extensible to other standard or proprietary protocols.
If your software is a client itself, you need to think of a malicious server as your attack platform for penetration testing. All the same rules for building custom clients hold true, except you will be building a custom server. If your software is a peer-to-peer program, such as P2P file sharing or chat, you need to build a malicious peer with which your software can interact.
Application penetration testing can be performed by most software quality assurance testers if they are given the proper tools and some minimal training. More than anything, penetration testing is a mindset shift from positive feature testing to assuming the role of an attacker. By using the threat modeling technique to prioritize security risks, the most serious security flaws can be uncovered first. This allows even a short application penetration test to deliver valuable results.
HTTP Debug Proxies
SPIKE from Immunity