Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

Tempest in the ‘TEMP’ Directory

Purpose
Reason
Introduction
Vulnerability
Example 1
Example 2
Example 3
Example 4
Detection
Instrumentation
Examination
MSRC Case 62886
Mitigations
Alternative 1
Alternative 2
Alternative 3

Purpose

Document an easy to exploit trivial vulnerability of Microsoft® Windows® NT due to insufficient isolation of privileged processes running under the NT AUTHORITY\SYSTEM alias LocalSystem account.

Reason

While Microsoft runs its WHQL alias Windows Hardware Certification Program to qualify and certify hardware drivers, offering the Windows Hardware Certification Kit (for Window 7, Window 8, Window 8.1, Window Server 2008 R2, Window Server 2012, Window Server 2012 R2) and the Windows Hardware Lab Kit (for Windows 10, Window Server 2016, Window Server 2019, Windows 11, Window Server 2022) to perform their evaluation, a corresponding and complementary Windows Software Quality Laboratory or Windows Software Certification Program, accompanied by a Windows Software Compatibility Kit or a Windows Software Lab Kit, is but missing, resulting in insecurity and miserability of not just hardware drivers shipped by Microsoft as well as third parties, i.e. IHVs and ISVs.

Introduction

Since Windows 2000 every user account has its own %TEMP%\ alias %LOCALAPPDATA%\Temp\ alias %USERPROFILE%\AppData\Local\Temp\ alias %SystemDrive%\Users\%USERNAME%\AppData\Local\Temp\ directory, which is not accessible for other (unprivileged) users.

The user-specific environment variables TEMP and TMP are set with the following registry entries:

REGEDIT4

[HKEY_CURRENT_USER\Environment]
"TEMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"
"TMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"
For the builtin user accounts NT AUTHORITY\SYSTEM alias LocalSystem, NT AUTHORITY\LOCAL SERVICE alias LocalService, and NT AUTHORITY\NETWORK SERVICE alias NetworkService, the user-specific environment variables TEMP and TMP are set with the following registry entries:
REGEDIT4

[HKEY_USERS\S-1-5-18\Environment]
"TEMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"
"TMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"

[HKEY_USERS\S-1-5-19\Environment]
"TEMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"
"TMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"

[HKEY_USERS\S-1-5-20\Environment]
"TEMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"
"TMP"=expand:"%USERPROFILE%\\AppData\\Local\\Temp"
Note: HKEY_USERS\S-1-5-18 is a symbolic link to the registry key HKEY_USERS\.DEFAULT.

The user profiles for the NT AUTHORITY\LOCAL SERVICE alias LocalService and the NT AUTHORITY\NETWORK SERVICE alias NetworkService accounts are stored in the directories %SystemRoot%\ServiceProfiles\LocalService\ and %SystemRoot%\ServiceProfiles\NetworkService\ respectively, which too are not accessible for other (unprivileged) users.

On 32-bit editions of Windows NT the user profile for the NT AUTHORITY\SYSTEM alias LocalSystem account is stored in the directory %SystemRoot%\System32\Config\SystemProfile\, which also is not accessible for other (unprivileged) users.
On 64-bit editions of Windows NT, thanks to the File System Redirector, the user profile for the NT AUTHORITY\SYSTEM alias LocalSystem account is stored in the disjoint directories %SystemRoot%\System32\Config\SystemProfile\ and %SystemRoot%\SysWoW64\Config\SystemProfile\, which are not accessible for other (unprivileged) users.

Note: the (sub)directory %SystemRoot%\System32\Config\SystemProfile\AppData\Local\Temp\, on 64-bit editions of Windows NT also %SystemRoot%\SysWoW64\Config\SystemProfile\AppData\Local\Temp\, which corresponds to %USERPROFILE%\AppData\Local\Temp\, but doesn’t exist, i.e. the user-specific environment variables TEMP and TMP set for the NT AUTHORITY\SYSTEM alias LocalSystem account have an invalid (dangling) value!

Only for the NT AUTHORITY\SYSTEM alias LocalSystem account the user-specific environment variables TEMP and TMP are but ignored and the system-specific environment variables evaluated instead, which are set with the following registry entries:

