Skip to navigation Skip to main content Skip to footer

Technical Advisory – Nullsoft Scriptable Installer System (NSIS) – Insecure Temporary Directory Usage

03 July 2023

By Rich Warren

Title: Nullsoft Scriptable Installer System (NSIS) - Insecure Temporary Directory
Usage
Vendor URL: https://nsis.sourceforge.io/Main_Page
Versions Affected: NSIS 3.08 (September 25, 2021) and below
CVE Identifier: CVE-2023-37378
Risk:
7.8 CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
7.3 CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Author: Richard Warren 

Description

The NSIS uninstaller package did not enforce appropriate permissions on the temporary directory used during the uninstall process. Furthermore, it did not ensure that the temporary directory was removed before running executable content from it. This could potentially result in privilege escalation under certain scenarios.

Impact

A low-privileged, local attacker could exploit this vulnerability to execute arbitrary code with the privileges of the user that launched the uninstaller – potentially resulting in privilege escalation. An example of this could be a privileged Windows service that runs as SYSTEM , and runs an NSIS uninstall.exe package. A malicious user could exploit this vulnerability to gain code execution with the privileges of that service.

Technical Details

During the uninstall process, the NSIS uninstaller.exe executable creates a temporary
sub-directory under the current user’s %TEMP% folder. It then copies itself to this directory before executing the a new temporary executable with CreateProcess. However, the uninstaller executable does not protect this temporary directory from removal when it has been launched from a privileged context. Additionally, it ignores the ERROR_ALREADY_EXISTS code returned by CreateDirectory, and applies an overly-permissive ACL to the existing directory instead.

This allows users in the Everyone group permission to delete the folder and re-create it with malicious content.

A malicious user could exploit these weaknesses to create a “poisoned” temporary directory containing a payload – which would get executed by the uninstaller. Looking at the nsis-3.08 source code, we can find the following line in Source\exehead\Main.c

On line 352, the program makes a call to UserIsAdminGrpMember and sets the admin variable to the return value. The UserIsAdminGrpMember function calls the shell32!IsUserAnAdmin Windows API function.

This function is simply a wrapper for SHTestTokenMembership, which checks that the user’s token contains the RID 0x220 (i.e. SID S-1-5-32-544 (BUILTIN_ADMINISTRATORS)).

If an uninstaller is launched as SYSTEM, it will pass the UserIsAdminGrpMember function, which the uninstaller.exe process token will contain the administrator SID. Furthermore, its %TEMP% and %TMP% variables will be set to the global C:\Windows\Temp temporary directory (via a call to GetTempPath), which all users have Write access to.

As such, the NSIS code will go on to call the CreateRestrictedDirectory, as the value of admin will be 1 . However, if we look at the code for this function, we can see that the ACL applied using SetFileSecurity includes an ACE which allows Everyone to have DELETE permissions.

Additionally, in the CreateRestrictedDirectory, although the CreateDirectory return code is checked for the ERROR_ALREADY_EXISTS return code, it does not re-create the folder. Instead, it applies the permissive ACL to the existing folder. This means that if the folder already contains malicious content, it will not be removed.

The NSIS uninstaller does attempt to remove any existing Un_X.exe executables from the
~nsuA.tmp folder. However, any other content will be left in place.

There is also a potential TOCTOU issue, since CopyFile is used to write the Un_X.exe file, no exclusive handle is maintained on the file. Therefore an attacker may be able to race between when the file is written with CopyFile and when it is launched with CreateProcess. The attacker could potentially improve their chances of winning this race by using oplocks.

Exploitation

Whilst it is tricky to exploit a race-condition, and DLL Hijacking is generally mitigated by the use of SetDefaultDllDirectories in NSIS – another way to exploit this vulnerability would be to abuse Windows Side-by-Side (WinSxS) assembly loading and DotLocal redirection.

