Testing for
            Software Security
                                                ware actually does. Developers a...
(continued from page 24)                         on the OS to provide resources such as              Creating environmenta...
(continued from page 26)                       of this function in the process space of         a file. It then takes a li...
(continued from page 28)                                have a correct user name, which means                 son, it is i...
utilizes the fact that parameters and calling convention for LoadLibrary are
(continued from page 32)                     ...
Upcoming SlideShare
Loading in …5
×

Testing for Software Security

541 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
541
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
14
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Testing for Software Security

  1. 1. Testing for Software Security ware actually does. Developers and testers a few extra network packets that contain Rethinking are painfully aware that these circles nev- er completely overlap. The area on the unencrypted, supposedly secure data. Luckily, there are both commercially left represents either incorrect behavior and freely available tools — such as security bugs (the software was supposed to do A but Mutek’s AppSight (http://www.identify did B instead) or missing behavior (the .com/products/appsightsuite.html) and software was supposed to do A and B but Holodeck Lite (http://se.fit.edu/holodeck/), Herbert H. Thompson did only A). Traditional software testing is well equipped to detect these types of respectively— that let you monitor these hidden actions. Another option is to write and James A. Whittaker bugs. Security bugs, however, do not fit your own customized monitoring solution such as injecting a custom DLL into the S ecurity bugs are different from other running application’s process space. types of faults in software. Tradition- al nonsecurity bugs are usually spec- Creating a Plan of Attack ification violations; the software was Software takes input from many different supposed to do something that it didn’t sources. Users, operating-system kernels, do. Security bugs, however, typically man- other applications, and filesystems all sup- ifest themselves as additional behavior — ply input to applications. You have con- something extra the software does that trol over these interfaces, and by careful- was not originally intended. This can make ly orchestrating attacks through them, you security-related vulnerabilities particular- can uncover many vulnerabilities in the ly hard to find because they are often software. Figure 2 is a simple model of masked by software doing what it was software and its interaction with the envi- supposed to. ronment. This model gives you a way to Traditional testing techniques, therefore, conceptualize these interactions. The four are not well equipped to find these kinds principal classes of input in Figure 2 are: of bugs. Why? For one thing, testers are trained to look for missing or incorrect • Human interface (UI). Implemented as output; they see only the correct behav- a set of APIs that get input from the key- ior and neglect to look for other side-effect well into this model. They tend to mani- board, mouse, and other devices. Se- behaviors that may not be desirable. fest as side effects; for instance, the soft- curity concerns from this interface in- For instance, the circle on the left in ware was supposed to do A, and it did, clude unauthorized access, privilege Figure 1 represents the specification — but in the course of doing A, it does B as escalation, and sabotage. what the software is supposed to do. The well. Imagine a media player that flaw- • Filesystem. Provides data stored in ei- circle on the right represents the true func- lessly plays any form of digital audio or ther binary or text format. Often, the tionality of the application — what the soft- video, but manages to do so by writing filesystem is trusted to store information the files out to unencrypted temporary such as passwords and sensitive data. Herbert is Director of Security Technology storage. This is a side effect that software You must be able to test the way in for System Integrity LLC (http://www pirates would be happy to exploit. which this data is stored, retrieved, en- .sisecure.com). James is a professor of com- It is important that as you verify func- crypted, and managed for security. puter science at the Florida Institute of tionality, you also monitor for side effects • API. Operating systems, libraries, and Technology. Herbert and James are coau- and their impact on the security of your other applications supply inputs and thors of How to Break Software Security application. The problem is that these side data in the return values of API calls. (Addison-Wesley). They can be contact- effects can be subtle and hidden from Most applications rely heavily on other ed at hught@sisecure.com and jw@cs view. They could manifest as file writes or software and operating-system resources .fit.edu, respectively. registry entries, or even more obscurely as to perform their required functions. 24 Dr. Dobb’s Journal, November 2002 http://www.ddj.com
  2. 2. (continued from page 24) on the OS to provide resources such as Creating environmental failure scenar- Thus, your application is only as secure memory and disk space, the filesystem to ios can be difficult, usually requiring you as the other software it uses and how read and write data, the registry to store to tamper with the application code to well equipped it is at handling bad data and retrieve information, and on and on. simulate specific failing responses from through these interfaces. These resources all provide input to the the operating system or some other re- • Operating-system kernel. Provides mem- software — not as overtly as human users source. This approach isn’t very feasible ory, file pointers, and services such as do, but input nonetheless. Like any input, in the real world, however, because of the time and date functions. Any informa- if the software receives a value outside of amount of time, effort, and expertise it tion that an application uses must pass its expected range, it can fail. takes to simulate just one failure in the through memory at one time or anoth- environment. Even if you did decide to er. Information that passes through use this approach, the problem is deter- memory in an encrypted form is gener- mining where in the code the application ally safe, but if it is decrypted and stored uses these resources and how to make even momentarily in memory, then it is the appropriate changes to simulate a real at risk of being read by hackers. En- failure in the environment. cryption keys, CD keys, passwords, and One alternative One alternative approach is run-time other sensitive information must even- fault injection: Simulating errors to the ap- tually be used in an unencrypted form and its exposure in memory needs to approach is plication in a black-box fashion at run time. This approach is nonintrusive and be protected. Another concern with re- spect to the operating system is stress run-time fault lets you test production binaries, not just contrived versions of your applications testing for low memory and other faulty operating conditions that may cause an injection that have return values hard coded. There are several ways to do this; in the exam- application to crash. An application’s tol- ple presented here, we overwrite the first erance to environmental stress can pre- few bytes of the actual function to be vent denial of service and also situations called in the process space and insert a in which the application may crash be- JMP statement to our fault injection code fore it completes some important task in its place. There are other methods that (like encrypting passwords). Once an can be used as well, such as modifying application crashes, it can no longer be When failures in the environment occur, the import address tables; a technique for responsible for the state of stored data. error-handling code in the software (if it which we have found Jeffrey Richter’s Pro- If that data is sensitive, then security may exists) gets called. Error handlers tend to gramming Applications for Microsoft Win- be compromised. be the weak point of an application in dows, Fourth Edition (Microsoft Press, terms of security. One reason for this is 1999) to be an excellent reference. At first glance, it seems as if you could that failures in the software’s environment Using these techniques, you can redi- organize a plan of attack by looking at that exercise these code paths are difficult rect a particular system call to your own each method of input delivery individu- to produce in a test lab situation. Conse- impostor function. One passive use for ally, and then bombard that interface with quently, tests that involve disk errors, mem- this is to simply log events. This can be input. For security bugs, though, most re- ory failures, and network problems are usu- informative for the security tester because vealing attacks require you to apply in- ally only superficially explored. It is during it lets you watch the application for file, puts through multiple interfaces. With this these periods that the software is at its most memory, and registry activity. in mind, we scoured bug databases, in- vulnerable and where carefully conceived At this point, you are in control of the cident reports, advisories, and the like, security measures break down. If such sit- application and can either forward a sys- identifying two broad categories of attacks uations are ignored and other tests pass, tem request to the actual OS function or that can be used to expose vulnerabili- we are left with a dangerous illusion of se- deny the request by returning any error ties — dependency attacks and design- curity. Servers do run out of disk space, message you choose. This technique is il- and-implementation attacks. network connectivity is sometimes inter- lustrated in the first attack. mittent, and file permissions can be im- Attacking Dependencies properly set. Such conditions cannot be ig- Block access to libraries. Applications Applications rely heavily on their envi- nored as part of an overall testing strategy. rely on external software libraries to get ronment to work properly. They depend What’s needed is a way to integrate these work done. Operating-system libraries and failures into your tests so that you can eval- third-party DLLs are critical for the appli- Actual uate their impact on the security of the cation to function properly. As testers and Traditional Software product itself and its stored data. developers, it is your responsibility to en- Faults Functionality sure that failures here do not compromise the security of your application. By deny- Kernel ing a library to load, you have deprived ating System the application of some functionality it ex- Oper pected to use. If the application does not API Application Under Test UI react to this failure by displaying an error Unintended, message, this may be a sign that appro- Intended Undocumented, priate checks are not in place and that the Functionality or Unknown software may be unaware that this code Functionality Filesystem did not load. If the library in question pro- vides security service, then all bets are off. Figure 1: Intended versus You can deny a library to load in Win- implemented software behavior. Figure 2: A look at software's users. dows by intercepting the LoadLibraryExW 26 Dr. Dobb’s Journal, November 2002 http://www.ddj.com
  3. 3. (continued from page 26) of this function in the process space of a file. It then takes a little detective work function. For instance, consider a publi- the application under test. These bytes are to determine which services the library is cized bug with Internet Explorer’s Con- replaced with a JMP statement to the mem- providing to the application and when tent Advisor feature (see “Exposing Soft- ory address of our imposter function, im- they are used. With a few modifications ware Security Using Runtime Fault poster_LoadLibraryExW. to the imposter function, you can then de- Injection” in Proceedings of the ICSE The problem with IE’s Content Advisor termine what would happen if that func- Workshop on Software Quality, 2002). If is that if IE fails to load the library msrat- tionality were to be denied. Listing Two you turn the feature on, all web sites that ing.dll, users can surf the Web unrestrict- is the source of the executable used to in- don’t have a RASCi rating are blocked by ed. Our imposter function checks to see ject our DLL into the target application’s default. (The Recreational Software Advi- whether the library that the application is process space. sory Council, RASCi, rating is assigned to attempting to load is msrating.dll; if so, it In addition to LoadLibraryExW, this a web site based on its content. This rat- blocks the library from being loaded by code can easily be modified to intercept ing system was replaced in 1999, howev- returning NULL (indicating failure) to the other system calls and monitor and/or se- er, with the Internet Content Rating As- application. lectively deny them at run time. We have sociation, ICRA, rating system.) Listing One You can uncover clues to library de- developed a freeware tool called is the C++ source code of a DLL you can pendencies such as this by changing the “Holodeck Lite” (available electronically inject into the application to hook the code in the imposter function, either to at http://se.fit.edu/holodeck/ and from function LoadLibraryExW for Windows alert you when a specific call is made or DDJ; see “Resource Center,” page 5), us- XP. Our DLL overwrites the first few bytes log all such calls and their parameters to ing techniques similar to those in Listing One, to help you easily monitor and ob- struct common system calls. Manipulate registry values (Windows specific). The problem with the registry is trust. When developers read informa- tion from the registry, they trust that the values are accurate and haven’t been tam- pered with maliciously. This is especially true if their code wrote those values to the registry in the first place. One of the most extreme vulnerabilities is when sen- sitive data, such as passwords, is stored unprotected in the registry. More complex information can cause problems too. Take, for example, “try and buy” software, where users have either limited functionality or a time limit in which to try the software, or both. In these cases, the application can then be un- locked if it is purchased or registered. In many cases, the check an application makes to see if users have purchased it or not is to read a registry key at startup. We’ve found that in some of the best cas- es, this key is protected with weak en- cryption; in some of the worst, it’s a sim- ple text value: 1 purchased; 0 trial. Force the application to use cor- rupt/protected files and file names. A large application may read from, and write to, hundreds of files in the process of car- rying out its tasks. It’s the tester’s job to make sure that applications can handle bad data gracefully, without exposing sen- sitive information or allowing unsafe be- havior. This attack is carried out by taking a file that the application uses and changing it in some way the software may not have anticipated. For a file that contains a se- ries of numerical data that the software reads, for instance, you may want to use a text editor and include letters and spe- cial characters. If successful, this attack usually results in denial of service either by crashing the application or by bring- ing down the entire system. More creative (continued on page 32) 28 Dr. Dobb’s Journal, November 2002 http://www.ddj.com
  4. 4. (continued from page 28) have a correct user name, which means son, it is important to test an application’s changes may force the application to ex- there is now only one string value to at- ability to handle long strings in input fields. pose data during a crash that users would tack— the password. This attack is especially effective when not normally have access to. Seek out unprotected test APIs. Com- long strings are entered into fields that Force the application to operate in low- plex, large-scale applications are often dif- have an assumed, but often not enforced, memory/diskspace/network availabil- ficult to test effectively by relying on the length such as ZIP codes and state names. ity conditions. Depriving applications of APIs extended for normal users alone. API calls have been notorious for un- these resources lets testers understand how Sometimes there are multiple builds a day, constrained inputs. As opposed to a GUI robust their application is under stress. The each of which has to go through some where you can filter inputs as they are en- decision of which faults to try and when suite of verification tests. To meet this de- tered, API parameters must be dealt with can only be determined on a case-by-case mand, many applications include hooks internally and checks must be done to en- basis. A general rule of thumb, though, is sure that values are appropriate before to block a resource when an application they are used. The most vulnerable APIs seems most in need of it. For memory, this tend to be those that are seldom used or may be during some intense computation support legacy functionality. the application is doing. For disk errors, Connect to all ports. Sometimes appli- look for file writes/reads by the applica- cations open custom ports on machines tion, then start pounding it with faults. Software security to connect with remote servers. Reasons These faults can be simulated relatively for this vary from creating maintenance easily by modifying the code in Listing One to intercept other system functions, testing must go channels to automatic updates or possi- bly as a relic from test automation. There such as CreateFile. beyond traditional are many documented cases (see http:// www.ntbugtraq.com/) where these ports Attacking Design and Implementation It’s difficult to identify all the subtle secu- testing are left open and unsecured. It is impor- tant that the same scrutiny that’s been giv- rity implications of choices made during en to the communications through the the design phase. Looking at a 200-page standard ports (Telnet, ftp, and so on) be specification and asking “Is it secure?” will given to these application-specific ports be met with blank looks, even by the most and the data that flows through them. experienced developers. Even if the de- sign is secure, the choices made by the Conclusion development team during implementation that are used by custom test harnesses. Software security testing must go beyond can have a major impact on the security These hooks and corresponding test APIs traditional testing if we ever hope to re- of the product. Here we present some at- often bypass normal security checks done lease secure code with confidence. In this tacks that have been effective at exposing by the application for the sake of ease of article, we have discussed a fault model these types of bugs. use and efficiency. They are added for that describes a paradigm shift from tra- testers by developers with the intention ditional bugs to security vulnerabilities, Force all error messages. This attack of removing them before the software is and outlined some of the attacks testers serves two purposes. The first is to see released. The problem, though, is that can use to better expose vulnerabilities how robust the application is by trying these test APIs become so integrated into before release. These attacks are only part values that should result in error messages the code and the testing process that when of a complete security-testing methodol- and see how many are handled properly, the time comes for the software to be re- ogy. Research into security vulnerabilities, improperly, or not at all. The second is to leased, managers are reluctant to remove their symptoms, and habits has only just make sure that error messages do not re- them for fear of destabilizing the code. It begun. veal unintended information to a would- is critical to find these hooks and ensure be intruder; for example, during authen- that if they were to make it out into the Acknowledgments tication, having one error message that field, they could not be used to open up Thanks to Rahul Chaturvedi for providing appears when an incorrect user name is vulnerabilities in the application. code excerpts from Holodeck and to At- entered and having a different error ap- Overflow input buffers. The first thing tila Ondi, Ibrahim El-Far, and Scott Chase pear when a valid user name is entered that comes to many peoples’ minds when for their input on this article. but with an incorrect password. At this they hear the term “software security” is point, the attacker then knows that they the dreaded buffer overflow. For this rea- DDJ Listing One { return real_LoadLibraryExW(lpFileName, hFile, dwFlags); #include "stdafx.h" } #include <windows.h> } typedef HMODULE (WINAPI *loadlibrary_t) (LPCWSTR, HANDLE, DWORD); BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, loadlibrary_t real_LoadLibraryExW; LPVOID lpReserved DWORD dwAddr; ) /* Our imposter function for the real LoadLibraryExW. All it does is check { if the incoming filename is msrating.dll and either returns NULL and switch (ul_reason_for_call) sets an appropriate error, or lets the call go through to our saved header { instructions of the real function which then jump to the real function case DLL_PROCESS_ATTACH: in the appropriate location. // Allocate memory for copying the first few instructions of the target */ // function. Since the granularity on VirtuallAlloc is a page, might as HMODULE WINAPI imposter_LoadLibraryExW(LPCWSTR lpFileName, // well allocate 4096 bytes HANDLE hFile, DWORD dwFlags) real_LoadLibraryExW = (loadlibrary_t) VirtualAlloc(NULL, 4096, { MEM_COMMIT,PAGE_EXECUTE_READWRITE); if (!_wcsicmp(lpFileName, L"msrating.dll")) // Copy first two instructions of LoadLibraryExW (which we know add up { // to 7 bytes - we need 5 for our jump). SetLastError(ERROR_FILE_NOT_FOUND); memcpy((void *) real_LoadLibraryExW, (void *)LoadLibraryExW, 7); return NULL; } else (continued on page 34) 32 Dr. Dobb’s Journal, November 2002 http://www.ddj.com
  5. 5. utilizes the fact that parameters and calling convention for LoadLibrary are (continued from page 32) the same as the thread function that is suplied to CreateThread/ // Writes a jump instruction out right after the copied instructions. CreateRemoteThread. It uses that API to call LoadLibrary in the target // The jump is a relative near jump to the 8th byte of LoadLibraryExW. process and load the desired DLL. PBYTE pbCode = (PBYTE) real_LoadLibraryExW + 7; */ int main(int argc, char* argv[]) // Write opcode for jump near and move (write) pointer forward { *(pbCode++) = 0xe9; DWORD dwTemp; LPVOID pvDllName; // Write out address of where to jump to using a double word pointer. // That way, compiler takes care to put it in big endian convention. if (argc < 3) PDWORD pvdwAddr = (PDWORD) pbCode; { printf("Usage: inject commandline dllname.dlln"); // Write out address - the +3 = -4 +7 (for the offset into the function) return 0; *pvdwAddr = (DWORD) LoadLibraryExW - (DWORD) pbCode + 3; } // Move (write) pointer forward the length of the address. // Setup the required structures and start the process pbCode+=4; PROCESS_INFORMATION pi = {0}; DWORD dwOld, dwTemp; STARTUPINFO si = {0}; si.cb = sizeof(si); if (!CreateProcess(NULL, argv[1], NULL, NULL, false, NULL, // Set the page with LoadLibraryExW to writeable NULL, NULL, &si, &pi)) VirtualProtect((LPVOID) LoadLibraryExW, 4096, goto error; PAGE_EXECUTE_READWRITE, &dwOld); // Write out the jump // Allocate memory for the name of the DLL to be loaded pbCode = (PBYTE) LoadLibraryExW; if (!(pvDllName = VirtualAllocEx(pi.hProcess, NULL, strlen(argv[2]), MEM_COMMIT, PAGE_EXECUTE_READWRITE))) // Write opcode for jump near to the beginning to LoadLibraryExW goto error; *((PBYTE) LoadLibraryExW) = 0xe9; // Write out the name of the target DLL // Compiler gymnastics to move forward by *1* byte and not 4 to get if (!WriteProcessMemory(pi.hProcess, pvDllName, argv[2], // the exact address where to write the target address for the jump to. strlen(argv[2]), &dwTemp)) pvdwAddr = (PDWORD) (pbCode + 1); goto error; dwAddr = (DWORD) pvdwAddr; // Technically this will execute LoadLibrary in the target process with // Write the address // name of the DLL as the first parameter. This relies on the fact that *pvdwAddr = (DWORD) imposter_LoadLibraryExW - (DWORD) LoadLibraryExW - 5; // that kernel32.dll will NOT be relocated. Assuming that it won't be, then // then address of LoadLibraryA in the target process is the same as ours // Set the old protection back. This is very important for some Win32 if (!CreateRemoteThread(pi.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE) // functions. They refuse to work with writeable protection enabled. LoadLibraryA, pvDllName, NULL, &dwTemp)) VirtualProtect((LPVOID) LoadLibraryExW, 4096, dwOld, &dwTemp); goto error; return 0; break; error: } if (pi.hProcess) return TRUE; TerminateProcess(pi.hProcess, 0); } printf("Error in injection!n"); return -1; } Listing Two #include "stdafx.h" #include <windows.h> /* This program uses one of the simplest injection techniques out there. It DDJ 34 Dr. Dobb’s Journal, November 2002 http://www.ddj.com

×