Breaking Barriers and Assumptions: Techniques for Privilege Escalation on Windows: Part 2
The number of vulnerabilities that we see through the program provides significant insight into the attack surfaces of each product that we purchase bugs in. These submissions sometimes reveal not only potential variants but also broader architectural flaws. Submitters frequently choose to provide a full exploit with their submission, which can further reveal interesting techniques. Some of these techniques are so versatile that they end up being useful in the exploitation of several products that all share common functionality. The technique discussed in this blog is one such example that we used to uncover and exploit several vulnerabilities.
Due to paywalls and other obstacles, several vendors and products on the market remain untested and may be vulnerable to the weaknesses we are about to share. We strongly recommend that defenders evaluate their products for these potential issues. Additionally, we encourage vendors who do not currently offer free trials to consider making them available, enabling researchers to conduct this type of research.
Using Alternate Data Streams to Bypass Assumptions
The technique we are about to share, introduced to us by researcher Abdelhamid Naceri, involves the use of NTFS streams. These streams allow a user to attach extra data to a file or directory by creating an alternate data stream (ADS). The interesting aspect of these alternate data streams is their relationship with directories. Typically, when a user wants to create an NTFS junction on a directory, the directory must be empty. However, what if a program needs to perform checks on a file before executing a specific operation that we might be interested in exploiting? In such a case it may not be feasible to maintain an empty directory.
That’s where alternate data streams come in. If we instead point the application to an alternate data stream attached to a directory, that directory can be made into a junction at any time! Since the alternate data stream isn’t technically a file inside the directory, the directory can be empty while the program performs any checks it needs to. Then, when the vulnerable file operation is about to occur, a junction can be created since the directory is technically empty. To further explain this technique, we will look at CVE-2024-0353, a privilege escalation vulnerability we discovered and exploited which affects several ESET Security products listed below.
CVE-2024-0353: ESET Smart Security Premium ekrn Link Following Local Privilege Escalation Vulnerability
For this case, we decided to dig into ESET’s real time protection feature. This feature is common to most antivirus solutions and is triggered by placing an infected file anywhere on the filesystem. For the purposes of testing, we can use an EICAR test file to trigger this behavior. (Be aware that some antiviruses we tested reacted differently to an EICAR file as opposed to a legitimately malicious file.) Once a test file has been placed onto the system, the real time protection feature should activate and delete the file. Doing this with ESET Smart Security, we see that the following actions occur:
ekrn.exe, a service run by ESET Smart Security, will initially scan and back up the detected EICAR file. Subsequently, it will open a handle to the EICAR file and modify its file attributes to FILE_ATTRIBUTE_NORMAL. Finally, it will open a new handle, this time with delete access requested, and call NtSetInformationFile to delete it. What immediately stands out is that when the handle is opened with delete permissions, there is nothing done to prevent it from following any links a standard user could create. Because of that, we can attempt to get the delete operation to follow a link and delete C:\Config.msi instead, so that we can escalate our privileges to NT AUTHORITY\SYSTEM.
The first challenge in attempting to do this is timing the creation of the link. If we create it too early, ekrn.exe won't detect the file as malicious. Conversely, if we create it too late, the link won't be followed, and our target directory won't be deleted. Lucky for us, ESET provides us with a good indicator for when the file will be deleted. As seen in the log from Procmon, shortly before the file is deleted, ekrn.exe will change the file attributes to FILE_ATTRIBUTE_NORMAL. By polling the file for attribute changes, we now have a good indicator of when the file will be deleted.
To start our exploit, we can create a new file and use the function SetFileInformationByHandle to set the new files attributes to something other than FILE_ATTRIBUTE_NORMAL. Then we can write an EICAR test string to this new file and close the handle so that it will be detected and deleted. While waiting for the file to be deleted we can repeatedly use GetFileInformationByHandleEx with a new handle to poll the file’s attributes. As soon as the files attributes have been changed to FILE_ATTRIBUTE_NORMAL, we know we can go ahead and create our link, as the file’s about to be deleted.
By default, standard Windows users don’t have the SeCreateSymbolicLinkPrivilege required to create symbolic links directly in the filesystem, so another approach must be used. One place a standard user does have the ability to create symbolic links is in Windows’ Object Manager. In writable object directories such as \RPC CONTROL\ or \BaseNamedObjects\Restricted\, a standard user can create an object manager symbolic link that can point to an arbitrary path. A standard user can then use NTFS junctions to set an empty directory as a mount point for either \RPC CONTROL\ or \BaseNamedObjects\Restricted\. By combining these two links, a standard user can create a path that will have the same behavior as a traditional symbolic link. You may recognize this approach from James Forshaw’s symboliclink-testing-tools.
There is still another issue. The directory we want to use to create the NTFS junction must be empty. This means that once we see our file attributes change, we need to delete the file before setting the directory as a junction. The issue is that once a file has been marked as malicious, ekrn.exe prevents any other process from accessing that file. This is where using the alternate data streams technique comes in. If the file we create is an alternate data stream attached to the directory, we can turn the directory into a junction at any time as it’s technically empty. This will finally allow us to create our link that will be used to delete any file or folder of our choosing.
In summary, our exploit will do the following:
- Create an object manager symbolic link in \BaseNamedObjects\Restricted\ with the same name as the EICAR test file, pointing to C:\Config.Msi::$INDEX_ALLOCATION.
- Create a directory, such as C:\LPE, and create an alternate data stream attached to it.
- Set the file attributes of the alternate data stream to something other than FILE_ATTRIBUTE_NORMAL.
- Write an EICAR test string to the alternate data stream.
- Wait for ESET to change the file attributes to FILE_ATTRIBUTE_NORMAL.
- Create an NTFS junction at C:\LPE pointing to \BaseNamedObjects\Restricted\
- Watch as C:\Config.Msi is deleted by ekrn.exe.
By deleting the `::$INDEX_ALLOCATION` stream of `C:\Config.Msi` which stores the index data associated with the folder, we can effectively delete the folder using this arbitrary file delete primitive. More on that trick can be found here.
Following these steps, we can see in the above log that we are able to create our link and cause ekrn.exe to follow it, resulting in C:\Config.Msi being deleted instead of our EICAR test file! We can use this arbitrary delete to escalate our privileges to NT AUTHORITY\SYSTEM using the techniques described in the previous blog.
Something you will notice in the log shown is that ekrn.exe is impersonating the current user when it performs the delete. Since the standard user does not have permission to delete C:\Config.Msi, why does this succeed? The answer has to do with the function ESET uses when opening a handle to the file. By inspecting the call stack of the CreateFile operation in Procmon, we can get a better idea of what is happening:
We can see in the above log that ekrn.exe uses DeviceIoControl to send a control code to an ESET kernel-mode driver named eamonm.sys. This driver then calls FltCreateFileEx2 to open the handle for the requested file. FltCreateFileEx2 supports various arguments, of which the Flags argument is of particular interest. One of the supported flags is IO_FORCE_ACCESS_CHECK. This flag is of critical importance for security, because if that flag is not specified, the I/O manager will not enforce proper user level access checks. In that case, any impersonation would be ignored.
We can set up a kernel debugging session to determine if the absence of this flag is the root cause of the ignored impersonation. We set a breakpoint on FltCreateFileEx2 and once again place an EICAR file on the computer to trigger a file deletion. This will quickly cause our breakpoint to be hit, where we can inspect the value of the Flags argument:
We see in the shown screenshot that the Flags argument has the value 0x800. The value IO_FORCE_ACCESS_CHECK flag is 0x001, which means it is not set! This explains why impersonation does not stop us from deleting arbitrary files. Impersonation could have stopped ekrn.exe from being able to open C:\Config.Msi, but since it was not implemented properly it did not provide the protection it was supposed to.
We saw this as a common theme amongst the products we audited that used impersonation. There were often flaws with their implementation of impersonation. In some cases, if a file couldn’t be opened due to impersonation, the product would simply either stop impersonating or impersonate higher privileged users (including NT AUTHORITY\SYSTEM) until the file was able to be opened. This behavior defeats the entire purpose of using impersonation.
Let's now delve into another vulnerability that further demonstrates the use of alternate data streams. Unfortunately, this next case, among several others, is being disclosed without a patch.
CVE-2024-7238: (0day) VIPRE Advanced Security SBAMSvc Link Following Local Privilege Escalation Vulnerability
This vulnerability in VIPRE Advanced Security is similar to the one we found in ESET Smart Security, as it involves the same real time protection feature. VIPRE calls this feature Advanced Active Protection. When an infected file is placed on the computer, VIPRE will detect and delete it. We can test it with an EICAR test file as we did with ESET Smart Security:
In this case, VIPRE has a service, SBAMSvc.exe, that is responsible for deleting detected files. The service runs as NT AUTHORITY\SYSTEM. Much like ESET, VIPRE first inspects the file to determine if it’s malicious. If it is, VIPRE will make a backup of it and delete it. When the file is opened with delete access, we see that neither the FILE_FLAG_OPEN_REPARSE_POINT flag nor impersonation is used. Also, we do not see any checks after the file is opened to see if any reparse points have been followed. Altogether, this tells us that if we can create a link before SBAMSvc.exe opens the file for deletion, it should follow that link and delete an arbitrary file. This time, however, we don’t have a convenient gadget that will tell us when the file is going to be opened for deletion.
For us to be able to exploit this vulnerability, we need to be able to create a link before SBAMSvc.exe opens the file with delete access. Again, VIPRE prevents us from accessing the file after it has been detected, so we must use an alternate data stream to create our EICAR file.
If we look at what SBAMSvc.exe does before the file is deleted, we see the following in Procmon:
Highlighted in the shown log is every time SBAMSvc.exe reads from the file before it is deleted. Every time a file is read from or written to, the file’s last access timestamp is updated. We can access this value using the function GetFileInformationByHandleEx. By using this function to query a file’s basic info, we can count how many times the file is read by VIPRE. Once we count four reads from the file, we can create our link, ensuring it is created right before the file is deleted.
Counting the number of file reads in this manner did not result in accurate counts 100% of the time, but it did increase the reliability of our exploit. Using this idea, we were able to create our link at just the right time, as seen in the following logs:
Using this arbitrary file delete we are again able to escalate privileges to NT AUTHORITY\SYSTEM by deleting C:\Config.Msi.
Discoveries
The two cases we detailed illustrate the significant role the ADS technique played in uncovering and exploiting privileged file operations in common functionality across antivirus products. Absent this approach, such exploitation would likely have not been feasible. We also highlighted how impersonation seen in Procmon logs could just be a smokescreen if not implemented correctly.
Below is a list of vulnerabilities we discovered which leveraged alternate data streams:
CVE-2024-0353: ESET Smart Security Premium ekrn Link Following Local Privilege Escalation Vulnerability
CVE-2024-7227: Avast Free Antivirus AvastSvc Link Following Local Privilege Escalation Vulnerability
CVE-2024-7234: AVG AntiVirus Free AVGSvc Link Following Local Privilege Escalation Vulnerability
CVE-2024-7240: F-Secure Total Link Following Local Privilege Escalation Vulnerability
CVE-2024-7238: VIPRE Advanced Security SBAMSvc Link Following Local Privilege Escalation Vulnerability
CVE-2024-4454: WithSecure Elements Endpoint Protection Link Following Local Privilege Escalation Vulnerability
Looking Ahead
The next and final part of this series will discuss one more technique and provide a helpful tool you can use for debugging on Windows. We will also talk about issues we faced with several vendors and their understanding of this class of vulnerabilities. Until then, you can find us on Twitter at @Izobashi and @NZubrisky and the team on Twitter, Mastodon, LinkedIn, or Instagram for the latest in exploit techniques and security patches.