Search the Community
Showing results for tags 'figure'.
-
In early January 2015, researcher Michael Heerklotz approached the Zero Day Initiative with details of a vulnerability in the Microsoft Windows operating system. We track this issue as ZDI-15-086. Unless otherwise noted, the technical details in this blog post are based on his detailed research. To understand the significance of his report, we need to go back to the last decade. In mid-2009, Stuxnet was released against the Iranian nuclear program. Attributed to the United States and Israel, Stuxnet used multiple zero-day attacks against Windows to attack the Iranian centrifuges. It was discovered in June 2010 by VirusBlokAda and reported to Microsoft. In February 2015, Kaspersky Labs' Global Research & Analysis Team released findings that attacks included in Stuxnet were in use as early as 2008. The initial infection vector was a USB drive that took advantage of a vulnerability in the Windows operating system that allowed simply browsing to a directory to run arbitrary code. Windows allowed for .LNK files, which define shortcuts to other files or directories, to use custom icons from .CPL (Control Panel) files. The problem is that in Windows, icons are loaded from modules (either executables or dynamic link-libraries). In fact, .CPL files are actually DLLs. Because an attacker could define which executable module would be loaded, an attacker could use the .LNK file to execute arbitrary code inside of the Windows shell and do anything the current user could. To prevent this attack, Microsoft put in an explicit whitelist check with MS10-046, released in early August 2010. Once that patch was applied, in theory only approved .CPL files should have been able to be used to load non-standard icons for links. The patch failed. And for more than four years, all Windows systems have been vulnerable to exactly the same attack that Stuxnet used for initial deployment. To see how it failed, we need to examine the fix itself. To show the vulnerability in action, we made a brief video: The definition of the icon that will be used is extracted in a function called CControlPanelFolder::GetUiObjectOf() in Shell32.dll. We can see what changed by comparing the RTM version of Shell32.dll with the latest vulnerable version, using DarunGrim. Figure 1 Diffing the function We can see there are only two sections of code (highlighted above in red) that have changed in this function since release. The first changed block looks like this: Figure 2 The first changed block in the function (click to expand in new window) We can see that in the event the definition calls for a custom icon (that is, has a requested icon ID of 0), we check against the registered list. If we put this snippet of assembly into C++, it looks something like this: … if ( (iconID == 0) && !this->_IsRegisteredCPLApplet(&wszModuleFullPath) ) { iconID = -1; } … If the DLL isn’t on the whitelist, you cannot have the icon ID be 0, and so no custom load step. So, problem solved? Clearly not, or we wouldn’t be talking about this now. Let’s look at the other snippet of code that changed, and see if it gives us a clue. Figure 3 The second changed block in the function Now that’s interesting. If the module path specified contains a comma in it, we’re going to error out with an invalid argument. It is possible that this is unrelated to the fix for Stuxnet, but it looks odd. Let’s look at the context around it. Immediately before this block of code, there is an unchanged block that takes user-provided data and formats it -- using commas. Let’s take a look at that: Figure 4 Unchanged adjacent code If we put this block of assembly language into C++, it would look something like this: StringCchPrintfW(wszWorkingBuffer, 554u, L"%s,%d,%s", &wszModuleFullPath, iconID, &wszDisplayName); With this context, the second change looks to be part of the Stuxnet fix after all. We are forcing the icon ID to be something other than 0, but we then put it into a comma delimited string. Since we’re then erroring out if the path contains a comma, that looks like a fix for embedding a fake icon ID inside of the path, which would imply that the icon ID will be parsed out of this constructed string later. So, the obvious work-around has been closed off; we cannot spoof the formatted string to insert our own icon ID. The next thing that happens after we have formatted and checked this string is that it gets passed to ControlExtractIcon_CreateInstance(). This function creates a CCtrlExtIconBase object, and passes it the composite string as the first argument. Let’s look at the constructor. Figure 5 Following the string through the constructor (click to expand in new window) If we look at what happens to that initial argument, we see it ends up (again, translating into C++) being used like this: StringCchCopyW(this->wszIconString, 260u, pwzIconString); The buffer we have just created as 554 wide characters in length is in fact being truncated and put into a 260 wide character buffer. Not only that, but the string contains two pieces of information we know get used in icon loading – the path to the DLL and the icon ID. Where does that information come from? It comes from a function called CControlPanelFolder::GetModuleMapped(): Figure 6 Call to CControlPanelFolder::GetModuleMapped (click to expand in new window) If we put this into C++, it would look something like this: retVal = CControlPanelFolder::GetModuleMapped(pControl, false, &wszModuleFullPath, 260, &iconID, &wszModuleDisplayName, 260); There are two parts of this function that are important for us. As we can see from the code above, the caller specifies the size of the buffers that data is copied in to, and in this case, the buffers are sized for 260 wide characters. Because this data is actually extracted from the .LNK file that we control, this means we can provide a path string that is up to 260 wide characters long, and we know that there is a truncation bug that will use our data. The second issue is actually inside of CControlPanelFolder::GetModuleMapped(), and will be one of the last hurdles to exploitation. If the module path specified does not actually exist, the path will be combined with the System (or SystemWoW64) directory. Looking at that code as C++, it looks something like this: if ( !PathFileExistsW(pwzModuleFullPath) ) { if ( fDoNotUseWoW || !CControlPanelFolder::_IsWowCPL(pControl) ) GetSystemDirectoryW(&wzSystemDir, 260u); else GetSystemWow64DirectoryW(&wzSystemDir, 260u); if ( PathCombineW(&wzBuffer, &wzSystemDir, pwzModuleFileName) ) retVal = StringCchCopyW(pwzModuleFullPath, cwchModuleFullPath, &wzBuffer); else retVal = E_FAIL; } This doesn’t appear to be a problem (since we do need to actually load our planted DLL to get code running), but as we’ll see later, this is actually an issue in exploitation. To see why, we need to look at where our constructed and truncated string is used. What happens to that data? To see that, let’s look at what the actual call stack would look like when the exploit fired: Figure 7 Call stack on the DLL load for an icon Since we know that our constructed string is stored as a member variable in CCtrlExtIconBase, let’s go ahead and look at that call to _GetIconLocationW(). Figure 8 Parsing the constructed string in CCtrlExtIconBase ::_GetIconLocationW If we look at the code above, we can see that we’re searching for the comma separator (the buffer itself is one we’ve copied for the caller). If we find it, we null it out, and then derive the icon ID by calling StrToInt(). Now, we know from looking at the original fix that our icon ID will be forced to be -1, but will then be truncated into a 260 wide character buffer. Since the truncation includes the null, we’ll have 259 wide characters to work with, one of which will be a comma. If we provided a 257 character path, the string that we’d parse here is “<our path>,-“, with everything after the minus sign being truncated. And StrToIntW(L”-“) is 0. We have bypassed the check by converting the negative value back into our desired icon ID of 0. (In fact, we can skip the check entirely and just pass in a small negative icon ID to begin with.) Just putting in the overly long path won’t work, however; there is a problem. To see it, we need to go further down the call chain and see where our load fails. We know from the stack trace above that our call to LoadLibrary() will come from CPL_LoadCPLModule(). The problem is that CPL_LoadCPLModule() is also going to look for a manifest file. That, in and of itself, is not a problem, as it doesn’t require the manifest. The problem lies in how it looks for the file: Figure 9 Constructing the manifest file path If we put this into C++, it would look something like this: if ( StringCchPrintfW(&wzManifestPath, 260u, L"%s.manifest", pwzModuleFullPath) < 0 ) { return NULL; } So, if our path is too long to have a “.manifest” appended (the 260 character limit we’ve been seeing throughout this is MAX_PATH), we’re not even going to try to load the DLL. As we’ve already seen, we need to take the path to 257 characters in order to force the icon ID to 0, and we need the icon ID to be 0 to even get to CPL_LoadCPLModule(). We need one more issue. To find it, we need to work back up the stack trace, and see if we can do anything about that path name passed to CPL_LoadCPLModule(). When we do that, we can see that the string is actually extracted in the function CPL_ParseCommandLine(). CPL_ParseCommandLine uses a function called CPL_ParseToSeparator() to pull the component elements out. If we look inside CPL_ParseToSeparator(), we can see that it has two options for valid separators: Figure 10 A look inside CPL_ParseToSeparator There is a flag which determines if only commas will be considered to be separators, or if unescaped spaces will as well. When we look at the first call to CPL_ParseToSeparator() (which extracts the module path), we can see that it has the flag set to consider spaces as valid separators: Figure 11 Initial call to CPL_ParseSeparator At this point, we have everything we need to get an exploit running. We’ll need to construct a malicious .LNK file which has a link path of exactly 257 characters, but uses embedded unescaped spaces to cause the extraction to truncate in CPL_ParseToSeparator(). That allows us to have a short enough path for the concatenation of the “.manifest” to the filename in CPL_LoadCPLModule() to work. That brings us back to our earlier note that CControlPanelFolder::GetModuleMapped() will check to see if the full module path (including embedded spaces) exists. So we’ll need to have two files, one with the embedded spaces (to pass the file existence check), and one without (to actually be loaded). Unlike a case of memory corruption, this attack doesn’t need to worry about low-level operating system mitigations. This bug has its roots in the decades-old decision to load icons by loading executable modules into the process, and because of that, there is no need to worry about any other mitigations. The Windows operating system itself will handle resolving ASLR and loading the attack into executable memory. And because of that, the attack is stable, reliable, and works cleanly across Windows versions. Microsoft has gone to a great deal of effort to make exploitation of memory corruption bugs more difficult. This is a classic example of the Defender’s Dilemma -- the defender must be strong everywhere, while the attacker needs to find only one mistake. In a future Security Briefing, ZDI will examine MS15-020, the patch that was released today to address CVE-2015-0096, and look at how Microsoft made changes to try to prevent this attack from coming back a third time. Source
-
Samba Remote Code Execution Vulnerability – CVE-2015-0240 The Samba team reported CVE-2015-0240 last February 23, 2015. This vulnerability is very difficult to exploit and we are not aware of successful exploitation. However, it is quite interesting from the point for view of detection. There are two important facts: The vulnerability resides in the Netlogon Remote Protocol implementation of Samba which is a very high-level application protocol that can be used over different transports configurations. To execute the vulnerable code the attacker doesn’t need be authenticated and can use many ways to launch the attacks because of the previous point. This is very motivating for attackers as they can find ways to bypass Intrusion Prevention System (IPS). There is a very good public description about the vulnerability, which can be found at this link. In this post, we will discuss it from the point of view of involved protocols and possible attack surfaces. Vulnerability description The vulnerability resides in the Netlogon Remote Protocol implementation of Samba, specifically in the method NetrServerPasswordSet. The Netlogon Remote Protocol was implemented for interoperability with Microsoft Windows environments and for simulating Primary Domain Controllers. Using the Netlogon Remote Protocol Windows and Linux machines can be part of the Samba PDC domain even without the use of Active Directory. The method NetrServerPasswordSet is used to change the machine account password in a Samba domain. The method NetrServerPasswordSet is implemented in _netr_ServerPasswordSet() in the source file samba\source3\rpc_server\netlogon\srv_netlog_nt.c. The “creds” pointer is passed into netr_creds_server_step_check() without initialization. The following figure shows the vulnerable code section: Figure 1. Vulnerable code section The triggering conditions can be different for Samba v3 and Samba v4 as pointed in this analysis. The attacker can control “computer_name” and “credentials” to reach the vulnerable code section making this vulnerability as possibly exploitable. There is a public POC triggering the vulnerable code. Running this POC and doing dynamic analysis shows that effectively the method _netr_ServerPasswordSet is called. The following figure shows the resumed call graph of Samba. Figure 2. Call graph of Samba Running Samba with high level debugging can allow us to get more runtime information. Example of a command: smbd –D –S /etc/samba/smb.conf -d 10 The following figure shows a section of the resulting log after running the POC. After some more lines we got: This error message is logged by the function schannel_fetch_session_key_tdb and returns the error with NT_STATUS_OBJECT_NAME_NOT_FOUND. This function is called by shannel_check_creds_state. Figure 4. The error NT_STATUS_OBJECT_NAME_NOT_FOUND The error NT_STATUS_OBJECT_NAME_NOT_FOUND will force _netr_ServerPasswordSet to free the “creds” pointer. Looking at the network packets in the following figure we can see the Netlogon Protocol using the transport RPC over SMB. Figure 5. Netlogon Protocol using the transport RPC over SMB And this is one important point regarding to the attack detection. The Netlogon protocol is a high-level application protocol and can use two transport types: RPC over SMB and RPC over TCP/IP. The next section discusses more about this topic. Attack Delivery Mechanisms The Netlogon Remote Protocol is a very high level application protocol that can run on different protocol stack configurations. The following figure shows it. Figure 6. Netlogon Protocol runs on different protocol stack configurations Figure 6 shows that theoretically, an attacker can use two stack configurations to reach the vulnerable code. They are: RPC over TCP/IP and RPC over SMB. These two configurations will use different network ports and communication mechanisms. This is a panacea for implementing attacks bypassing IPS. But even more interesting is the case over SMB where the NetrServerPasswordSet can be called using several SMB commands and at the same time the parameters to the method can be encrypted and unencrypted. The following figure shows other ways to call NetrServerPasswordSet. Figure 7. Other ways to call NetrServerPasswordSet Conclusion The vulnerability it is not easy to exploit and we are not aware of public exploits until now. However, the attack can be implemented in many different ways and the fact that it is not required to be authenticated makes it easy for the attackers. Implementing the protection requires coverage of multiple protocol stack configurations and multi commands over SMB. Sursa: Samba Remote Code Execution Vulnerability – CVE-2015-0240