REGEDIT4

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment]
"TEMP"=expand:"%SystemRoot%\\TEMP"
"TMP"=expand:"%SystemRoot%\\TEMP"
Note: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet is a symbolic link to the registry key HKEY_LOCAL_MACHINE\SYSTEM\ControlSet‹digit›‹digit›‹digit›, typically HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001.

Due to its inheritable DACL D:PAI(A;CI;0x100026;;;BU)(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)(A;OICIIO;GA;;;CO) the directory %SystemRoot%\Temp\ is writable for unprivileged users who can create arbitrary files and subdirectories with full access permission for themselves as well as NT AUTHORITY\SYSTEM alias LocalSystem and BUILTIN\Administrators there.

The resulting well-known weaknesses are classified as CWE-378: Creation of Temporary File With Insecure Permissions, CWE-379: Creation of Temporary File in Directory with Incorrect Permissions, CWE-426: Untrusted Search Path and CWE-427: Uncontrolled Search Path Element.

Vulnerability

Processes running under the privileged NT AUTHORITY\SYSTEM alias LocalSystem account use the directory %SystemRoot%\Temp\ as their %TEMP%\ directory, thus defeating their isolation from unprivileged processes.

Setup programs, most notably self-extractors alias wrappers, unpack their payload, which typically includes executable files, to the processes %TEMP%\ alias %SystemRoot%\Temp\ directory and run the extracted executable files there.

When stored in a directory other than the system directory %SystemRoot%\System32\ and executed there, programs susceptible to CAPEC-471: Search Order Hijacking load system DLLs and system programs from their application directory instead from the system directory %SystemRoot%\System32\: as documented in the MSDN articles Dynamic-Link Library Security, Dynamic-Link Library Search Order, LoadLibrary() and CreateProcess(), the application directory is searched first per default.

By planting files in the directory %SystemRoot%\Temp\ which are executed from vulnerable programs run there any time later, unprivileged users can elevate their privileges to those of NT AUTHORITY\SYSTEM alias LocalSystem and BUILTIN\Administrators.

Example 1

Skype uses its own proprietary update mechanism instead of Microsoft Update: in version 7, the program %ProgramFiles%\Skype\Updater\Updater.exe is run periodically under the NT AUTHORITY\SYSTEM alias LocalSystem user account. When an update is available, %ProgramFiles%\Skype\Updater\Updater.exe copies or extracts another executable as %TEMP%\SKY‹abcd›.tmp alias %SystemRoot%\Temp\SKY‹abcd›.tmp and executes it using the command line
"%SystemRoot%\Temp\SKY‹abcd›.tmp" /QUIET
This executable is susceptible to CAPEC-471: Search Order Hijacking, it loads multiple system DLLs from its application directory %SystemRoot%\Temp\ instead from Windows’ system directory %SystemRoot%\System32\.

For the full story see Skype – or “Redmond, You’ve got a Problem!”.

Example 2

Deployment and unattended installation of application software is typically performed via an agent or service running with administrative privileges on client computers, for example the built-in Group Policies, as documented in the MSKB article 816102.

For just one case where this still allows local users to escalate their privileges see ADV170017.

Example 3

With Windows 10 20H1 Microsoft moved the installation of (updated) drivers available online from Device Manager to Windows Update.

Contrary to previous versions, where driver installation initiated from Driver Manager runs under an administrator account, driver installation now runs under the NT AUTHORITY\SYSTEM alias LocalSystem user account.

Processes running under a normal user (or administrator) account use its (private) %LOCALAPPDATA%\Temp\ alias %USERPROFILE%\AppData\Local\Temp\ directory, which is not accessible for other (unprivileged) users, as %TEMP%\ directory, while processes running under the NT AUTHORITY\SYSTEM alias LocalSystem account use the (public) %SystemRoot%\Temp\ directory.

Quite some driver packages available on Windows Update contain besides their primary (kernel) drivers, which are typically installed via .inf scripts, also so-called satellites, i.e. additional programs and/or DLLs, which provide interfaces to configure and control the driver and its hardware. These satellites are typically installed by separate setup programs that are run during driver installation.

Note: satellites (really: arbitrary applications) can of course be installed via .inf scripts too, but seldom are.

