
DLL Hijacking Just Won’t Die - ingve
http://textslashplain.com/2015/12/18/dll-hijacking-just-wont-die/
======
userbinator
I've used this behaviour --- non-maliciously --- multiple times in the past to
override APIs for logging/tracing/debugging purposes. For example, I have a
set of DLLs[1] that you can put in the same directory as the .exe of an
application and it will log all network traffic that it generates. Very useful
and convenient compared to the alternatives. Another use is to workaround
compatibility problems.

What I find more saddening is the trend to view _any_ behaviour that could
potentially be exploited as a vulnerability, regardless of how useful it could
be, which just leads to locked-down user-hostile systems where nothing is
possible without going through some sort of ridiculously bureaucratic excess
of process.

Thus, I think the root cause of this problem is not with the DLL loading
behaviour, but with this...

 _The bad guy just navigates a frame of your browser to the DLL of his choice
and, if you’re on Chrome or Microsoft Edge, the DLL is dropped in the
Downloads folder without even asking_

...entirely unconsented file download. The design of putting all downloads in
one place is a small contributing factor.

[1]
[http://www.netresec.com/?page=Blog&month=2011-01&post=Proxoc...](http://www.netresec.com/?page=Blog&month=2011-01&post=Proxocket
---A-Winsock-Proxy-Sniffer)

Edit: we can also exploit this behaviour benevolently by putting a set of DLLs
in the Downloads folder that would be loaded by any installers being run from
there, which could do things like sandboxing/install logging. (Presumably
browsers would be not so brash as to overwrite an existing file of the same
name in there!?) It's not so bad after all...

~~~
dietrichepp
> What I find more saddening is the trend to view any behaviour that could
> potentially be exploited as a vulnerability, regardless of how useful it
> could be, which just leads to locked-down user-hostile systems where nothing
> is possible without going through some sort of ridiculously bureaucratic
> excess of process.

I'm going to take a viewpoint counter to this. One of the things that
constantly frustrates me on my desktop computer is my inability to run
untrusted third-party code outside my browser. The desktop was simply not
built to do that, and I wish it was. I'm currently judging games made for the
34th Ludum Dare game jam, and the way I do it safely is by creating a
completely separate user account in Windows, and playing the games there. This
is inconvenient. I'm not going to play the games under my normal account,
because I simply don't trust the code, but Windows gives me no other option. I
know my paranoia puts me in the minority, because after the jam is over, I
uninstall Java and Flash and the other "high-risk" pieces of software, and I'm
pretty sure most other people don't do that.

On the other hand, the recent SIP lockdown on OS X and the way it's affected
dtrace is not something to be ignored either. But given the choice, I'd rather
have a dozen dialogs ask permission rather than one piece of malware slip by
uncontested.

Phones may be a nightmare in terms of hackability, but at least I can download
a random application without worrying about whether it's CryptoLocker in
disguise or something like that.

~~~
hayksaakian
Dozens of dialogs lead to "dialog blindess" where users blindly accept dialogs
to get their thing to work.

I think sudo works because it requires _some_ expertise to use a terminal,
even though it's conceptually the same as a windows UAS dialog for example.

~~~
dietrichepp
Right, but I was responding to the viewpoint that not all exploitable holes
should be closed. At least with dialogs, a user has the possibility to make an
informed choice. With "vulnerable by default", you don't get to make a choice
at all.

------
zyxley
This trick is used by a number of game mods, by way of providing a fake
DirectX dll that monkeys with the internal game code and then calls the actual
DirectX library.

ENBoost is probably the most prominent at the moment, and is considered nigh
mandatory by modders for Skyrim, the Fallout series, etc, because it lets you
override the game engine and use free RAM (beyond the game engine's 2GB or 4GB
limit) as an extended cache for your video card.

~~~
claudius
But this should also be possible without the game executable looking up DLLs
in its CWD? A mechanism analogous to LD_PRELOAD_PATH on Linux should work
equally well or the mod could provide its own binary, load its dll and then
run the main game binary?

In other words, I don’t understand why “load DLLs from CWD” is vital to the
workings of such mods?

~~~
SolarNet
Well it's easier to explain to users of the mod at least (dropping files in a
folder). Also replacing the binary is problematic because that will cause
updating and DRM problems.

~~~
lawl
With an LD_LIBRARY_PATH they'd have to drop 2 files into the folder, the dll
and a wrapper that sets the library path, I don't see the issue...

~~~
SolarNet
Yes of course. But then the users have to run the game with the wrapper file.
Not a large inconvenience though. The Linux system _is_ better.

