The registry is an integral part of Windows operating systems. It provides a centralized database containing configuration information about software installed on the system and the system itself. Applications often access the registry, and the manner in which they do so is quite important for security reasons because the information in there can direct how the program operates. Information in the registry can be stored in several formats and is used for controlling many aspect of a program's behavior. Applications might store pathnames to more detailed configuration files or helper DLLs, integer values that determine the level of processing an application performs on a file, and so forth. You need to be able to examine each access to the registry in an application to determine whether it's done securely; if it isn't, you must evaluate the level of danger that the application is exposed to if someone takes advantage of an insecure registry access. The registry is organized in a large tree structure. Each top node is called a key, each nonleaf node below a top node is a subkey, and each leaf node is a value. Several predefined keys exist on every system. Table 11-12 summarizes them, based on information in the MSDN.
Key PermissionsAs mentioned already, keys are securable objects, so they have a set of access rights used to restrict who can read and write to keys and constituent vales. Table 11-13 summarizes these access rights, based on information in the MSDN.
The permissions applied to keys created by applications are quite critical because the capability to manipulate them can result in severe modification of an application's behavior. The exact effects of altering registry keys is very application specific. In the worst case, however, unchecked registry manipulation could allow an attacker to manipulate the most critical elements of a Windows system. Another important point is that registry keys can be secured but registry values can't. The values are simply in the security scope of the keys, so any attempt to implement a permission boundary must be applied to keys, not values. Key and Value SquattingAs with all other named objects, keys could potentially be created before an application creates them. This could allow attackers to supply arbitrary values to the key, regardless of permissions the application attempts to enforce. Key squatting is far less likely than other name squatting for two main reasons:
Despite these reasons, key squatting might still be an issue. Services can store session-related information in the registry, allowing applications to potentially squat on key and value pairs. Client applications might also perform similar operations that leave them vulnerable to client-side registry squatting attacks. Here's the API for creating and opening registry keys: LONG RegCreateKeyEx(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPTSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) The RegCreateKeyEx() function is responsible for creating a new key or opening an existing key. The first parameter is a handle to an existing key or one of the predefined keys discussed earlier. The second parameter is the subkey to create or open. All the remaining parameters provide information about the subkey, such as what type of data is stored in the key, associated security permissions, and so forth. If the key already exists, all parameters pertaining to the type of key and the key access permissions are ignored. When looking for key-squatting issues, the last parameter, lpdwDisposition, is important. This value is filled in by RegCreateKeyEx() and can contain REG_CREATED_NEW_KEY to indicate it created the key successfully or REG_OPENED_EXISTING_KEY. Therefore, an application is immune to key squatting if it checks this value, as shown in this example: BOOL CreateNewKey(HKEY hKey, LPCSTR lpSubKey, HKEY hNewKey) { DWORD dwDisp; if(RegCreateKeyEx(hKey, lpSubKey, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hNewKey, &dwDisp) != ERROR_SUCCESS) return FALSE; if(dwDisp != REG_CREATED_NEW_KEY) return FALSE; return TRUE; } However, if an application fails to check the lpdwDisposition value and is writing to a registry location accessible to malicious users, the potential for key squatting exists. The following example is a slightly modified version of the CreateNewKey() function that's now vulnerable to key squatting: BOOL CreateNewKey(HKEY hKey, LPCSTR lpSubKey, HKEY hNewKey) { if(RegCreateKeyEx(hKey, lpSubKey, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hNewKey, NULL) != ERROR_SUCCESS) return FALSE; return TRUE; } Notice that a NULL value is supplied as the disposition argument to RegCreateKeyEx(). Therefore, there is no way of knowing whether a new key is a created key or an existing one is opened. This failure to check for the key's creation state leaves this code vulnerable to key squatting attacks. |