These setup programs are typically self-extractors which use the %TEMP%\ directory to unpack and run their payload. Instead to create a properly secured subdirectory there, some self-extractors place their payload in the %TEMP%\ directory itself. Many, if not most payloads are but susceptible to CAPEC-471: Search Order Hijacking and execute files planted by unprivileged users in the %TEMP%\ alias %SystemRoot%\Temp\ directory with administrative privileges and access rights.

Example 4

Vulnerable (setup) programs like those in example 3, when run via computer startup scripts.

Detection

Instrumentation

To instrument an installed system for detection, create hardlinks of all 32-bit system DLLs (for example) in the %SystemRoot%\Temp\ directory and configure the advanced logging feature of Software Restriction Policies to track (not only) their execution.

Run the following VBScript elevated, i.e. with administrative privileges, in the 32-bit execution environment:

Rem Copyright © 2004-2023, Stefan Kanthak <stefan‍.‍kanthak‍@‍nexgo‍.‍de>

Option Explicit

Const strCommandLine = "C:\Windows\System32\Cmd.exe /D /K For %? In (*.acm *.ax *.cpl *.dll *.drv *.ocx WBEM\*.dll) Do @MkLink /H C:\Windows\Temp\%~nx? %?"
Const strCurrentDirectory = "C:\Windows\System32"

With GetObject("WinMgmts:{impersonationLevel=Impersonate, (Backup, Restore)}!\\.\Root\CIMv2")
	Dim objProcessStartup
	Set objProcessStartup = .Get("Win32_ProcessStartup").SpawnInstance_
	With objProcessStartup
	'	.CreateFlags = 8	' Detached_Process
	'	.EnvironmentVariables = Array("NoDefaultCurrentDirectoryInExePath=*", _
	'	                              "SYSTEMDRIVE=C:", _
	'	                              "SYSTEMROOT=C:\Windows", _
	'	                              "TEMP=C:\Windows\Temp")
		.ErrorMode = 2		' Fail_Critical_Errors
		.FillAttribute = 240	' Black on White
		.PriorityClass = 32	' Normal
		.ShowWindow = 1		' SW_NORMAL
		.Title = vbNull
		.WinstationDesktop = vbNull
	'	.X = 0
		.XCountChars = 80
	'	.XSize = 640
	'	.Y = 240
		.YCountChars = 50
	'	.YSize = 480
	End With

	Dim intReturn, intProcessID
	intReturn = .Get("Win32_Process").Create(strCommandLine, strCurrentDirectory, objProcessStartup, intProcessID)
	If intReturn <> 0 Then
		WScript.Echo "Error " & intReturn
	Else
		WScript.Echo "Process " & intProcessID & " created"
	End If
End With

With WScript.CreateObject("WScript.Shell")
	.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\AuthentiCodeEnabled", 0, "REG_DWORD"
	.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\DefaultLevel", 262144, "REG_DWORD"
'	.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\ExecutableTypes", vbNull, "REG_MULTI_SZ"
	.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\LogFileName", "C:\Windows\System32\LogFiles\SAFER.log", "REG_SZ"
	.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\PolicyScope", 0, "REG_DWORD"
	.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\TransparentEnabled", 2, "REG_DWORD"
End With
Alternative: run the following batch script in Windows PE after SETUP.exe /NoReboot, with the drive letter of the target volume as its only argument:
Rem Copyright © 2004-2023, Stefan Kanthak <stefan‍.‍kanthak‍@‍nexgo‍.‍de>

If "%~1" == "" Goto :USAGE
If Not "%1" == "%*" Goto :USAGE
If /I Not "%~1" == "%~d1" Goto :USAGE
If "%~d1" == "%SystemDrive%" Goto :USAGE
If Not Exist "%~d1\Windows\System32\Config\SOFTWARE" Goto :USAGE

