Protection against exploitation of CWE-428 Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

Protection against exploitation of CWE-428

Purpose

Protection against exploitation of the well-known weakness CWE-428: Unquoted Search Path or Element listed in the CWE.

Reason

The (to say the very least) weird braindead behaviour of the Win32 functions CreateProcess(), CreateProcessAsUser(), CreateProcessWithLogonW(), CreateProcessWithTokenW() and WinExec(), introduced with the support of long filenames with Win32 in Windows NT 3.1 (and of course Windows 95 too) more than 20 years ago:
[…] the module name must be the first white space-delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:
c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe
These Win32 functions play try & error where they should but fail and return an error to their caller!

Observed behavior

On Windows NT 5.x (Windows Embedded POSReady 2009 is in extended support until April 2019) the Win32 function calls
CreateProcess*(NULL, "C:\\Program Files\\Internet Explorer\\IExplore.exe", …)
CreateProcess*(NULL, "C:\\Program Files (x86)\\Internet Explorer\\IExplore.exe", …)
yield Win32 error 5 alias ERROR_ACCESS_DENIED if the directories C:\Program\ and/or C:\Program.exe\ exist.

On Windows NT 6.x the directories C:\Program\ and C:\Program.exe\ are but ignored/skipped and the (unquoted) command line executed successfully.

On both Windows NT 5.x and Windows NT 6.x the Win32 function calls

CreateProcess*(NULL, "C:\\Program Files\\Internet Explorer\\IExplore.exe", …)
CreateProcess*(NULL, "C:\\Program Files (x86)\\Internet Explorer\\IExplore.exe", …)
yield ERROR_ACCESS_DENIED if the directories "C:\Program Files\Internet\", "C:\Program Files\Internet.exe\", "C:\Program Files (x86)\Internet\" and/or "C:\Program Files (x86)\Internet.exe\" respectively exist (yes, you need administrative rights to create them, but that's not the point here).

Do you like the inconsistent behaviour or the special treatment of the directories C:\Program\ and C:\Program.exe\ under Windows NT 6.x?

Now remove the directories "C:\Program Files (x86)\Internet.exe\", "C:\Program Files (x86)\Internet\", "C:\Program Files\Internet.exe\", "C:\Program Files\Internet\", C:\Program.exe\ and C:\Program\ and create the files "C:\Program Files\Internet.exe" and "C:\Program Files (x86)\Internet.exe" (yes, you need administrative rights to create them too, but that's still not the point here):

%COMSPEC% /C COPY %COMSPEC% "C:\Program Files\Internet.exe"
%COMSPEC% /C COPY %COMSPEC% "C:\Program Files (x86)\Internet.exe"
On both Windows NT 5.x and Windows NT 6.x the Win32 function calls
CreateProcess*(NULL, "C:\\Program Files\\Internet Explorer\\IExplore.exe", …)
CreateProcess*(NULL, "C:\\Program Files (x86)\\Internet Explorer\\IExplore.exe", …)
execute the file "C:\Program Files\Internet.exe" or "C:\Program Files (x86)\Internet.exe" respectively.

Create the directories "C:\Program Files\Internet\" and "C:\Program Files (x86)\Internet\" and retry: the Win32 function calls

CreateProcess*(NULL, "C:\\Program Files\\Internet Explorer\\IExplore.exe", …)
CreateProcess*(NULL, "C:\\Program Files (x86)\\Internet Explorer\\IExplore.exe", …)
don't execute the file "C:\Program Files\Internet.exe" or "C:\Program Files (x86)\Internet.exe" but "C:\Program Files\Internet Explorer\IExplore.exe" or "C:\Program Files (x86)\Internet Explorer\IExplore.exe" instead, i.e. the presence of a directory "C:\Program Files\Internet\" or "C:\Program Files (x86)\Internet\" lets Windows NT skip/ignore a file "C:\Program Files\Internet.exe" or "C:\Program Files (x86)\Internet.exe"!

Does this work for the file C:\Program.exe too?

After execution of the command line

%COMSPEC% /C COPY %COMSPEC% C:\Program.exe
the Win32 function calls
CreateProcess*(NULL, "C:\\Program Files\\Internet Explorer\\IExplore.exe", …)
CreateProcess*(NULL, "C:\\Program Files (x86)\\Internet Explorer\\IExplore.exe", …)
execute C:\Program.exe on all versions of Windows NT!

Finally create the directory C:\Program\ and retry: the Win32 function calls

