This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: DLL hijacking vulnerability in Python 3.5.2 installer
Type: security Stage: resolved
Components: Installation, Windows Versions: Python 3.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: anandbhat, chrullrich, eryksun, jkloth, mhammond, paul.moore, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2016-06-29 03:50 by anandbhat, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
Python_3.5.2_64_exe_version_DLL_Hijack.PNG anandbhat, 2016-06-29 03:51
Python_3.5.2_64_exe_DLL_Hijack.PNG anandbhat, 2016-06-29 03:53
Messages (5)
msg269461 - (view) Author: (anandbhat) Date: 2016-06-29 03:50
The Python 3.5.2 Windows x86-64 executable installer (MD5: 4da6dbc8e43e2249a0892d257e977291) downloaded from https://www.python.org/ftp/python/3.5.2/python-3.5.2-amd64.exe is vulnerable to DLL hijacking.

The installer attempts to load DLLs from the current directory, which in most cases, is the Downloads directory. As explained in http://blog.opensecurityresearch.com/2014/01/unsafe-dll-loading-vulnerabilities.html and https://textslashplain.com/2015/12/18/dll-hijacking-just-wont-die/, installers that are vulnerable to DLL hijacking can be used to load untrusted and malicious DLLs. A maliciously crafted DLL when dropped into the user's Downloads directory will be executed by this installer.

System used for testing: Windows 10

Steps to reproduce:

1. Download a dummy DLL file for this demo -- version.dll -- from https://www.dropbox.com/s/3l5qwz7ppevs9za/version.dll?dl=0 and place it in the default Downloads directory. Virustotal report for this file: https://www.virustotal.com/en/file/29b51fdb8e498ef5d3fe05e924e23fcaffa554d64fb024b042101236028242b0/analysis/1467171188/

2. Download the Python 3.5.2 Windows x86-64 executable installer (MD5: 4da6dbc8e43e2249a0892d257e977291) from https://www.python.org/ftp/python/3.5.2/python-3.5.2-amd64.exe and save it to the default Downloads directory (e.g., C:\Users\xxx\Downloads)

3. Attempt to run the downloaded installer.

4. Windows loads version.dll placed in step [1]. This is just one of several DLLs that can be exploited.

Attached are screen captures from Process Monitor (https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx) in a Windows 10 environment with filters (listed below) that show the DLLs looked for by the installer in the Downloads directory.

Process Monitor filters:
Inclusion:

Process Name beginswith python,
Path beginswith <path to Downloads directory>
Operation is Load Image
Operation is CreateImage
Exclusion:

Path endswith .ini
Path contains .exe
msg269482 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2016-06-29 12:19
> installer attempts to load DLLs from the current directory

It's actually the application directory that's the culprit, not the current directory. All supported versions of Windows default to SafeDllSearchMode, which moves the current directory after system directories. However, the loader (and also the CreateProcess family) default to searching the application directory before system directories. Known DLLs [1] aren't vulnerable, and AFAIK neither are DLLs loaded from system API Sets, which is typically how ucrtbase.dll gets loaded. 

The problem could be worked around by calling SetDefaultDllDirectories (requires KB2533623 prior to Windows 8) to disable searching the application directory. For static imports, I suppose one could delay loading them until after SetDefaultDllDirectories is called. There should really be a way to control this behavior in the application manifest. Giving the application directory priority when looking for DLLs and EXEs is fine for securely installed applications, but not for installers and the like.

[1] HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
msg269489 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2016-06-29 13:35
Unless you can show that it's loaded after the installer elevates, I'm not concerned. "User can run arbitrary code as themselves" is not a security vulnerability. (Hint: when the bundle elevates, it copies the exe to a new directory and runs it from there to avoid this issue.)

I'll leave this open for a few days in case of more comments.
msg269780 - (view) Author: Mark Hammond (mhammond) * (Python committer) Date: 2016-07-04 08:26
While I agree the risk is fairly low and it will require effort to actually do, it still sounds worth fixing at some point. A user might be tricked into downloading a DLL - eg, Firefox will happily save it without any scary UI - it's just a file. Later they run our "trusted" download from the same directory and we screw them - even if the attacker can't elevate they can do damage.
msg269812 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2016-07-04 22:13
It's not even that the risk is low, it's that we can't actually fix it. There are zero explicit DLL loads in the installer (either the part we own or the third-party core) that are insecure, and the four DLLs referenced by the third-party core executable that are not listed as KnownDLLs are Windows system DLLs that could be used by any downloaded executable - in particular installers, which are most likely to show up in a downloads folder.

If a user is not knowledgeable enough to avoid "accidentally" downloading a file from a website, is not perceptive enough to notice an unexpected download, and/or is not paranoid enough to run installers from their own directory, they are going to be affected by this design decision in the operating system through some other installer.

We are already more secure than most, since we don't elevate by default. The 7-zip installer (which just happened to be first in my downloads folder) is more vulnerable to this, in that it will load version.dll from the downloads folder and execute code as Administrator. We will only run it as the current user, which is certainly a vector to start executing code, but it's not one that we can possibly close off.

If someone wants to report this flaw to the Microsoft security team, they can consider changing Windows to add these DLLs to the KnownDLLs list and ensure that the system's version is always loaded. The most we can do is publish an article for paranoid people to protect themselves (which I am not volunteering to write).
History
Date User Action Args
2022-04-11 14:58:33adminsetgithub: 71597
2016-07-04 22:13:58steve.dowersetstatus: open -> closed
resolution: not a bug
messages: + msg269812

stage: resolved
2016-07-04 08:26:45mhammondsetnosy: + mhammond
messages: + msg269780
2016-06-29 16:11:16jklothsetnosy: + jkloth
2016-06-29 13:35:21steve.dowersetmessages: + msg269489
2016-06-29 12:19:28eryksunsetnosy: + eryksun, paul.moore, tim.golden, zach.ware
messages: + msg269482
components: + Windows
2016-06-29 06:43:02chrullrichsetnosy: + chrullrich
2016-06-29 05:01:27berker.peksagsetnosy: + steve.dower
2016-06-29 03:53:56anandbhatsetfiles: + Python_3.5.2_64_exe_DLL_Hijack.PNG
2016-06-29 03:52:15anandbhatsetfiles: - Python_3.5.2_64_exe_DLL_Hijack.PNG
2016-06-29 03:51:17anandbhatsetfiles: + Python_3.5.2_64_exe_version_DLL_Hijack.PNG
2016-06-29 03:50:44anandbhatcreate