This is a relatively lesser-known technique that allows us to create a DLL hijacking primitive by creating a .local folder in the executable directory. DotLocal abuse has been documented and exploited previously by multiple researchers, and is used in the UACME UAC bypass tool.

As mentioned earlier, an attacker can delete the C:\Windows\Temp\~nsuA.tmp folder and re-create it with their own chosen permissions. Once the folder has been re-created with write permissions, the attacker can create an Un_A.exe.local sub-directory inside the ~nsuA.tmp folder. This will cause Windows to attempt to load SxS assemblies from this folder – which is controlled and write-able by the attacker.

In the following screenshot we can see the Un_A.exe process attempting to open the .local directory under normal usage:

If we delete the ~nsuA.tmp folder, re-create it with weak permissions, and create the .local folder sub-directory described above, we can see it now attempts to open the C:\Windows\Temp\~nsuA.tmp\Un_A.exe.local\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e subdirectory from a .local folder:

If we create the amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_60b5254171f9507e sub-directory too, then it will finally attempt to load the comctl32.dll library, giving the attacker a DLL hijacking primitive:

Therefore, to exploit this issue, an unprivileged attacker simply has to:

  1. Delete any existing C:\Windows\Temp\~nsuA.tmp folder
  2. Recreate the folder with Read/Write permissions
  3. Create the .local SxS redirection subfolder containing a malicious COMCTL32.dll file
  4. Trigger the uninstaller.exe process to run as a privileged (e.g. SYSTEM ) user (this will be product specific – e.g. RPC/COM).

This would give the attacker code execution within the Un_A.exe process, which runs with the same privileges as the uninstaller.exe process.

Proof of Concept

Whilst a full Proof of Concept is not provided, some example code can be found here which shows how to determine the required SxS folder name.

The following screenshot shows the PoC being run against a simple test NSIS package.

  • At 1: the PoC exploit is run, creating the neccessary folder structure.
  • At 2: the folder structure shows ~nsuA.tmp directory, and the .local folder containing the SxS DLL Hijack.
  • At 3: the uninstaller.exe package is run under the SYSTEM account using PSExec (for example purposes).
  • At 4: the DLL hijack is triggered, resulting in a new cmd.exe Window being spawned as SYSTEM.

Affected Software

We have identified multiple products using NSIS where this vulnerability is exploitable and leads to privilege escalation.

If your software package makes use of NSIS versions prior to 3.09 and allows a low-privileged user to initiate an uninstall operation from a privileged context; for example, auto-updaters, or software which uses a service for maintenance tasks (e.g. repairing an application install) – then it is likely be exploitable.

Furthermore, if your software can be (un)installed through a deployment service such MDM or Configuration Management software, then it may also be exploitable via this vulnerability – as many of these products install software packages as SYSTEM.

The Patch

A proposed patch was provided to the NSIS project maintainers, which removed the permissive ACE allowing all users to delete the temporary directory, and added error handling to delete the directory if it already existed.

This was reviewed by the project maintainers and multiple fixes were implemented, which:

  • Creates an isolated temporary directory for each uninstaller process, deleting any existing directories if present.
  • Checks that the temporary directory does not contain a symlink before deleting it.
  • Removes the permissive ACL.

These fixes were released in NSIS version 3.09.

Report Timeline

2023-02-08 - Reported to NSIS Maintainers
2023-02-22 - Confirmation from maintainers, and patch provided for review
2023-05-21 - Initial patch committed to NSIS project
2023-05-30 - Feedback provided by NCC regarding proposed patch
2023-06-03 - Additional hardening added
2023-05-05 - Further feedback provided about patches
2023-06-21 - Additional hardening added
2023-07-01 - NSIS version 3.09 released
2023-07-11 - NCC Group advisory published

About NCC Group

NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate respond to the risks they face. We are passionate about making the Internet safer and revolutionizing the way in which organizations think about cybersecurity.

Published date:  2023-07-11

Written by:  Richard Warren