This version of the blog is preserved for archival purposes only. An updated version of this blog, including links to new PoC code, can be found here.
What do you do when you’ve found an arbitrary file delete as NT AUTHORITY\SYSTEM
? Probably just sigh and call it a DoS. Well, no more. In this article, we’ll show you some great techniques for getting much more out of your arbitrary file deletes, arbitrary folder deletes, and other seemingly low-impact filesystem-based exploit primitives.
The Trouble with Arbitrary File Deletes
When you consider how to leverage an arbitrary file delete on Windows, two great obstacles present themselves:
SYSTEM
. Instead, most OS files are owned by TrustedInstaller
, and only that account has permission to modify them. (Exercise for the reader: Find the critical Windows OS files that can still be deleted or overwritten by SYSTEM
!)SYSTEM
, it needs to be something that causes a “fail-open” (degradation of security) if deleted.A third problem that can arise is that some critical system files are inaccessible at all times due to sharing violations.
Experience shows that finding a file to delete that meets all the above criteria is very hard. When looking in the usual places, which would be within C:\Windows
, C:\Program Files
or C:\Program Data
, we’re not aware of anything that fits the bill. There is some prior work that involves exploiting antivirus and other products, but this is dependent on vulnerable behavior in those products.
The Solution is Found Elsewhere: Windows Installer
In March of 2021, we received a vulnerability report from researcher Abdelhamid Naceri (halov). The vulnerability he reported was an arbitrary file delete in the User Profile service, running as SYSTEM
. Remarkably, his submission also included a technique to parlay this file delete into an escalation of privilege (EoP), resulting in a command prompt running as SYSTEM
. The EoP works by deleting a file, but not in any of the locations you would usually think of.
To understand the route to privilege escalation, we need to explain a bit about the operation of the Windows Installer service. The following explanation is simplified somewhat.
The Windows Installer service is responsible for performing installations of applications. An application author supplies an .msi
file, which is a database defining the changes that must be made to install the application: folders to be created, files to be copied, registry keys to be modified, custom actions to be executed, and so forth.
To ensure that system integrity is maintained when an installation cannot be completed, and to make it possible to revert an installation cleanly, the Windows Installer service enforces transactionality. Each time it makes a change to the system, Windows Installer makes a record of the change, and each time it overwrites an existing file on the system with a newer version from the package being installed, it retains a copy of the older version. In case the install needs to be rolled back, these records allow the Windows Installer service to restore the system to its original state. In the simplest scenario, the location for these records is a folder named C:\Config.Msi
.
During an installation, the Windows Installer service creates a folder named C:\Config.Msi
and populates it with rollback information. Whenever the install process makes a change to the system, Windows Installer records the change in a file of type .rbs
(rollback script) within C:\Config.Msi
. Additionally, whenever the install overwrites an older version of some file with a newer version, Windows Installer will place a copy of the original file within C:\Config.Msi
. This type of a file will be given the .rbf
(rollback file) extension. In case an incomplete install needs to be rolled back, the service will read the .rbs
and .rbf
files and use them to revert the system to the state that existed before the install.
This mechanism must be protected against tampering. If a malicious user were able to alter the .rbs
and/or .rbf
files before they are read, arbitrary changes to the state of the system could occur during rollback. Therefore, Windows Installer sets a strong DACL on C:\Config.Msi
and the enclosed files.
Here is where an opening arises, though: What if an attacker has an arbitrary folder delete vulnerability? They can use it to completely remove C:\Config.Msi
immediately after Windows Installer creates it. The attacker can then recreate C:\Config.Msi
with a weak DACL (note that ordinary users are allowed to create folders at the root of C:\
). Once Windows Installer creates its rollback files within C:\Config.Msi
, the attacker will be able to replace C:\Config.Msi
with a fraudulent version that contains attacker-specified .rbs
and .rbf
files. Then, upon rollback, Windows Installer will make arbitrary changes to the system, as specified in the malicious rollback scripts.
Note that the only required exploit primitive here is the ability to delete an empty folder. Moving or renaming the folder works equally well.
From Arbitrary Folder Delete/Move/Rename to SYSTEM EoP
In conjunction with this article, we are releasing source code for Abdelhamid Naceri’s privilege escalation technique. This exploit has wide applicability in cases where you have a primitive for deleting, moving, or renaming an arbitrary empty folder in the context of SYSTEM
or an administrator. The exploit should be built in the Release configuration for either x64 or x86 to match the architecture of the target system. Upon running the exploit, it will prompt you to initiate a delete of C:\Config.Msi
. You can do this by triggering an arbitrary folder delete vulnerability, or, for testing purposes, you can simply run rmdir C:\Config.Msi
from an elevated command prompt. Upon a successful run, the exploit will drop a file to C:\Program Files\Common Files\microsoft shared\ink\HID.DLL
. You can then get a SYSTEM
command prompt by starting the On-Screen Keyboard osk.exe
and then switching to the Secure Desktop, for example by pressing Ctrl-Alt-Delete.
The exploit contains an .msi
file. The main thing that’s special about this .msi
is that it contains two custom actions: one that produces a short delay, and a second that throws an error. When the Windows Installer service tries to install this .msi
, the installation will halt midway and rollback. By the time the rollback begins, the exploit will have replaced the contents of C:\Config.Msi
with a malicious .rbs
and .rbf
. The .rbf
contains the bits of the malicious HID.DLL, and the .rbs
instructs Windows Installer to “restore” it to our desired location (C:\Program Files\Common Files\microsoft shared\ink\
).
The full mechanism of the EoP exploit is as follows:
C:\Config.Msi
and sets an oplock.C:\Config.Msi
(or move C:\Config.Msi
elsewhere) in the context of SYSTEM
(or admin). Due to the oplock, the SYSTEM
process is forced to wait.C:\Config.Msi
elsewhere. This is done so that the oplock remains in place and the vulnerable process is forced to continue waiting, while the filesystem location C:\Config.Msi
becomes available for other purposes (see further)..msi
, with UI disabled.C:\Config.Msi
. For reasons that are not clear to me, Windows Installer will create C:\Config.Msi
, use it briefly for a temp file, delete it, and then create it a second time to use for rollback scripts. The callback thread polls C:\Config.Msi
to wait for each of these actions to take place.C:\Config.Msi
for the second time, the callback thread exits, releasing the oplock. This allows the vulnerable process to proceed and delete (or move, or rename) the C:\Config.Msi
created by Windows Installer.C:\Config.Msi
with a weak DACL. As soon as the vulnerable process deletes (or moves, or renames) C:\Config.Msi
, the EoP’s create operation succeeds.C:\Config.Msi
and waits for Windows Installer to create an .rbs
file there.C:\Config.Msi
elsewhere. As soon as Windows Installer closes its handle to the .rbs
, the move succeeds, and the EoP proceeds.C:\Config.Msi
one final time. Within it, it places a malicious .rbs
file having the same name as the original .rbs
. Together with the .rbs
, it writes a malicious .rbf
..msi
, Windows Installer performs a rollback. It consumes the malicious .rbs
and .rbf
, dropping the DLL.Note that at step 7, there is a race condition that sometimes causes problems. If the vulnerable process does not immediately awaken and delete C:\Config.Msi
, the window of opportunity may be lost because Windows Installer will soon open a handle to C:\Config.Msi
and begin writing an .rbs
there. At that point, deleting C:\Config.Msi
will no longer work, because it is not an empty folder. To avoid this, it is recommended to run the EoP on a system with a minimum of 4 processor cores. A quiet system, where not much other activity is taking place, is probably ideal. If you do experience a failure, it will be necessary to retry the EoP and trigger the vulnerability a second time.
From Arbitrary File Delete to SYSTEM EoP
The technique described above assumes a primitive that deletes an arbitrary empty folder. Often, though, one has a file delete primitive as opposed to a folder delete primitive. That was the case with Abdelhamid Naceri’s User Profile bug. To achieve SYSTEM
EoP in this case, his exploit used one additional trick, which we will now explain.
In NTFS, the metadata (index data) associated with a folder is stored in an alternate data stream on that folder. If the folder is named C:\MyFolder
, then the index data is found in a stream referred to as C:\MyFolder::$INDEX_ALLOCATION
. Some implementation details can be found here. For our purposes, though, what we need to know is this: deleting the ::$INDEX_ALLOCATION
stream of a folder effectively deletes the folder from the filesystem, and a stream name, such as C:\MyFolder::$INDEX_ALLOCATION
, can be passed to APIs that expect the name of a file, including DeleteFileW
.
So, if you are able to get a process running as SYSTEM
or admin to pass an arbitrary string to DeleteFileW
, then you can use it not only as a file delete primitive but also as a folder delete primitive. From there, you can get a SYSTEM
EoP using the exploit technique discussed above. In our case, the string you want to pass is C:\Config.Msi::$INDEX_ALLOCATION
.
Be advised that success depends on the particular code present in the vulnerable process. If the vulnerable process simply calls DeleteFileA
/DeleteFileW
, you should be fine. In other cases, though, the privileged process performs other associated actions, such as checking the attributes of the specified file. This is why you cannot test this scenario from the command prompt by running del C:\Config.Msi::$INDEX_ALLOCATION
.
From Folder Contents Delete to SYSTEM EoP
Leveling up once more, let us suppose that the vulnerable SYSTEM
process does not allow us to specify an arbitrary folder or file to be deleted, but we can get it to delete the contents of an arbitrary folder, or alternatively, to recursively delete files from an attacker-writable folder. Can this also be used for EoP? Researcher Abdelhamid Naceri demonstrated this as well, in a subsequent submission in July 2021. In this submission he detailed a vulnerability in the SilentCleanup
scheduled task, running as SYSTEM
. This task iterates over the contents of a temp folder and deletes each file it finds there. His technique was as follows:
temp\folder1
.temp\folder1\file1.txt
.temp\folder1\file1.txt
.temp\folder1
and try to delete the file file1.txt
it finds there. This will trigger the oplock.file1.txt
elsewhere, so that temp\folder1
is empty and can be deleted. We move file1.txt
as opposed to just deleting it because deleting it would require us to first release the oplock. This way, we maintain the oplock so that the vulnerable process continues to wait, while we perform the next step.temp\folder1
as a junction to the ‘\RPC Controlfolder of the object namespace.
c. Create a symlink at
\RPC Control\file1.txtpointing to
C:\Config.Msi::$INDEX_ALLOCATION`.file1.txt
becomes a delete of C:\Config.Msi
.Readers may recognize the symlink technique involving \RPC Control
from James Forshaw’s symboliclink-testing-tools. Note, though, that it’s not sufficient to set up the junction from temp\folder1
to \RPC Control
and then let the arbitrary file delete vulnerability do its thing. That’s because \RPC Control
is not an enumerable file system location, so the vulnerable process would not be able to find \RPC Control\file1.txt
via enumeration. Instead, we must start off by creating temp\folder1\file1.txt
as a bona fide file, allowing the vulnerable process to find it through enumeration. Only afterward, just as the vulnerable process attempts to open the file for deletion, we turn temp\folder1
into a junction pointing into the object namespace.
For working exploit code, see project FolderContentsDeleteToFolderDelete
. Note that the built-in malware detection in Windows will flag this process and shut it down. I recommend adding a “Process” exclusion for FolderContentsDeleteToFolderDelete.exe
.
You can chain these two exploits together. To begin, run FolderOrFileDeleteToSystem
and wait for it to prompt you to trigger privileged deletion of Config.Msi
. Then, run FolderContentsDeleteToFolderDelete /target C:\Config.Msi
. It will prompt you to trigger privileged deletion of the contents of C:\test1
. If necessary for your exploit primitive, you can customize this location using the /initial
command-line switch. For testing purposes, you can simulate the privileged folder contents deletion primitive by running del /q C:\test1\*
from an elevated command prompt. FolderContentsDeleteToFolderDelete
will turn this into a delete of C:\Config.Msi
, and this will enable FolderOrFileDeleteToSystem
to drop the HID.DLL
. Finally, open the On-Screen Keyboard and hit Ctrl-Alt-Delete for your SYSTEM
shell.
From Arbitrary Folder Create to Permanent DoS
Before closing, we’d like to share one more technique we learned from this same researcher. Suppose you have an exploit primitive for creating an arbitrary folder as SYSTEM
or admin. Unless the folder is created with a weak DACL, it doesn’t sound like this would be something that could have any security impact at all. Surprisingly, though, it does: it can be used for a powerful denial of service. The trick is to create a folder such as this one:
C:\Windows\System32\cng.sys
Normally there is no file or folder by that name. If an attacker name squats on that filesystem location with an extraneous file or even an empty folder, the Windows boot process is disrupted. The exact mechanism is a bit of a mystery. It would appear that Windows attempts to load the cng.sys
kernel module from the improper location and fails, and there is no retry logic that allows it to continue and locate the proper driver. The result is a complete inability to boot the system. Other drivers can be used as well for the same effect.
Depending on the vulnerability at hand, this DoS exploit could even be a remote DoS, as nothing is required besides the ability to drop a single folder or file.
Conclusion
The techniques we’ve presented here show how some rather weak exploit primitives can be used for great effect. We have learned that:
• An arbitrary folder delete/move/rename (even of an empty folder), as SYSTEM
or admin, can be used to escalate to SYSTEM.
• An arbitrary file delete, as SYSTEM
or admin, can usually be used to escalate to SYSTEM
.
• A delete of contents of an arbitrary folder, as SYSTEM
or admin, can be used to escalate to SYSTEM
.
• A recursive delete, as SYSTEM
or admin, of contents of a fixed but attacker-writable folder (such as a temp folder), can be used to escalate to SYSTEM
.
• An arbitrary folder create, as SYSTEM
or admin, can be used for a permanent system denial-of-service.
• An arbitrary file delete or overwrite, as SYSTEM
or admin, even if there is no control of contents, can be used for a permanent system denial-of-service.