DLL Hijacking Just Won’t Die
textslashplain.com
textslashplain.com
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...
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...
Not having the current directory in PATH / LD_LIBRARY_PATH is a well-known wisdom now to avoid inadvertent interference. I suspect Windows behavior is more like an overlook, designed when environment was less hostile, but now they can't change because of the backward compatibility. It's not a vulnerability per se, but a bad choice in retrospect, imho.
But this type of exploit still existed even under MS-DOS in the form of BBS door hacks. Remote access systems would let you run external programs connected to the serial line. But some would leave the CWD in the download directory after an upload thus allowing you to send a file with the name of an external program then when you activate that program you have a shell.
The solution then still applies today: Don't run external programs without sanitizing your environment. Quarantine all uploads. Don't allow the remote client to control the filename of uploads.
And it's not like Windows doesn't have an executable bit on files. The shell already prompts you for permission to run downloaded programs. Why is it not clearing execute permission by default then adding it when the file is confirmed safe? (I know from experience that a non-executable ACL will prevent a DLL from loading.)
I prefer to have dynamically loaded libraries (dll's) but never shared locations, other than for OS level libraries and runtimes (which are rarely installed by applications). Everything I manage myself I prefer to keep in the application directories. This is also the normal behaviour of application installers on windows.
\app1\app1.exe
\app1\somelib-1.0.dll
\app2\app2.exe
\app2\somelib-1.1.dll
Now it is pretty reasonable that the application searches for dependencies somewhere relative to the directory of the application. This has several benefits but a few security drawbacks 1) hijacking is possible since the current directory is used, 2) if there is a security vulnerability in somelib, you have to patch all applications that use it. I much prefer this to the idea of applications installing files to a shared location on my disk however.libkeepalive: library preloading to force linux programs support TCP Keepalive
Automatic downloading falls into the category "kind-of useful and convenient, but exploitable". Maybe you want to reconsider your argument?
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.
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.
See Myth II: http://minimaxir.com/2013/06/working-as-intended/
This is the type of scenario I'm protecting against, as well as unsophisticated but malicious actors.
Not that that's any less work!
Leaving aside the fact that this is not advisable because user to admin boundary is a lot more porous than remote boundary I hope you're at least running under local non-admin account because of a certain peculiarity of Microsoft[1]. Microsoft doesn't regard UAC as security boundary for admin accounts and won't fix vulnerabilities that enables software to bypass UAC completely. Under default configuration in Windows 7 and 8 (not sure about 10) all software thus runs effectively under root. Also check what parts of filesystem games will have under that account because by default only files in a few system folders are protected while executables outside can be overwritten.
If you can I'd suggest you use dedicated machine for testing, if that is not possible and if you have compatible hardware then use visualization with bypass for GPU which can speed things to usable levels. If both aren't an option then you could test games on a separate hard disk while having main one disconnected physically, which would leave your attack surface open only to firmware overwrites which aren't very common.
I think this could be a multi-pronged solution. Why not attack both sides? Edge and Chrome should correct their behaviors but Windows should also patch things up with DLL loading to reduce the risk. Maybe a signed manifest could verify the assemblies an app is loading and only authorize execution if it passed a UAC prompt explaining why it is blocked.
As a developer, I appreciate that you can use other DLLs too, but this feels like it should be the exception more than the rule.
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.
In other words, I don’t understand why “load DLLs from CWD” is vital to the workings of such mods?
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.)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.
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.
Just now, I decided to mess with Steam again after a long hiatus...guess what popped up when I ran SteamSetup.exe?
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?
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...
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...
The version.dll is a standard Microsoft DLL, just checked it here on a few systems and on Windows 7 it doesn't even appear to have been signed by Microsoft. Only starting in Windows 8 it has been signed.
The version.dll provides very standard functionality such as Win32 API call GetFileVersionInfoA. It is the same thing as what you see in Windows explorer by right-clicking a binary such as exe or DLL and display the version info in the properties tab page.
It is very commonly used functionality so lots of applications/installers will fall for 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.
Though I've never had a need to download multiple exe / msi / dlls at once, so I wouldn't really mind a warning on those downloads. But the OS already does warn for exes from the internet, which makes it a little redundant.
Just how malware works today! even saw this in a Mark Russinovich talk.
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.
Windows could stop trusting code in folders with some flag. That would be much more useful.
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.
also there's the question of should you associate the file with the domain that served it (probably?) or the domain that was in the browser bar when the download was triggered? I think it's unclear because the user's will expect the latter but the former makes more sense as security.
Anyhow I think the right answer is that this is on the OS to provide better defense mechanisms. Maybe just something like the ability for the browser to tag the file with the domain it's from, instead of just "the internet". And then the OS could say "exe from www.foo.com is trying to load dll from www.bar.com, this looks fishy do you want to allow?" or maybe just flat out fail it; this way you get your cross-domain restrictions but less usability problems.
Or better yet, the OSes could solve this problem entirely by having a much stronger whitelist of what DLLs are included from where. why don't we just require programs to specify the full path to any DLL they try to load, instead of doing a search for the file? Or maybe some sort of code signing technique could apply, and programs could specify they want to load X dll, but only if signed by Microsoft or whoever the expected party is, with some optional power-user way to override this?
Or maybe we should just have some sort of warnings when you download a DLL from the internet, and put DLLs in their own download folder or something? That might be the easiest mitigation for a browser to implement.
What fucked up joke is this?!
Since the libraries the application might pull in might not even be available before runtime would you prompt for each load? Maybe prompt for each load that isn't in a system directory -- implying that there isn't prior trust?
You could embed the key the library developer signed the library with but then we have a key revocation problem and updating the library might require updating the application and business critical applications might hold entire departments back from getting security fixes.
I don't think this is really a problem with DLLs or the signature process, but that the old installer tries to load any library in the executable directory.
And any action taken can be either legitimate or nefarious, given the context of intent.
Software need an interfaces that reflect intent - if your browser dumps stuff from unrelated places at the same folder, and then the OS uses those unrelated stuff as if it was related, there's a completely failure from the software data to reflect the user intent. This is a blatant fault of the software stack (but of no party in particular).
Well, I'd say it's Windows fault for having LoadLibrary do so by default. Unsafe actions should have to be manually enabled, not manually disabled!
The idea on Windows is that an application's directory is a trusted location created specifically for that application. Running executables directly out of a Downloads folder is a violation of the Windows security model, so in that sense the security vulnerability is Chrome's fault, as the "correct" thing to do is to put downloaded files into different folders as older versions of IE did. Of course, that's terrible UX, and considering that this exact problem has been popping up for decades, I'd consider a manifest flag for "don't trust the application directory" long overdue.
I find the "put everything that gets downloaded in one folder" to be worse UX than being able to choose where each download goes as it means having to move things back out of the downloads folder instead of them being downloaded to where I want them; especially when they're large files I wanted to put on a different drive, so the move turns into a lengthy copy operation.
It actually searches both the location of the executable and the CWD: https://support.microsoft.com/en-us/kb/2389418#mt1
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).
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).
But then it allows silent DLL dropping... jeez.
In the case of Safari, I'm not sure what downloading a DLL would hurt on a Mac anyway, and an actual executable file would be quarantined.
IMHO the browser should always ask where you want to save something, defaulting to the last location you chose. The extra click/keypress, and having the files downloaded to their intended location, is far better than the multiple actions required to rummage in Downloads and move the files to where they should be afterwards. The workaround, to right-click and "Save As...", also involves an extra action.