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_MACHINESystemCurrentControlSetControlSession ManagerKnownDLLs
Microsoft employee Larry Osterman describes this in a blog post ( href="http://blogs.msdn.com/b/larryosterman/archive/2004/07/19/187752.aspx">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 FilesMyCompany" 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 FilesMyCompany" 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:Windowsntshrui.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)iTunesSspiCli.dll
Hijackable Location: C:Program Files (x86)iTunesCRYPTBASE.dll
Hijackable Location: C:Program Files (x86)iTunesCoreFoundation.dll
Hijackable Location: C:Program Files (x86)iTunesMSVCR80.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 href="https://www.fireeye.com/content/dam/legacy/ammo/finddllhijack1.zip">here.