------
kelnos
Really bad consequence of the current/same directory being in the library
search path. It's similar to why, on Linux/Unix, it's bad practice to include
"." in your PATH (or LD_LIBRARY_PATH). I know including same-directory
libraries can make things more convenient, but it should be something that an
app explicitly needs to want and enable, not something that just happens.

~~~
sltkr
> It's similar to why, on Linux/Unix, it's bad practice to include "." in your
> PATH (or LD_LIBRARY_PATH).

An even trickier problem on Linux is that an empty component in the
LD_LIBRARY_PATH is interpreted as a reference to the cwd. Many tools come with
launcher scripts that do something like:

    
    
        export LD_LIBRARY_PATH=/usr/local/lib/my-app-1.0:${LD_LIBRARY_PATH}
        /usr/local/bin/my-app-1.0
    

... and bam, now if $LD_LIBRARY_PATH was empty (which it usually is) you've
unintentionally added the cwd to it. This problem is fairly common in
practice.

FWIW, the correct way to set the variable is:

    
    
        export LD_LIBRARY_PATH=/usr/local/lib/my-app-1.0${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
    

(or make sure the binary has a DT_RUNPATH entry that points to the library
directory, so you don't have to mess around with environmental variables at
all.)

~~~
coldpie
I wonder if changing this behavior would break anything. I can't imagine _too_
much software relies on it.

------
golergka
Typical result of developers overestimating users. If a browser developer sees
that some file suddenly downloaded automatically, he would notice it instantly
and delete it if it's something fishy. But a lot of typical users wouldn't
notice (the kind that never closes download bar in chrome anyway) and would
never clean up their downloads folder. Damn, a lot of them would even run it
to find out what it is.

~~~
marshray
No, I think it has more to do with the way that executables on Windows are
'tagged' as having been downloaded from the internet. When a user opens one of
them (such as an installer) they get a prompt if they want to run this code
from the internet. Generally, this is considered a good thing.

Browsers, in a stroke of unassailable logic, have decided that the existence
of this new security feature should mean they should now start silently
downloading executables from websites. After all, what good does it do to have
_two_ pop-up warnings that users simply click through?

This is just my impression, I could be wrong about all this.

~~~
golergka
> they get a prompt

Yeah. About prompts and real users. In my experience, once user clicks on a
given prompt 5 times, after that he's completely trained to close it
automatically without giving a slightest regard to it.

~~~
diabeetusman
In this case, the user clicking through the prompt isn't the issue. They
wanted to run the non-malicious installer and so they did. If they read and
re-read the prompt, they would still make the same decision

------
cubano
Interesting aside...I downloaded the dll this afternoon just for laughs to see
what the fuss was. Since I didn't want to dig around for an installer that
would trigger the hook, I just left it in my download dir.

Just now, I decided to mess with Steam again after a long hiatus...guess what
popped up when I ran SteamSetup.exe?

------
hyperpape
Can someone explain all the steps here?

I get that:

1) the browser will silently download a DLL to the Downloads folder

2) the installer does _something_ that causes the DLL to run, compromising the
machine.

I get why people don't like (1), but why is (2) actually happening? Are the
DLL hijackers exploiting name collisions, is an API being abused, or something
else? And is there a robust way to prevent this even if browsers persist in
silent downloads?

~~~
jffry
The linked article [1] has an explanation:

    
    
      In simple terms if an application (e.g. Test.exe) loads
      a DLL (e,g. foo.dll) by just the name, Windows follows
      a specific search order depending upon whether
      “SafeDllSearchMode” is enabled or disabled to
      locate the legitimate DLL. 
    

So it looks like the installer is legitimately attempting to load some DLL but
either hasn't fully qualified the name or hasn't enabled this flag

[1]: [http://blog.opensecurityresearch.com/2014/01/unsafe-dll-
load...](http://blog.opensecurityresearch.com/2014/01/unsafe-dll-loading-
vulnerabilities.html)

~~~
wila
I was interested so read the article. Enabling the "SafeDllSearchMode" flag
doesn't help as it is not the current directory from which the DLL is loaded,
but the startup directory from which the installer is run (eg. the Downloads
folder).

The directory from which the application is loaded is still the first
directory from which DLLs are loaded with "SafeDllSearchMode" on. Moving
current directory down in the search order doesn't help.

edit: The Microsoft Security Research center also had a paper on this [1] and
there it lists that "SafeDllSearchMode" also employs a "known DLLs" technique
when this flag has been set.

Now the question is if Microsoft has added this DLL as a known DLL or not. I
don't see it in my registry, but it might be defined elsewhere (or I might
overlook it)