If Exist "%~d1\Windows\SysWoW64" (
For %%? In ("%~d1\Windows\SysWOW64\*.acm"
            "%~d1\Windows\SysWOW64\*.ax"
            "%~d1\Windows\SysWOW64\*.cpl"
            "%~d1\Windows\SysWOW64\*.dll"
            "%~d1\Windows\SysWOW64\*.drv"
            "%~d1\Windows\SysWOW64\*.ocx"
            "%~d1\Windows\SysWOW64\WBEM\*.dll") Do @MkLink /H "%~d1\Windows\Temp\%%~nx?" "%%?"
) Else (
For %%? In ("%~d1\Windows\System32\*.acm"
            "%~d1\Windows\System32\*.ax"
            "%~d1\Windows\System32\*.cpl"
            "%~d1\Windows\System32\*.dll"
            "%~d1\Windows\System32\*.drv"
            "%~d1\Windows\System32\*.ocx"
            "%~d1\Windows\System32\WBEM\*.dll") Do @MkLink /H "%~d1\Windows\Temp\%%~nx?" "%%?"
)
"%SystemRoot%\System32\Reg.exe" LOAD   "HKEY_USERS\SOFTWARE" "%~d1\Windows\System32\Config\SOFTWARE"
"%SystemRoot%\System32\Reg.exe" QUERY  "HKEY_USERS\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers" /S
"%SystemRoot%\System32\Reg.exe" ADD    "HKEY_USERS\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers" /V "AuthentiCodeEnabled" /T REG_DWORD /D 0 /F
"%SystemRoot%\System32\Reg.exe" ADD    "HKEY_USERS\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers" /V "DefaultLevel" /T REG_DWORD /D 262144 /F
"%SystemRoot%\System32\Reg.exe" ADD    "HKEY_USERS\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers" /V "ExecutableTypes" /T REG_MULTI_SZ /D "" /F
"%SystemRoot%\System32\Reg.exe" ADD    "HKEY_USERS\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers" /V "LogFileName" /T REG_SZ /D "C:\Windows\System32\LogFiles\SAFER.log" /F
"%SystemRoot%\System32\Reg.exe" ADD    "HKEY_USERS\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers" /V "PolicyScope" /T REG_DWORD /D 0 /F
"%SystemRoot%\System32\Reg.exe" ADD    "HKEY_USERS\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers" /V "TransparentEnabled" /T REG_DWORD /D 2 /F
"%SystemRoot%\System32\Reg.exe" UNLOAD "HKEY_USERS\SOFTWARE"
Exit /B

:USAGE
Echo Usage: %~nx0 ^<drive letter^>:
Exit /B
Note: since (the hardlinks of) the system DLLs are writable only for the TrustedInstaller account or with SeRestorePrivilege enabled, this instrumentation inhibits attacks via (malicious) fake system DLLs and mitigates the vulnerability!

Note: some hardlinks will become orphans over time and thus undergo bit rot, they are not updated by (security) updates; orphaned hardlinks can be deleted and recreated any time!

Examination

Run the following command line to list the pathnames of files executed in and below the %SystemRoot%\Temp\ directory:
REM Copyright © 2004-2023, Stefan Kanthak <stefan‍.‍kanthak‍@‍nexgo‍.‍de>

FIND.EXE /I "%SystemRoot%\Temp\" "%SystemRoot%\System32\LogFiles\SAFER.log"

MSRC Case 62886

I reported a vulnerability detected during installation of a graphic display driver via Windows Update to the driver’s vendor and the MSRC, where case number 62886 was assigned:

After exchanging several rounds of mail discussing the case they replied with the following statements:

Because this vulnerability exists in a third-party driver installer, Microsoft cannot fix the vulnerability itself. I had contacted NVIDIA in January and was told that the driver in question is out of support.

