Abusing Arbitrary File Deletes to Escalate Privilege and Other Great Tricks (Archive)
September 03, 2024 | Simon ZuckerbraunThis 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:
- Most critical Windows OS files are locked down with DACLs that prevent modification even by
SYSTEM
. Instead, most OS files are owned byTrustedInstaller
, 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 bySYSTEM
!) - Even if you find a file that you can delete as
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:
- The EoP creates a dummy
C:\Config.Msi
and sets an oplock. - The attacker triggers the folder delete vulnerability to delete
C:\Config.Msi
(or moveC:\Config.Msi
elsewhere) in the context ofSYSTEM
(or admin). Due to the oplock, theSYSTEM
process is forced to wait. - Within the EoP, the oplock callback is invoked. The following several steps take place within the callback.
- The EoP moves the dummy
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 locationC:\Config.Msi
becomes available for other purposes (see further). - The EoP spawns a new thread that invokes the Windows Installer service to install the
.msi
, with UI disabled. - The callback thread of the EoP continues and begins polling for the existence of
C:\Config.Msi
. For reasons that are not clear to me, Windows Installer will createC:\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 pollsC:\Config.Msi
to wait for each of these actions to take place. - As soon as the EoP detects that Windows Installer has created
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) theC:\Config.Msi
created by Windows Installer. - The EoP main thread resumes. It repeatedly attempts to create
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. - The EoP watches the contents of
C:\Config.Msi
and waits for Windows Installer to create an.rbs
file there. - The EoP repeatedly attempts to move
C:\Config.Msi
elsewhere. As soon as Windows Installer closes its handle to the.rbs
, the move succeeds, and the EoP proceeds. - The EoP creates
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
. - After the delay and the error action specified in the
.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:
- Create a subfolder,
temp\folder1
. - Create a file,
temp\folder1\file1.txt
. - Set an oplock on
temp\folder1\file1.txt
. - Wait for the vulnerable process to enumerate the contents of
temp\folder1
and try to delete the filefile1.txt
it finds there. This will trigger the oplock. - When the oplock triggers, perform the following in the callback:
a. Movefile1.txt
elsewhere, so thattemp\folder1
is empty and can be deleted. We movefile1.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.
b. Recreatetemp\folder1
as a junction to the\RPC Control
folder of the object namespace. c. Create a symlink at\RPC Control\file1.txt
pointing toC:\Config.Msi::$INDEX_ALLOCATION
. - When the callback completes, the oplock is released and the vulnerable process continues execution. The delete of
file1.txt
becomes a delete ofC:\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.
We would like to thank researcher Abdelhamid Naceri for his great work in developing these exploit techniques, as well as for the vulnerabilities he has been reporting to our program. We look forward to seeing more from him in the future. Until then, you can find me on Twitter at @HexKitchen, and follow the team for the latest in exploit techniques and security patches.