Abusing Arbitrary File Deletes to Escalate Privilege and Other Great Tricks (Archive)

September 03, 2024 | Simon Zuckerbraun

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:

  1. Most critical Windows OS files are locked down with DACLs that prevent modification even by 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!)
  2. 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:

  1. The EoP creates a dummy C:\Config.Msi and sets an oplock.
  2. The attacker triggers the folder delete vulnerability to delete 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.
  3. Within the EoP, the oplock callback is invoked. The following several steps take place within the callback.
  4. 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 location C:\Config.Msi becomes available for other purposes (see further).
  5. The EoP spawns a new thread that invokes the Windows Installer service to install the .msi, with UI disabled.
  6. 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 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.
  7. 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) the C:\Config.Msi created by Windows Installer.
  8. 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.
  9. The EoP watches the contents of C:\Config.Msi and waits for Windows Installer to create an .rbs file there.
  10. 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.
  11. 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.
  12. 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:

  1. Create a subfolder, temp\folder1.
  2. Create a file, temp\folder1\file1.txt.
  3. Set an oplock on temp\folder1\file1.txt.
  4. Wait for the vulnerable process to enumerate the contents of temp\folder1 and try to delete the file file1.txt it finds there. This will trigger the oplock.
  5. When the oplock triggers, perform the following in the callback:
    a. Move 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.
    b. Recreate temp\folder1 as a junction to the \RPC Control folder of the object namespace. c. Create a symlink at \RPC Control\file1.txt pointing to C:\Config.Msi::$INDEX_ALLOCATION.
  6. When the callback completes, the oplock is released and the vulnerable process continues execution. The delete of 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.

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.