[1] [http://blogs.technet.com/b/srd/archive/2014/05/13/load-
libra...](http://blogs.technet.com/b/srd/archive/2014/05/13/load-library-
safely.aspx)

------
TwoBit
Does anybody know why Chrome and Edge would silently unilaterally download
binary code like that?

~~~
Klathmon
Well it's not silent (at least in chrome). it does show that it is downloaded,
but it doesn't do anything to prevent this.

IMO a good solution is to make the user manually re-confirm that they meant to
download a .dll file on windows to prevent this kind of thing from happening.

~~~
kevingadd
IIRC Chrome will begin downloading an EXE in the background while the prompt
is open, so you don't even lose time to the confirmation window.

------
Pxtl
it seems like the OS should be preventing you from running an executable in
your root Downloads folder, maybe copying it into a Temp dir before executing
it. This could also be used to add security, sandboxing the exe within the
temp dir and prompting you before accessing the larger filesystem.

~~~
13of40
There's actually a Windows feature intended to mitigate this, that was added
sometime around Server 2003, but it's never turned on by default because of
backwards compatibility issues. Look under 'Windows Settings\Security
Settings\Software Restriction Policies' in a GPO to see it.

------
dimdimdim
Here is a fantastic on on Privilege Escalation using DLL Hijacking
[http://www.pentesteracademy.com/video?id=575](http://www.pentesteracademy.com/video?id=575)

Just how malware works today! even saw this in a Mark Russinovich talk.

------
mrerrormessage
The question that needs to be asked here is how to get all installers using
MSI. MSI is a secure, declarative format which runs off MS code in known
directory. Because it's declarative, it can also be queried and tracked. I
recently packaged an installer using it and it worked really well. WiX has
terrific documentation and it was straightforward.

------
chris_wot
Need to set the registry key HKLM\SYSTEM\CurrentControlSet\Control\Session
Manager\CWDIllegalInDllSearch

~~~
pilif
That's not enough - that's just removing the current working directory. But
unfortunately, the issue here is that DLLs are put into the same directory as
the executable to be run.

You can't remove loading DLLs from the same directory as the executable on the
OS level because many applications rely on this feature. This can only be
fixed on a per-executable basis.

------
jimrandomh
Browsers could protect users from this class of vulnerability by making it so
that, if you run a browser-downloaded executable from within the browser, it
first moves it to an empty directory and runs it there.

~~~
marcosdumay
Browsers can't do that. At least not in a general enough way, since it's
Windows that executes the files.

Windows could stop trusting code in folders with some flag. That would be much
more useful.

~~~
cornholio
Such flag already exists: [http://www.howtogeek.com/70012/what-causes-the-
file-download...](http://www.howtogeek.com/70012/what-causes-the-file-
downloaded-from-the-internet-warning-and-how-can-i-easily-remove-it/)

It's a simple fix for Windows to disable local folder DLL loading based on the
Zone.Identifier ADS. There's no usecase where an EXE downloaded from the
internet should load a DLL from it's current folder.

An alternate quick fix for the browser to redirect all DLL/SYS/OCX/Whetever to
a DLLs folder inside the Downloads directory, and keep the EXEs in the main
folder as before, so as not to confuse the users. Downloading DLLs is so rare
that the extra hoop is acceptable.

------
mschuster91
> if you’re on Chrome or Microsoft Edge, the DLL is dropped in the Downloads
> folder without even asking

What fucked up joke is this?!

~~~
striking
I think the bigger joke is that you can hijack DLLs, and the UAC prompt and
signed code verification don't say a word about it.

~~~
winter_blue
It's not Microsoft's or the UAC's fault. It's Nullsoft's fault.

NSIS (Nullsoft Scriptable Install System) loads and executes the DLL without
any verification.

Also, you're not hijacking DLLs -- you're using a DLL to hijack NSIS (which
runs with administrative privileges).

~~~
icebraining
How can NSIS verify the DLL? How can an installer from, say, 2012 know if the
copy of shfolder.dll in Windows 10 is valid?

And worse - in some cases, NSIS wasn't even directly loading the DLLs, Windows
was doing it behind its back (eg. NSIS called a Win32 function called
OleInitialize, which loaded UXTheme.dll by itself).

~~~
Strom
All valid points. I think it should be possible, at least for Microsoft DLLs,
to specify a flag that you are willing to load only those signed by Microsoft.
A malicious version.dll wouldn't probably have a Microsoft signature. The
signature verification would be done by the OS and thus would be future-proof.
Even a OS-local whitelist for exemptions could work, where an admin could add
some unsigned DLL hashes to the list that would still load. None of the
downloaded malicious DLL files would pass this test.