CreateProcess*(NULL, "C:\\Program Files\\Internet Explorer\\IExplore.exe", …)
CreateProcess*(NULL, "C:\\Program Files (x86)\\Internet Explorer\\IExplore.exe", …)
yield ERROR_ACCESS_DENIED on Windows NT 5.x, but execute their (unquoted) command line on Windows NT 6.x!

Caveat: the documentation of the behaviour of the Win32 functions CreateProcess*() for unquoted command lines is incomplete:

[…] the module name must be the first white space-delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:
c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe
Neither the 4 other possibilities
c:\program files\sub dir\program name
c:\program files\sub dir\program name
c:\program files\sub dir\program name
c:\program files\sub dir\program name
which are tried first (executable files don't need to have a file extension at all, .exe is appended only if there is no direct match!), nor the skipping of files "…\‹name›.exe" in the presence of directories "…\‹name›\", nor the behaviour for "c:\program files (x86)\sub dir\program name" are documented!

Note: the Win32 functions LoadLibrary*("") search for a file .dll in the DLL search path and load it: executables also don't need to have a file name at all!

For further investigations peeking and poking see the documentation of NTFS Reparse Points:

A file or directory can contain a reparse point, which is a collection of user-defined data. The format of this data is understood by the application which stores the data, and a file system filter, which you install to interpret the data and process the file. When an application sets a reparse point, it stores this data, plus a reparse tag, which uniquely identifies the data it is storing. When the file system opens a file
or a directory
with a reparse point, it attempts to find the file system filter associated with the data format identified by the reparse tag. If a file system filter is found, the filter processes the file as directed by the reparse data. If a file system filter is not found, the file open operation fails.
Then create a directory %SystemDrive%\Program\ and add a collection of user-defined data to it: (Un)fortunately the file system filter driver for symbolic links only handles reparse points from file to file and directory to directory; it fails on reparse points from file to directory and from directory to file.

The file system filter driver for junctions (and mount points) only handles reparse points from directory to directory or from directory to drive; it fails on reparse points with all other combinations.

Note: the MkLink builtin command of the command processor of Windows Vista and newer versions of Windows NT but creates reparse points with such invalid combinations the existing file system filter drivers can't handle:

%COMSPEC% /C MKLINK %SystemDrive%\Program %PUBLIC%
%COMSPEC% /C MKLINK /D %SystemDrive%\Program %COMSPEC%
%COMSPEC% /C MKLINK /J %SystemDrive%\Program %COMSPEC%

Code authenticity and integrity

CWE-428.CAB is digitally signed using an X.509 certificate issued by WEB.DE TrustCenter E-Mail Certification Authority.
Serial number
73420882
0x04605052
Fingerprint
MD5: e5 0b 01 66 ce 2e 7a 03 f4 98 39 37 f6 f9 9f ba
SHA-1: 79 05 5d 63 2f 03 31 83 04 e2 ff 3b 25 b9 cc b6 70 ad ec 31
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAwoDvctTIkyz5KyHlms35ue9lm7I2yPVqZbRjGL26OKxei/R9APYKA47yoJQu
QZvr0husZPI/XQEGDicmBH1Gw/T821Y/E3pwUrumhw2dRI83Vn3wqO1OaAfkcOxjtNthr04r
YT+8f1SJtZabDP0Fv7dF4ltrUSwvy+lxV4jLLU2y7qtJ6XawLHEIBZAurozEGUVlgF93nsIZ
ydcHLxQzUEbSSsegkeY+aaaC/pGFE9Q3P3c4Nn5kOwK8ElwPwbHFMiK4t8RT3DSPXX0XQl2M
yoB3XAhZj6VOC9JyHC4COVSTnbFz3mmDkxYL/qyKFkDH/V5JWZhEv+T0Rl2Bebh91wIDAQAB
-----END RSA PUBLIC KEY-----
Download and install the CA and root X.509 certificates of WEB.DE to validate and verify the digital signature.

Note: the digital signature remains valid past the certificates expiration date due to its counter signature alias timestamp!

Installation

The installation requires administrative privileges.

Automatic online installation

If visited with Internet Explorer, this web page will prompt to install (the contents of) the package using Internet Component Download.

Manual offline installation

Download the package CWE-428.CAB and verify its digital signature, then open it in Windows Explorer, extract its contents and call the extracted batch script CWE-428.CMD to run the installation.

Deinstallation

Not provided.

Background information

In the blog post It rather involved being on the other side of this airtight hatchway: Unquoted service paths, once again a Microsoft® employee tried to downplay the well-known (and trivial to fix) weakness CWE-428: Unquoted Search Path or Element.

In standard installations of Windows® NT users are but per default on the wrong side of this (not so) airtight hatchway: the user account(s) created during Windows NT setup is/are member(s) of the Administrators group, and the security theatre named User Account Control is no security boundary!

According to numbers published by Microsoft in their Security Intelligence Reports, about ½ to ¾ of all (some 100 million) Windows NT installations engaged in their malware telemetry reported only a single active user account.

Standard installations of Windows 7 (and earlier versions of Windows NT too) include services (and other components) which use unquoted command lines!

A proof of concept (working in standard installations of Windows 7, Windows Server 2008 R2, Windows 8, Windows Server 2012, Windows 8.1 and Windows Server 2012 R2) which uses UACs auto-elevation (mis)feature to copy an arbitrary file to %SystemRoot%\Program.exe is available as PROGRAM.CMD.

Disabling User Account Control (UAC) on Windows Server:

One of the common misconceptions about UAC and about Same-desktop Elevation in particular is that it prevents malware from being installed or from gaining administrative rights. First, malware can be written not to require administrative rights, and malware can be written to write just to areas in the user's profile. More important, Same-desktop Elevation in UAC is not a security boundary and can be hijacked by unprivileged software that runs on the same desktop. Same-desktop Elevation should be considered a convenience feature, and from a security perspective, "Protected Administrator" should be considered the equivalent of "Administrator." By contrast, using Fast User Switching to log on to a different session by using an administrator account involves a security boundary between the administrator account and the standard user session.
Update on UAC:
One important thing to know is that UAC is not a security boundary. UAC helps people be more secure, […]
The most effective way to secure a system against malware is to run with standard user privileges.
Inside Windows 7 User Account Control:
[…] the primary purpose of elevation is not security, though, it's convenience: […]
The Long-Term Impact of User Account Control:
[…] this is also where we run into some of the limitations of UAC. Remember, there is no effective isolation; there is no security boundary that isolates processes on the same desktop.
Inside Windows Vista User Account Control:
It's important to be aware that UAC elevations are conveniences and not security boundaries. A security boundary requires that security policy dictates what can pass through the boundary. User accounts are an example of a security boundary in Windows because one user can't access the data belonging to another user without having that user's permission.

Despite this, unprivileged users can create the directories %SystemDrive%\Program\ and %SystemDrive%\Program.exe\ on all versions of Windows NT.

Note: finding the appropriate directory name for non-english versions of Windows NT 3.x, Windows NT 4 and Windows NT 5.x (where unprivileged users can create the files %SystemDrive%\Program and %SystemDrive%\Program.exe which will be executed) is left as an exercise to the reader.

Note: if 8.3 alias short file name creation is enabled, a user with privilege SeRestorePrivilege might just create short file names, either using the Win32 function SetFileShortName() or the command FSUtil.exe:

PROGRAM or PROGRAM.EXE for the directory "C:\Program Files\",
PROGRAM or PROGRAM.EXE for any file "C:\‹arbitrary executable›",
COMMON or COMMON.EXE for the directory "C:\Program Files\Common Files\",
INTERNET or INTERNET.EXE for the directory "C:\Program Files\Internet Explorer\",
INTERNET or INTERNET.EXE for any file "C:\Program Files\‹arbitrary executable›",

Event ID 7000 and "%1 Is Not a Valid Win32 Application" Error Message When You Start a Service:

This issue may occur if the path of the executable file for the service contains spaces.

When Windows starts a service, it parses the path of the service from left to right. If both of the following conditions are true, Windows may locate and try to run the file or folder before it locates and runs the executable file for the service:

For example, if the path of the executable file for a service is C:\Program Files\MyProgram\MyService.exe, and if a folder that is named C:\Program also exists on your hard disk, Windows locates the C:\Program folder on your hard disk before the C:\Program Files\MyProgram\MyService.exe file, and then tries to run it.

Contact

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, errors, inaccuracies, omissions, 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.

Notes: I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see a full (real) name as sender, not a nickname!
Emails in weird formats and without a proper sender name are likely to be discarded.
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!
Copyright © 1995-2017 • Stefan Kanthak • <‍skanthak‍@‍nexgo‍.‍de‍>