DLL Search Order Hijacking Revisited
Written by Nick Harbour
Since my last blog post on the topic of DLL Search Order Hijacking there has been a lot of community activity in this area. The purpose of this article is to differentiate the specific hijack technique I was describing from the one that is currently being discussed in the media as well as propose my own solution to the problem.
The internet community took notice of DLL hijacking when a link to a security advisory was being passed around Twitter and being discussed by various security industry figureheads. The advisory was produced by a company named Acros Security and can be found here: http://www.acros.si/aspr/ASPR-2010-08-18-1-PUB.txt. I was naturally curious about this as it was published only one month after my blog post on the topic and sounded at first very similar. People have been taking this technique and discovering vulnerabilities in many applications, as is visible in the enormous spike in activity on exploit-db.com (http://www.exploit-db.com/local/) on August 24th and 25th.
The key difference in this technique as opposed to the one I described is that it relies on a DLL being placed in the Current Working Directory of the software versus being placed in the Application Directory. In my post I described the scenario in which almost every program is vulnerable to DLL Search Order Hijacking when a DLL can be written to the directory that contains the EXE of the program. The directory containing the EXE is always the very first location in the DLL search order (except for KnownDlls) so the problem is quite wide-spread. This technique makes a great persistence mechanism for malware but is a poor way to attempt to get initial code execution on a system.
The problem currently making headlines comes down to the fact that when most programs recursively enumerate files, they do so by setting the current working directory to each directory they find before examining the files found in that directory. By setting the current working directory to a location, you expose DLLs found in that directory to be a part of the DLL search order and in some cases they will be loaded. The current working directory is fifth in the DLL search order with SafeDllSearchMode enabled (the default on most systems these days) and second in the search order otherwise. Strictly speaking, with a position farther down the chain of DLL search order it is more difficult to exploit this than if one has access to the application directory itself. The reason for all the attention this has received is that many applications will traverse files across a network share, allowing remote infection by applications that both set current working directory for file traversals and have a mechanism where a DLL can be caused to load based on the file type or contents. The now famous example of this is the iTunes example from the advisory where iTunes sets the current working directory to the directory of files it is scanning, then loads a DLL under some circumstances based on the content of the files it finds. With current working directory potentially set to a network share containing a batch of music files, a specifically named rouge DLL could be loaded by the iTunes application. This technique is a great way to get initial code execution on a system but makes a poor malware persistence mechanism.
Many security vendors have been discussing solutions to the problem lately. Many recommend loading DLLs by explicit paths, which is a valid approach. Others have been pressing Microsoft to alter the behavior of DLL loading within operating system, which creates a nightmare of backward compatibility problems.
If setting the current working directory during file traversal leads to potential vulnerabilities in some applications, the logical question to ask is do applications really need to set current working directory to traverse files? The answer is no. Setting current working directory leads to slightly simpler recursive code which is why it was chosen in the first place. All API documentation on the topic of traversing files in a Win32 environment use this approach, including Microsoft’s MSDN documentation as well as the two Win32 System programming books on my bookshelf “Windows via C++” and “Windows System Programming”.
When a programmer sets out to write code to traverse files they will typically not reinvent the wheel and will most likely use reference code found on the internet or in a book. This is not a knock on the programmers who use reference code, file traversal in Win32 is actually somewhat complicated to understand and implement correctly, especially for the novice programmer. Reference code leading to vulnerabilities is nothing new. For example, open any book on making web database front-ends and you’ll probably be writing code that is profoundly vulnerable to SQL injection.
Traversing files without setting current working directory involves building full path strings recursively. The reason this code was mostly likely not chosen to be the reference implementation of file traversal is that it requires string manipulation, which can be error-prone and insecure if done improperly, and requires slightly more code. Let’s examine the pseudo-code for each approach.
Recurse(path)
{
If path is a file
{
process_file(path)
}
Else if path is a directory
{
Save current directory path with GetCurrentDirectory()
SetCurrentDirectory(path)
Loop over all directory entries with FindFirstFile(“*.*”) and FindNextFile()
{
Recurse(directory entry)
}
SetCurrentDirectory(saved current directory)
}
}
In the code above there isn’t any string concatenation taking place. Each time we recurse down a directory we saved our current directory, changed the directory before recursing, then restored the current directory when the recursive branch finished. The vulnerability lies in what specifically happens when your application does something like process_file() above. If process_file() for your application could potentially result in a DLL loading, then the current working directory is set to the directory of the file you are processing. Thus the operating system will include this directory in its list of places to look for the DLL. Let’s examine a different high level pseudo-code that won’t leave us vulnerable to this attack.
Recurse(path)
{
If path is a file
{
Process_file(path)
}
Else if path is a directory
{
Concatenate the path with the wildcard “*”
Loop over all directory entries with FindFirstFile(path with wildcard) and FindNextFile()
{
Concatenate the path with the directory entry name
Recurse(new directory entry path)
}
}
}
Pseudo code is great for seeing the big picture but the problem, as I have stated, is that the skeleton code people grab from reputable documentation sources which uses the technique that isn’t appropriate for their application. I have written a skeleton file traversal program which uses the string concatenation technique as shown here. I’ve included the same skeleton program that uses the current working directory approach in case any researcher is curious to compare. Both the vulnerable and non-vulnerable skeleton file traversal code can be downloaded here: filetraverse_skeleton_code
Tags: hijacks, malware, secure coding
Find Evil and Solve Crime, Part 1: Focus
Written by Jason Luttgens
This is part one of a series of posts I plan to make on what Mandiant does to “Find Evil and Solve Crime“. These posts should help to make your organization better, faster and stronger at performing effective computer security incident investigations. And hopefully they will spark some good discussion about improving incident response. The first part is about focus.
Focus
One of the biggest challenges during an investigation is staying focused. It is all too easy to chase shiny objects, and sometimes even not-so-shiny objects, and never figure anything out. So in this part, I’ll talk about what Mandiant does to help prevent an investigation from falling off track.
According to the Carnegie Mellon Software Engineering Institute:
“When an incident occurs, the goal of the CSIRT is to control and minimize any damage, preserve evidence, provide quick and efficient recovery, prevent similar future events, and gain insight into threats against the organization.”
I think that statement does a great job summing up what the incident response process is all about, and what Mandiant commonly focuses on. But I have something to add. Mandiant pays special attention to specific high-level questions that need to be answered.
Questions
Based on discussions with our customer, we form high-level questions early on in the investigation. These questions define what topics will be in the executive summary of our final report. They also provide guidance for all investigative activities – the team should only perform tasks that contribute to answering those questions.
During an investigation, I consider myself a fact-finder looking for facts to answer those questions. I establish and search for facts that describe the incident. So it’s very important to start the investigation on solid ground. We start by discussing the incident, in technical detail, with our customer. We directly verify and examine all initial facts about the incident by acquiring the data that shows the facts – forensic images, firewall logs, etc. Once we know we’re on solid ground, we start to fan out – thinking of ways to look for evidence associated with our initial facts.
As we proceed, leads can take us down many different paths, some that help and some that hurt. To stay focused here, we take an old school approach: Who, What, When, Where, Why and How. Staying focused on answering these questions will help us Find Evil, and eventually Solve Crime.
Context
One very important aspect that will help is to develop a clear picture of the context of the incident and evaluating every new investigative action against it. This will help keep the team focused and efficient. Here are examples scenarios Mandiant has seen challenge an IR team’s ability to stay focused:
Problem: The team is not keeping a list of affected systems, malware found, indicators of compromise or dates and times of significant events. Also, no one is keeping a list of evidence gathered, outstanding tasks or responsible persons. Each day, team members are thinking someone else is working on a critical task but things are slipping through the cracks.
Solution: Assign a single team member to maintain a Web page, document or spreadsheet with all that information.
Problem: Team members are spending a lot of time analyzing data. Forensic images are scrutinized in painful detail. Lead generation is slow.
Solution: Before a team member begins analysis on any type of data, provide them with the following:
- Lead information (i.e., what do we already know)
- A list of questions you want answered
- A report template
- Discuss the elapsed time expected to complete the analysis
- Request the analyst inform you as soon as he or she thinks they are not on track with expectations
Problem: An investigation clearly identifies malware associated with the incident on a computer. While performing detailed analysis, additional malware is identified on the system. The team extracts the malware, performs analysis, and begins searching for indicators of that malware on other systems. They find the malware is on additional systems and begin investigations of those. Unfortunately, the malware was unrelated to the incident at hand, and the team wastes days of work.
Solution: A quick review of the context of the finding – as simple as checking the date the malware was created.
Problem: The team provides IP addresses and domain names to the proxy administrator to search for. While searching for those indicators, the administrator begins to look at the logs more closely than they ever have before. The administrator discovers entries that seem suspicious. They are reported to the team. The team begins to investigate these entries – responding to the computers responsible for the traffic. The team finds no correlation between these systems and the systems involved with the incident at hand.
Solution: A quick sanity check on the reported entries – are they similar to other known activity? Are they within the time frame of known activity?
Summary
Mandiant has found that the biggest challenge to most investigations is in how they are managed. We’ve found that sticking to the basics – documentation and communication – go a long way to help us stay focused to Find Evil and Solve Crime.
Stay tuned to M-unition for my next post, where I’ll discuss collecting and analyzing data that’s useful on an IR. I’ll talk about some challenges and provide suggestions to help.
Tags: incident response, investigation
Reversing Malware Command and Control: From Sockets to COM
Written by Nick Harbour
On a Windows host there is more than one way for a program to communicate across the internet. When reverse engineering a piece of malware it is of critical importance to understand what API is being used and how it works so that you may gain an understanding of the data sent and received as well as command structure and internal protocol if applicable. The choice of networking API also effects how you craft your indicators (more on this later). I break Windows Malware Command and Control communications into four API categories: Sockets, WinInet, URLMon and COM. The primary focus of this article is COM, since it is the rarest, least understood and most difficult to reverse engineer.
Sockets
The first group, sockets, is the most widely known as it is the same basic networking API found on Unix. It provides a somewhat raw session level access to a TCP or UDP session. It is provided primarily by the DLL ws2_32.dll, though it has a storied history. Any application using the socket API must manually craft any higher level protocol such as HTTP. A socket object is created with a call to the function socket(). It is during this call where the protocol is specified, TCP or UDP. For a TCP client like most malware backdoors, the function connect() must be called, which performs the TCP three-way handshake and paves the way for reading and writing of data. A server program on the other hand will typically call bind() and listen() to wait for connections (although bind() can also be used client side to force a socket to a specific egress port). The functions send() and recv() are frequently used to transfer data across the wire for TCP connections and sendto() and recvfrom() are traditionally used for UDP connections. From a malware analysis perspective this makes things simple, if I need to understand what information a piece of malware is expecting in response to its beacon packet I can typically look for calls to the recv() function and see how the code that follows inspects the data it reads from the wire. On Windows though, sockets can be used interchangeably with most operations as if they were a file handle. For example, a process (like cmd.exe) could be spawned with a network socket specified as its standard input and standard output and that process would automatically communicate across the network. To learn the socket API in-depth I recommend reading the late W. Richard Stevens’ classic book UNIX Network Programming Volume 1. The drawback to using the Socket API is that interacting with any higher level protocol such as HTTP must be done so manually. This allows a lot of flexibility in how the malware crafts its requests but everything must be laid out explicitly. Malware authors will frequently introduce subtle nuance differences between the way their HTTP traffic looks on the wire and the way most web browsers look. These small differences make great network signatures!
WinInet
The WinInet API requires much less work than the socket API. It is a convenience API which simplifies the interaction to higher level protocols such as HTTP, FTP and even GOPHER! To begin using the WinInet API to talk to a remote host you first need to call InternetOpen() followed by InternetConnect() or InternetOpenURL(). Once the internet has been opened and a connection established, to perform and HTTP request you can call the functions HttpOpenRequest() to make a request handle and HttpSendRequest() to send the request. InternetReadFile() may then be called to read any response from the server. It can also be used to read data from an FTP session. The InternetWriteFile() function can also be used generically in place of any protocol specific function where data needs to be sent across the wire. The HTTP functions provide the programmer the ability to configure most of the options one would expect in an HTTP request header such as the User-Agent string. Not all of these values have to be specified though, and the system default will be used if none is specified. The malware programmer doesn’t have as much flexibility to introduce subtle anomalies in the request structures though like they can with sockets, and left with default settings the malware’s HTTP requests will look virtually identical to legitimate Internet Explorer traffic on the network.
URLMon
The URL Monikers API provided by the DLL urlmon.dll provides yet another API for performing internet communications. In the back end it uses COM but I choose to list this as a separate category from the later discussion of COM because using this API is an abstraction away from the ugly, obscure-t0-reverse methods of direct COM interaction. The most popular function in the URLMon arsenal, from a malware perspective, is the one-punch knockout function URLDownloadToFile(). Rarely in the Win32 API does one function do so much work. You provide this function a URL (for any protocol IE understands), a filename and it uses COM to force Internet Explorer to download the resource to the specified filename. This is very popular with dropper malware which simply needs to download an EXE from a website and launch it. You might also run into the URLDownloadToCacheFile() function which will download a specified URL to the browser cache and return the name of the file it downloaded to. URLOpenStream() and URLOpenPullStream() can be used to download a URL to a buffer in memory, but these functions are rarely used in malware.
Controlling Internet Explorer with COM
Using COM for malware command and control has a number of advantages for the malware author. From a live response/volatile data/memory analysis perspective it obscures the source of malicious traffic because all communication with the remote host will be performed within an iexplore.exe process instead of the malware process. From a reverse engineering perspective it makes things complicated because it is not immediately clear that the malware is doing network communications at all when first inspected with static analysis. COM has fallen out of fashion with many of today’s programmers and is less understood than many other technologies used in modern software. Malware analysts may be particularly unfamiliar with the inner workings of COM, depending on the programming background in the Win32 world.
Before any COM object can be instantiated, the function CoInitialize() must be called to initialize the COM library. Once this is successfully initialized a call can be made to CoCreateInstance() to create an instance of a particular COM object, such as Internet Explorer. In order to understand which object is being instantiated at this point you must inspect the first argument to the CoCreateInstance() function, which will be a CLSID value which is a unique identifier for a COM object. Here is the call to CoCreateInstance() found in a malware sample which used COM:
At first glance it’s difficult to tell what object this function is instantiating because IDA simply shows you the data type of the first value instead of any type of meaningful interpretation of it. The first argument in this example code is a global variable (a constant actually) that exists at some location in the binary that has been given the label “rclsid” by IDA Pro. If you double click on this first argument IDA Pro will take you to view the variable as it would look in memory:
This CLSID value is recognized as a data structure by IDA and is shown here broken into its components. The Human-readable way to represent this CLSID value is “{0002DF01-0000-0000-C000-000000000046}”. It would be nice if there were an IDA script to automatically name these values, but in the mean time you can look them up manually in the registry. By opening regedit and browsing to the key HKEY_CLASSES_ROOT\CLSID you can see a rather long list of subkeys, each named with a CLSID value. By finding the subkey name which matches the hexadecimal values you see in IDA Pro you can identify what the object name is that the program is requesting, which is stored in the default value of the key. Here is a screen shot of regedit showing the key for the CLSID shown in the example code above:
So it appears that our malware sample is making an instance of the Internet Explorer object! In order to use any functionality from this object the malware must make use of the last argument to the CoCreateInstance() function (which was labeled “ppv”). This parameter is a pointer to pointer to receive a newly allocated data structure containing all the pertinent data for this object, most notably function pointers. The list of functions available is documented here: http://msdn.microsoft.com/en-us/library/bb159694.aspx. To see the Internet Explorer object in action from a source code level please take a look at this article: http://support.microsoft.com/kb/167658.
The most important function call to this COM object we need to recognize as reverse engineers is the call to the function Navigate() or Navigate2(). This is what actually accomplishes the HTTP request which may also contain POST data or a parametrized GET, and thus transmit data to the remote command and control server. The following screen fragment shows the call to the Navigate() method of the IE COM object as seen from IDA Pro:
In this fragment we see the ppv value being accessed, which is what was populated from the call to CoCreateInstance(). A function is being called from within this data structure. This function is at offset 2Ch from the beginning of the ppv data structure, and you can tell that the binary is calling this function because the call instruction accesses this specific offset from the beginning of the structure (“call dword ptr [ecx+2Ch]“). There is no clear-cut way to go directly from the Microsoft documentation of this COM interface to seeing the actually internal offset used by each member function, so I made a small test application to simply reference each function. I then disassembled my test application and could see the clear mapping of offsets to member functions. The following table is a mapping of the commonly used member functions (by malware specifically) and their associated offsets as seen in a call instruction:
Final Thoughts
My goal with this article was to make more malware analysts and incident responders aware of the spectrum of communication techniques available to malware authors and to make analysts recognize and be able to begin reverse engineering the COM technique specifically. There is certainly a need for more tools and techniques in this area but it all begins with awareness and understanding. One thing to take away from this is that as a malware analyst it is not enough to simply know assembly language. You must gain a working knowledge of the APIs and you must be rigorous, if not downright tenacious, in your appetite to learn new facets of the APIs as you encounter them. If a malware analyst disregards calls such as CoCreateInstance() without deeper inspection due to their lack of understanding of it, they potentially will miss a critically important component of the malware’s operation.