As for %TEMP% / %TMP% for the SYSTEM account, this is a known issue. We’re experimenting with ways to mitigate this issue in future versions of Windows (https://aka.ms/flighthub). Unfortunately, these mitigations are infeasible on existing Windows versions because they introduce application compatibility issues.

I had asked for more time because I wanted to check if we could implement a limited (i.e., not system-wide) mitigation for the TEMP issue that would not involve updating the third-party installer. After further discussion, my colleagues and I concluded that even a limited mitigation would still introduce application compatibility issues and would not even address all instances of the TEMP issue across all third-party drivers (e.g., third-party drivers that had hardcoded C:\Windows\Temp, though we don’t believe that that’s the case with this specific driver).

Moreover, any TEMP mitigation would not address any memory corruption bugs—like the ones you noted in your original report—in this or other third-party drivers.

We understand that vulnerable drivers are a problem. While we don’t have an immediate solution for this case, MSRC 62886, or other vulnerable third-party drivers (or vulnerable third-party driver installers), we encourage customers to report vulnerable drivers here:

https://www.microsoft.com/en-us/wdsi/driversubmission

Thanks again for reporting this issue, answering our questions, sharing an advance copy of your blog post, and giving us extra time to do some additional analysis.

Mitigations

Never create or execute files directly in the %SystemRoot%\Temp\ directory; always create a properly secured subdirectory which other (less privileged) users can’t access first, then create your files there!

Since this doesn’t help with existing self-extractors which ignore this basic rule of isolation and privilege separation, better use the following alternative mitigation.

Alternative 1

Create the missing subdirectory %SystemRoot%\System32\Config\SystemProfile\AppData\Local\Temp\, on 64-bit systems also %SystemRoot%\SysWoW64\Config\SystemProfile\AppData\Local\Temp\, owned by the NT AUTHORITY\SYSTEM alias LocalSystem user account, and set the system-specific environment variables TEMP and TMP to the value %USERPROFILE%\AppData\Local\Temp.

Use the following command lines in the batch script %SystemRoot%\Setup\Scripts\SetupComplete.cmd to apply these changes automatically during Windows Setup:

Rem Copyright © 2009-2023, Stefan Kanthak <stefan‍.‍kanthak‍@‍nexgo‍.‍de>

MkDir "%SystemRoot%\System32\Config\SystemProfile\AppData\Local\Temp"
If Exist "%SystemRoot%\SysWoW64\Config\SystemProfile" MkDir "%SystemRoot%\SysWoW64\Config\SystemProfile\AppData\Local\Temp"

"%SystemRoot%\System32\SetX.exe" TEMP "%%USERPROFILE%%\AppData\Local\Temp" /M
"%SystemRoot%\System32\SetX.exe" TMP "%%USERPROFILE%%\AppData\Local\Temp" /M
Exit /B
Note: this mitigation also stops many other attacks and thus prevents vulnerabilities like Microsoft Windows Defender Elevation of Privilege Vulnerability alias CVE-2020-1170 from being exploited in the first place!

Caveat: on 64-bit systems, the disjoint directories may cause surprising behaviour!

Alternative 2

Add the ACEs (D;OIIO;WP;;;WD) and (D;CIOIIO;WD;;;OW) to the DACL of the %SystemRoot%\Temp\ directory: the first ACE denies execute permission for all files created there, the second ACE denies the respective owner of files and subdirectories the (otherwise implied) permission to change their DACL.

Also set the attributes hidden and system to prevent File Explorer from granting full access to any UAC controlled administrator account, as documented in the MSKB article 950934.

Use the following command lines in the batch script %SystemRoot%\Setup\Scripts\SetupComplete.cmd to apply these changes automatically during Windows Setup:

Rem Copyright © 2009-2023, Stefan Kanthak <stefan‍.‍kanthak‍@‍nexgo‍.‍de>

"%SystemRoot%\System32\CACLs.exe" "%SystemRoot%\Temp" /S:"D:PAR(D;CIOIIO;WD;;;OW)(D;OIIO;WP;;;WD)(A;CI;0x100026;;;BU)(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)(A;OICIIO;GA;;;CO)"
"%SystemRoot%\System32\Attrib.exe" +H +R +S "%SystemRoot%\Temp" /M
Exit /B

Alternative 3

See detection above!

Note: the instrumentation prevents only attacks via fake system DLLs; it does not prevent similar attacks via fake system programs like Cmd.exe etc., which may be called from batch scripts running in the %SystemRoot%\Temp\ directory via unqualified filenames.

Contact

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, deficiencies, errors, inaccuracies, misrepresentations, omissions, shortcomings, vulnerabilities or weaknesses, …: don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Note: email in weird format and without a proper sender name is likely to be discarded!

I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see your full (real) name as sender, not your nickname.
I abhor top posts and expect inline quotes in replies.

Terms and Conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!

Data Protection Declaration

This web page records no (personal) data and stores no cookies in the web browser.

The web service is operated and provided by

Telekom Deutschland GmbH
Business Center
D-64306 Darmstadt
Germany
<‍hosting‍@‍telekom‍.‍de‍>
+49 800 5252033

The web service provider stores a session cookie in the web browser and records every visit of this web site with the following data in an access log on their server(s):


Copyright © 1995–2023 • Stefan Kanthak • <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>