TYPES OF PENETRATION TESTS

Testing is about variation—finding the things in the software and its environment that can be varied, varying them, and seeing how the software responds. The goal is to ensure that the software performs reliably and securely under reasonable and even unreasonable production scenarios. So the most fundamental planning a tester can do is to understand what can be varied and what ways that variation needs to be staged for testing. From a security standpoint, the environment, user input, and internal data and logic are the primary places where such variation can reveal security issues. The environment consists of the files, applications, system resources, and other local or network resources used by the application. Any of these could be the entry point of attack. User input is the data that originates with external (usually untrusted) entities that is parsed and used by the software. Internal data and logic are the internally stored variables and logic paths, which have any number of potential enumerations. By varying the information in the software’s environment, input domain and data/logic paths, you can perform attacks.

Environment Attacks
Software does not execute in isolation. It relies on any number of binaries and code-equivalent modules, such as scripts and plug-ins. It may also use configuration information from the registry or file system as well as databases and services that may reside anywhere. Each of these environmental interactions may be the source of a security breach and therefore must be tested. There are also a number of important questions you must ask about the degree of trust that your application has in these interactions, including the following: How much does the application trust its local environment and remote resources? Does the application put sensitive information in a resource (for instance, the registry) that can be read by other applications? Does it trust every file or library it loads without verifying the contents? Can an attacker exploit this trust to force the application to do his bidding? In addition to the trust questions, penetration testers should watch for DLLs that might be faulty or have been replaced (or modified) by an attacker, binaries, or files with which the application interacts that are not fully protected by access control lists (ACLs) or are otherwise unprotected. Testers must also be on the lookout for other applications that access shared memory resources or store sensitive data in the registry or in temporary files. Finally, testers must consider factors that create system stress, such as a slow network, low memory, and so forth, and determine the impact of these factors on security features. Environment attacks are often conducted by rigging an insecure environment and then executing the application within that environment to see how it responds. This is an indirect form of testing; the attacks are waged against the environment in which the application is operating. Now let’s look at direct testing.

Input Attacks
In penetration testing, the subsets of inputs that come from untrusted sources are the most important. These include communication paths such as network protocols and sockets, exposed remote functionality such as DCOM, remote procedure calls (RPCs) and Web services, data files (binary or text), temporary files created during execution, and control files such as scripts and XML, all of which are subject to tampering. Finally, UI controls allowing direct user input, including logon screens, Web front ends, and the like, must also be checked. Specifically, you want to determine whether input is properly controlled: are good inputs allowed in and bad ones (such as long strings, malformed packets, and so forth) kept out? Suitable input checking and file parsing
are critical.

You’ll need to test to see whether dangerous input can be entered into UI controls, and find out what happens when it is. This includes special characters, encoded input, script fragments, format strings, escape sequences, and so forth. You’ll need to determine whether long strings that are embedded in packets fields or in files and are capable of causing memory overflow will get through. Corrupt packets in protocol streams are also a concern. You must watch for crashes and hangs and check the stack for exploitable memory corruption. Finally, you must ensure that such things as validation and error messages happen in the right place (client-side rather than server side) as a proper defense against bad input.Input attacks really are like lobbing grenades against an application. Some of them will be properly parried and some will cause the software to explode. It’s up to the penetration team to determine which are which and initiate appropriate fixes.

Data and Logic Attacks
Some faults are embedded in an application’s internal data storage mechanisms and algorithm logic. In such cases, there seem to be design and coding errors where the developer was assuming either a benevolent user or failed to consider some code paths where a user might tread. Denial of service is the primary example of this category but certainly not the most dangerous. Denial of service attacks can be successful when developers have failed to plan for a large number of users (or connections, files, or whatever inputs cause some resource to be taxed to its limit). However, there are far more insidious logical defects that need to be tested. For example, information disclosure can happen when inputs that drive error messages and other generated outputs reveal exploitable information to an attacker. One practical example of such data that you should always remove is any hardcoded test accounts or test APIs (which are often included in internal builds to aid test automation). These can provide easy access to an attacker. Two more
tests you should run are to input false credentials to determine if the internal authorization mechanisms are robust, and choose inputs that vary the code paths. Often one code path is secure but the same functionality can be accessed in a different way, which could inadvertently bypass some crucial check.

Don’t Be Deterred
Penetration testing is very different from traditional functional testing; not only do penetration testers lack appropriate documentation, but they also must be able to think like users who intend to do harm. This point is very important—developers often operate under the assumption that no reasonable user would execute a particular scenario, and therefore decline a bug fix. But you really can’t take chances like that. Hackers will go to great lengths to find vulnerabilities and no trick, cheat, or off-the-wall test case is out of bounds. The same must be true for penetration testers as well.