The Challenges to Remediating from the APT
Written by Christopher Glyer
MANDIANT has been involved in numerous widespread remediation efforts following intrusions at large organizations. We have seen nearly identical recurring challenges emerge at these large organizations, and we believe conveying these challenges may be important to developing your overall approach to remediation should you be compromised by advanced and persistent threats:
- Remedial efforts usually take more effort and determination than anticipated. It is a good principle to begin managing the expectations of the business units as soon as possible, ensuring they are aware that the remedial efforts may involve continual effort, resources, and periodic adjustments based on the dynamics of the ongoing threat.
- Good remediation plans often fail because determination wanes if each phase of the plan is not short and concise.
- An ineffective remediation is initiated because the plan was implemented prior to understanding the tools and techniques of the intruder.
- An ineffective remediation plan was initiated because the remediation plan took too long to develop, allowing the compromise to become so widespread that remedial efforts become very time consuming and costly.
- The remediation plan fails because accountability for its execution is not clearly assigned to an individual. Each business unit should assign an individual who becomes responsible for the implementation of the plan.
- Remediation fails due to lack of resources – lacking the personnel, technology and processes to follow through on the remediation plan.
- Remediation fails because the organization tipped off the attacker. In past investigations the following actions have tipped of the attacker:
- Removing compromised systems as you discover them
- Changing one-off domain admin passwords when you see them used
- Blocking Command and Control (C2) channels as they are identified
- Remediation fails because the organization does not or cannot disconnect from the Internet while undertaking remediation activities.
In order to develop and execute an effective remediation plan, not only must you understand these points, but you must also execute your remediation at the right time. Remediating too early does not help your organization defend your networks, and remediating too late ensures you have lost all your trade secrets to the adversary. Therefore, below are some key criteria for you to use in order to assess your remediation “timeliness”:
You are remediating early, and entertain higher risk of re-compromise or not fully remediating the current compromise when:
- Host-based indicators of the current compromise (the attacker’s fingerprints) are unknown
- Network-based indicators are unknown or transaction based
- New compromised hosts are still being detected at a high rate (more than one per day)
- There seems to be no established pattern to assist your organization in anticipating the next compromised host
- There is little coordination between business lines (Staff) concerning remediation
You are potentially remediating too late when:
- Host-based indicators are becoming less reliable (they are not hitting on anything)
- Network-based indicators are becoming less reliable
- You know the attacker has been active and they just “vanish”
- Staff motivation and concern has waned
- Remedial activities have evolved from corporate-wide efforts to independent “splinter cells”
You are in the strike zone and remediating at the right time when:
- Host-based indicators are stable
- Network-based indicators are stable
- The delta to detect new compromised hosts is shrinking consistently
- Your organization is postured to actively identify and address the “next generation” of attacks – In many of our investigations we see the attacker, or a different attack group, return. We have seen it take 3 days, 3 weeks, or even 3 months – but inevitably they try and come back. Your organization has information that is deemed valuable and the attackers won’t just “go away” when you kick them out).
- There is active communication and coordination between business lines (Staff) concerning remediation
Once you understand when to time the execution of your remediation plan, you should execute it. MANDIANT will be posting numerous blogs throughout the next several weeks to provide the technical details behind many of the longer term remediation strategies that cannot be implemented prior to eradicating the current incident.
Stuxnet Memory Analysis and IOC creation
Written by Peter Silberman
The stuxnet malware has been making the press recently for two reasons. First it contains two drivers signed with a legitimate (at the time) cert. Second is it’s targeting SCADA systems. The malware is cool for a host of other geeky reasons. Nick Harbour, Stephen Davis, and I started looking at the malware Sunday afternoon. We had hoped to write a blog post about the specifics of the malware before we left for Vegas on Friday. However, in the short term I thought this malware would provide a great opportunity to demonstrate how memory analysis can be leveraged to find malware easily, and how the MANDIANT’s Indicator of Compromise editor (IOCe) tool can be used to describe the malware and what to look for.
The goal of every good IOC is to leverage the intelligence we have about the malware to find it effectively, while allowing for changes/ variants, and weeding out false positives. We can describe most aspects of malware using the IOC language, for this exercise we will focus our energy on writing a good memory IOC. In memory, malware appears rather naked and this is a prime example of that. When loaded, stuxnet spawns lsass.exe in a suspended state. The malware then maps in its own executable section and fixes up the CONTEXT to point to the newly mapped in section. This is a common task performed by malware and allows the malware to execute under the pretense of a known and trusted process. The first indicator in memory is the path it uses to spawn lsass.exe:
Notice that the path to lsass.exe has extra backslashes so when the backslashes are resolved by CreateProcessW the path is c:\windows\\system32\\lsass.exe instead of c:\windows\system32\lsass.exe. This is seen in the following screen shot taken from Audit Viewer:
Notice the arguments in each process. The process with a score of 100 is the original lsass spawned by the system. The process with a score of negative 145 is the lsass spawned by the malware. The arguments are very distinctive and a great indication that something is wrong. This is a fine IOC for this specific variant but fixing this and rendering the IOC useless is a trivial task for this malware author. So let’s keep building out the IOC.
If we examine the lsass process further we see another indicator that something is wrong.
Above is a complete DLL listing of the malicious lsass. Who can spot what is missing? If you noticed the lsass.exe itself is missing you are correct. The original lsass has about three times the number of DLL’s and also includes lsass.exe in the listing:
The listing continues but notice lsass.exe at the top. The lack of a binary and DLLs in the malicious lsass listing reconfirms what we already knew. That the malware used a process suspend and unmap technique. When the attacker unmaps the lsass.exe section, the lsass.exe is removed the VAD tree and subsequently doesn’t show up when doing a DLL listing based on VADs. Spotting suspend and unmap via taskmgr or other live response tools would be very difficult. In this case the malware author took extra care and created the process with the correct privileges allowing the attacker to mimic the correct lsass.exe user.
The next addition to the IOC is the digital signature itself. The drivers were signed and verified:
<DigitalSignature>
<SignatureExists>true</SignatureExists>
<SignatureVerified>true</SignatureVerified>
<Description>The file is signed and the signature was verified.</Description>
<CertificateSubject>Realtek Semiconductor Corp</CertificateSubject>
<CertificateIssuer>VeriSign Class 3 Code Signing 2004 CA</CertificateIssuer>
</DigitalSignature>
We can use the fact that this certificate has now been revoked and add this to our IOC. This again is not a great variant resistant IOC because the attacker can sign their driver with a new cert, if they have one, or have an unsigned driver. In either case those changes will render this IOC useless. We will still add it to our existing IOC knowledge base.
The next behavior to create an IOC for is the injection component. Stuxnet injects at least one binary into svchost, lsass, services and we see references for the potential to infect winlogon as well. Stuxnet is actually injecting a full binary not just shellcode into these processes.
When we examine the inject sections we see the binaries import three dlls:
The most abstract way to write an IOC for this is to say any process that has an injected binary that imports ADVAPI32.dll or KERNEL32.dll or USER32.dll flag as part of the stuxnet malware family. There is a chance we could end up flagging other things as part of stuxnet but adding imports makes the IOC a little too strict. This is a much better signature the previous two. It allows for some modification and requires the author to actually make more than one line code changes in their malware to force us to miss it. Now it’s still feasible that the malware could be modified and we could miss it with the current three IOC’s we have so let’s continue building our IOC. The final thing to create an IOC for is the rootkit component. The rootkit component is designed to hide the presence of the malware and LNK file on the filesystem. To do this they use an old standard technique that AV and rootkits have been using for years. The rootkit layers itself on filesystem devices, if you are running on VMWare it will layers itself on the VMWare filesystem driver. If we create an IOC describing the driver layering we can make it very hard to defeat detection. The IOC we create states that any driver that layers itself on sr.sys, fs_rec.sys, and fastfat.sys will be flagged. There is definitely a chance for false positive but it should be a small set of hosts and you can add parameters to exclude the false positives if need be. This IOC could be expanded if you are running truecrypt or other filesystem software the IOC might need to be updated or modified to include or exclude certain drivers. IOC’s can and should be tailored for the environment where necessary. The final memory IOC looks like this:
Lets translate this IOC into english. If a process with an argument that contains \\system32\\lsass.exe OR a driver exists that has a certificate subject that contains Realtek Semiconductor Corp flag it as stuxnet. OR a driver exists that has attached to the following fs_rec.sys AND sr.sys AND fastfat.sys flag the driver as part of stuxnet. OR a process has an injected section AND the injected section imports any of the following DLLs advapi32.dll OR kernel32.dll OR user32.dll. This is a pretty solid IOC for malware in memory as we do more work on the malware we may find more nuisances we can add to it, this is a good start.
Our focus here was to describe the malware in memory using an IOC. But when we write IOCs for the field or customers we take everything into account including disk, registry, filesystem, eventlog, etc. A more complete IOC for this malware looks like:
This IOC reads the following way if the file has a section named .stub OR a file exists named mdmcpq3.pnf OR a file exists named mdmeric3.pnf OR a file exists named oem6c.pnf OR a file exists named oem7a.pnf OR all of the following drivers are attached to by one drivers fs_rec.sys, sr.sys, fastfat.sys OR a process has an injected section AND it imports any of the following DLLs advapi32.dll, kernel32.dll, user32.dll OR a file exists named mrxcls.sys and it has a certificate subject of Realtek Semiconductor Corp OR a file exists and it has a name of mrxnet.sys and it has a certificate subject of Realtek Semiconductor Corp OR a registry key path exists of HKEY_LOCAL_MACHINE\SYSYTEM\ControlSet001\Services\MRxCLs\ImagePath AND has a value of mrxcls.sys OR a registry key path exists of HKEY_LOCAL_MACHINE\SYSYTEM\ControlSet001\Services\MRxNet\ImagePath AND has a value of mrxnet.sys.
Nick Harbour, Stephen Davis, Jamie Butler, Kris Harms and I will all be at Blackhat this year teaching classes ranging from Malware Analysis Crash Course, Advanced Malware Analysis, Advanced Memory Analysis in Incident Response, and Incident Response. Even if you don’t take a class, join us for the MANDIANT pre-game party from 7-9 on Wednesday before going out for the night!
Tags: IOC, IOCe, malware analysis, Memory analysis, Stuxnet
Malware Persistence without the Windows Registry
Written by Nick Harbour
For an attacker to maintain a foothold inside your network they will typically install a piece of backdoor malware on at least one of your systems. The malware needs to be installed persistently, meaning that it will remain active in the event of a reboot. Most persistence techniques on a Microsoft Windows platform involve the use of the Registry. Notable exceptions include the Startup Folder and trojanizing system binaries. Examining malware persistence locations in the Windows Registry and startup locations is a common technique employed by forensic investigators to identify malware on a host. Each persistence technique commonly seen today leaves a forensic footprint which can be easily collected using most forensic software on the market.
The persistence technique I’ll describe here is special in that it doesn’t leave an easy forensic trail behind. A malware DLL can be made persistent on a Windows host by simply residing in a specific directory with a specific name, with no trace evidence in the registry or startup folder and no modified system binaries. There isn’t just one directory location and DLL filename that are candidate locations for this persistence mechanism but rather a whole class of candidate locations exist for any given system. On my laptop (Windows 7 64-bit) there are no less than 1032 such path and DLL name combinations where a DLL could be placed such that it would automatically be loaded at some point during my normal boot-up, and that’s just for a 32-bit DLL! If you had a 64-bit malware DLL the number would be much higher as I have many more 64-bit processes running at boot time. So how does this work?
DLL Search Order Hijacking
When an application requests to load a DLL either statically via an import table in its executable file, or dynamically via the LoadLibrary() function the operating system will look for the DLL in a predefined sequence of locations. This sequence is defined in the MSDN documentation here: http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx. The most important tidbit of information to take away from that document is that the first place the application looks for a DLL is the location of the executable itself. This isn’t always the case though. If the DLL name that is requested is listed in the “\\.\KnownDlls” object then it will always load from a fixed location (the System32 folder). This object is populated at boot-time using data from the Registry at the following location:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\KnownDLLs
Microsoft employee Larry Osterman describes this in a blog post (http://blogs.msdn.com/b/larryosterman/archive/2004/07/19/187752.aspx). He states in the post that the KnownDlls object will be larger in memory than what is in the Registry key and will be built recursively from the statically imported DLLs from any DLL listed in the registry. In the limited testing I’ve done on Windows XP and Windows 7 systems, the KnownDlls object in memory is identical to the list provided by the KnownDLLs registry key.
Casual browsing of the KnownDlls key will reveal a short list of about 30-35 of the most commonly used DLLs. For example, the low level networking API DLL “ws2_32.dll” is contained in this list. Whenever any application attempts to load a DLL named “ws2_32.dll” it will always load it from the System32 folder because it is listed in this key, regardless of where the application was launched from. The KnownDlls system provides a thin layer of security for this small set of crticial DLLs because an attacker can’t simply place a DLL named “ws2_32.dll” inside a folder containing an application which uses ws2_32.dll and expect their local copy to be loaded. The KnownDlls system is far too limited to provide any realistic sense of DLL loading security though. For example, even though we can guarantee that the copy of ws2_32.dll that will be loaded will always be the one from system32, other components loaded when ws2_32.dll is loaded (such as iphlpapi.dll and mswsock.dll) are not guaranteed because they are not covered by KnownDlls.
Lets imagine that we had a legitimate program called update.exe which ran from the location “C:\Program Files\MyCompany” and loaded ws2_32.dll, all we would have to do to make update.exe load our malware DLL is place our malware in the “C:\Program Files\MyCompany” directory and give it the name “iphlpapi.dll”. When the update.exe program runs it loads ws2_32.dll, which in turn loads iphlpapi.dll which it loads from the application directory first before checking the System32 folder where it legitimately resides. All the malware author needs to do is make sure their malicious iphlpapi.dll eventually loads the real thing and the user of the system (and a forensic analyst most likely) will have no idea that malware has been loaded.
Real-World Usage
You might have come to the conclusion in reading the description of the problem above that executables which reside in the System32 folder are not susceptible. If you thought that, you’d be correct. If you also thought that there is no real practical problem because all consistent and reliably placed startup binaries exist in the System32 folder, you’d be incorrect. Case-in-point: Explorer.exe . Strangely, this binary resides in C:\Windows (I assume for historic reasons). So when explorer.exe launches and it requests a DLL that is not protected by KnownDlls, the first place the system looks to find the DLL is the C:\Windows directory. Thus far, the most common place we’ve found this malware persistence technique being used is in the location and name “C:\Windows\ntshrui.dll”. The real ntshrui.dll is located in the System32 folder but since this dll is loaded by Explorer.exe and not protected by KnownDlls, it’s unfortunately susceptible to DLL search order hijacking.
The Extent of the Problem
Once you really understand the nature of the problem it may occur to you that it’s a very widespread and pervasive issue. It has always existed in Windows and will likely exist for the foreseeable future. To alter the DLL search path mechanism could have severe backward-compatibility problems for Windows and is most likely not going to happen due to the high value they have always placed in compatibility (We love you Raymond Chen!). I’ve written a program to identify all locations and filenames that a DLL could be placed to achieve persistence on a given system. The idea is that you can run this program on a clean (Gold Image) system and forensically search for any DLL name listed in the output on a machine you suspect of being compromised with this method of persistence. Similar programs may be developed to attempt to identify hijacked DLLs on a live system. I chose to write this program first however because its output helps to explain the extent of the problem. I ran the program on my laptop and it produced output which contained 1032 lines, each describing a location and filename that a DLL could be placed to be loaded at boot-time by my system. On a clean XP SP2 machine I get 91 locations listed. Here are a few lines from the output from my laptop:
Hijackable Location: C:\Program Files (x86)\iTunes\SspiCli.dll
Hijackable Location: C:\Program Files (x86)\iTunes\CRYPTBASE.dll
Hijackable Location: C:\Program Files (x86)\iTunes\CoreFoundation.dll
Hijackable Location: C:\Program Files (x86)\iTunes\MSVCR80.dll
According to this output, some program that loads when my system boots (most likely iTunes) attempts to load the DLL named “CRYPTBASE.DLL” which is commonly found in the System32 folder but an attacker could place a malicious DLL in the iTunes folder and that would be loaded instead. The program examines running processes and determines hijackable DLL locations by the following properties (applied to each loaded dll in every running process in the system):
- The process executable that loaded the DLL is not located in the System32 folder
- The DLL name is not found in the KnownDlls object
- The DLL is not found in the same directory as the executable
Any loaded DLL that contains all three properties is susceptible to being trumped by search order hijacking.
The tool (compiled and source) to identify possibly malicious 32-bit DLL locations from a clean system can be found here.
Tags: KnownDLLs, malware, persistence














