FortiGuard Labs Threat Research
FortiGuard Labs How-To Guide for Threat Researchers
In the first part of this blog series, we discussed an approach we use here at FortiGuard Labs to find logical bugs on an RPC server using RPCView. As a result, we discovered a potential issue in the Microsoft Universal Telemetry service.
If you have followed the blog series, we discussed finding the RPC APIs that accept strings as their input parameter through RPCView. However, one of the limitations of RPCView is that it will not show RPC services that have not been started automatically by default on Windows—for instance the Data Sharing Service. We were not able to initially identify this service until we used a different approach that will be described in the next section. As it turns out, this service also suffers from a couple of privilege escalation issues that should also be uncovered by our enhanced approach.
Ultimately, Google Security Researcher James Forshaw was able to report four vulnerabilities which were fixed by MSRC last December. So, while using RPCView is still helpful, it is also time consuming as you have to literally audit all of the APIs that accept strings. So we wanted to find other ways to save the time.
We started by analyzing a group of previously discovered bugs that were all very similar. We determined that there is one thing in common among them – they all call the SetNamedSecurityInfo Windows API that allows the program to set specified security information in the security descriptor of a specified object through the object name. For example, the program can specify the filename if it is a file object.
We want to emphasize that this Windows API does not pose any security issues; however, it serves as a filter when we used a static analysis tool that we wrote to search through the RPC services that we wanted to look into. With that knowledge in mind, we created a simple tool that parses all RPC service executables statically in an attempt to look for the Windows APIs of interest to narrow down the number of RPC services that we need to dig into further.
As a result, we found a couple of interesting RPC services. The notorious Storage Service, also known as StorSvc, has multiple privilege escalation issues previously uncovered by other researchers, and the AppX Deployment Server, which was susceptible to a race condition that could eventually lead to privilege elevation. FortiGuard Labs then reported these vulnerabilities to the Microsoft Security Response Centre (MSRC) and they are now fixed and assigned with CVE-2019-0569 and CVE-2019-0766 respectively.
So we will now discuss the process of how we uncovered these vulnerabilities.
[+] Target: appidsvc.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary DACL modification: appidsvc.dll
[+] Target: AppVEntSubsystemController.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: AppVEntSubsystemController.dll
[+] Target: AppXDeploymentServer.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: AppXDeploymentServer.dll
[*] Potential DLL with arbitrary deletion: AppXDeploymentServer.dll
[*] Potential executable with arbitrary file modification with move: AppXDeploymentServer.dll
[*] Potential DLL with arbitrary DACL modification: AppXDeploymentServer.dll
[+] Target: bdesvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: bdesvc.dll
[+] Target: bisrv.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary DACL modification: bisrv.dll
[+] Target: combase.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: combase.dll
[*] Potential executable arbitrary deletion: combase.dll
[+] Target: cryptcatsvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: cryptcatsvc.dll
[*] Potential executable with arbitrary file modification with move: cryptcatsvc.dll
[+] Target: cryptsvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: cryptsvc.dll
[+] Target: dhcpcore.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: dhcpcore.dll
[+] Target: dhcpcore6.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: dhcpcore6.dll
[+] Target: DiagSvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: DiagSvc.dll
[+] Target: diagtrack.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: diagtrack.dll
[*] Potential executable arbitrary deletion: diagtrack.dll
[*] Potential executable with arbitrary file modification with move: diagtrack.dll
[*] Potential DLL with arbitrary DACL modification: diagtrack.dll
[+] Target: DmApiSetExtImplDesktop.dll
[*] Is RPC server file
[+] Target: dot3svc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: dot3svc.dll
[+] Target: dpapisrv.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: dpapisrv.dll
[+] Target: dssvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: dssvc.dll
[*] Potential DLL with arbitrary deletion: dssvc.dll
[*] Potential executable with arbitrary file modification with move: dssvc.dll
[*] Potential DLL with arbitrary DACL modification: dssvc.dll
[+] Target: dusmsvc.dll
[*] Is RPC server file
[+] Target: edgehtml.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: edgehtml.dll
[*] Potential DLL with arbitrary deletion: edgehtml.dll
[*] Potential executable with arbitrary file modification with move: edgehtml.dll
[*] Potential DLL with arbitrary DACL modification: edgehtml.dll
[+] Target: eeprov.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: eeprov.dll
[+] Target: efslsaext.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: efslsaext.dll
[*] Potential executable arbitrary deletion: efslsaext.dll
[+] Target: FXSAPI.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: FXSAPI.dll
[+] Target: FXSSVC.exe
[*] Is RPC server file
[*] Potential executable arbitrary deletion: FXSSVC.exe
[*] Potential DLL with arbitrary deletion: FXSSVC.exe
[*] Potential executable with arbitrary file modification with move: FXSSVC.exe
[+] Target: iphlpsvc.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary DACL modification: iphlpsvc.dll
[+] Target: LogonController.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: LogonController.dll
[+] Target: lsasrv.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: lsasrv.dll
[*] Potential executable with arbitrary file modification with move: lsasrv.dll
[+] Target: mispace.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: mispace.dll
[*] Potential executable arbitrary deletion: mispace.dll
[+] Target: modernexecserver.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary DACL modification: modernexecserver.dll
[+] Target: msdtcprx.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: msdtcprx.dll
[*] Potential executable with arbitrary file modification with move: msdtcprx.dll
[*] Potential DLL with arbitrary DACL modification: msdtcprx.dll
[*] Potential executable with arbitrary file modification with move: msdtcprx.dll
[+] Target: netlogon.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: netlogon.dll
[*] Potential executable with arbitrary file modification with move: netlogon.dll
[+] Target: p2psvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: p2psvc.dll
[+] Target: PackageStateRoaming.dll
[*] Is RPC server file
[+] Target: pcasvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: pcasvc.dll
[*] Potential executable with arbitrary file modification with move: pcasvc.dll
[+] Target: PeerDistSvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: PeerDistSvc.dll
[*] Potential DLL with arbitrary deletion: PeerDistSvc.dll
[*] Potential executable with arbitrary file modification with move: PeerDistSvc.dll
[+] Target: PhoneProviders.dll
[*] Is RPC server file
[+] Target: pla.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary DACL modification: pla.dll
[*] Potential executable arbitrary deletion: pla.dll
[*] Potential DLL with arbitrary deletion: pla.dll
[+] Target: pnrpsvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: pnrpsvc.dll
[+] Target: profsvc.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: profsvc.dll
[*] Potential executable arbitrary deletion: profsvc.dll
[*] Potential DLL with arbitrary DACL modification: profsvc.dll
[+] Target: rasmans.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: rasmans.dll
[*] Potential executable with arbitrary file modification with move: rasmans.dll
[*] Potential DLL with arbitrary DACL modification: rasmans.dll
[+] Target: rdpclip.exe
[*] Is RPC server file
[*] Potential executable arbitrary deletion: rdpclip.exe
[+] Target: scesrv.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: scesrv.dll
[*] Potential DLL with arbitrary DACL modification: scesrv.dll
[+] Target: schedsvc.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: schedsvc.dll
[*] Potential executable arbitrary deletion: schedsvc.dll
[*] Potential DLL with arbitrary DACL modification: schedsvc.dll
[+] Target: SessEnv.dll
[*] Is RPC server file
[*] Potential executable with arbitrary file modification with move: SessEnv.dll
[*] Potential executable arbitrary deletion: SessEnv.dll
[*] Potential DLL with arbitrary deletion: SessEnv.dll
[+] Target: Spectrum.exe
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: Spectrum.exe
[+] Target: spoolsv.exe
[*] Is RPC server file
[*] Potential executable with arbitrary file modification with move: spoolsv.exe
[*] Potential executable arbitrary deletion: spoolsv.exe
[+] Target: sstpsvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: sstpsvc.dll
[+] Target: StorSvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: StorSvc.dll
[*] Potential DLL with arbitrary deletion: StorSvc.dll
[*] Potential DLL with arbitrary DACL modification: StorSvc.dll
[+] Target: sysmain.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: sysmain.dll
[*] Potential executable with arbitrary file modification with move: sysmain.dll
[*] Potential DLL with arbitrary DACL modification: sysmain.dll
[+] Target: SystemEventsBrokerServer.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: SystemEventsBrokerServer.dll
[*] Potential executable with arbitrary file modification with move:
[+] Target: tapisrv.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: tapisrv.dll
[+] Target: taskcomp.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: taskcomp.dll
[*] Potential DLL with arbitrary DACL modification: taskcomp.dll
[+] Target: tellib.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: tellib.dll
[*] Potential executable arbitrary deletion: tellib.dll
[*] Potential executable with arbitrary file modification with move: tellib.dll
[*] Potential DLL with arbitrary DACL modification: tellib.dll
[+] Target: termsrv.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary DACL modification: termsrv.dll
[+] Target: trkwks.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: trkwks.dll
[*] Potential executable with arbitrary file modification with move: trkwks.dll
[+] Target: tttracer.exe
[*] Is RPC server file
[*] Potential executable with arbitrary file modification with move: tttracer.exe
[*] Potential DLL with arbitrary DACL modification: tttracer.exe
[+] Target: uireng.dll
[*] Is RPC server file
[*] Potential executable with arbitrary file modification with move: uireng.dll
[*] Potential DLL with arbitrary deletion: uireng.dll
[*] Potential executable arbitrary deletion: uireng.dll
[+] Target: usermgr.dll
[*] Is RPC server file
[*] Potential executable with arbitrary file modification with move: usermgr.dll
[*] Potential DLL with arbitrary DACL modification: usermgr.dll
[+] Target: vaultsvc.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: vaultsvc.dll
[*] Potential executable arbitrary deletion: vaultsvc.dll
[*] Potential executable with arbitrary file modification with move: vaultsvc.dll
[+] Target: vmrdvcore.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: vmrdvcore.dll
[*] Potential executable arbitrary deletion: vmrdvcore.dll
[*] Potential executable with arbitrary file modification with move: vmrdvcore.dll
[+] Target: w32time.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary DACL modification: w32time.dll
[+] Target: wevtsvc.dll
[*] Is RPC server file
[*] Potential executable with arbitrary file modification with move: wevtsvc.dll
[*] Potential executable arbitrary deletion: wevtsvc.dll
[*] Potential DLL with arbitrary DACL modification: wevtsvc.dll
[+] Target: wiaservc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: wiaservc.dll
[+] Target: wifinetworkmanager.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: wifinetworkmanager.dll
[*] Potential DLL with arbitrary deletion: wifinetworkmanager.dll
[+] Target: wimserv.exe
[*] Is RPC server file
[*] Potential executable arbitrary deletion: wimserv.exe
[*] Potential DLL with arbitrary deletion: wimserv.exe
[+] Target: Windows.Internal.Bluetooth.dll
[*] Is RPC server file
[+] Target: wininit.exe
[*] Is RPC server file
[*] Potential executable arbitrary deletion: wininit.exe
[*] Potential executable with arbitrary file modification with move: wininit.exe
[+] Target: winlogon.exe
[*] Is RPC server file
[*] Potential executable with arbitrary file modification with move: winlogon.exe
[+] Target: wlansvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: wlansvc.dll
[*] Potential executable with arbitrary file modification with move: wlansvc.dll
[+] Target: wwansvc.dll
[*] Is RPC server file
[*] Potential executable arbitrary deletion: wwansvc.dll
[*] Potential executable with arbitrary file modification with move: wwansvc.dll
[+] Target: XblGameSave.dll
[*] Is RPC server file
[*] Potential DLL with arbitrary deletion: XblGameSave.dll
[*] Potential executable arbitrary deletion: XblGameSave.dll
[*] Potential executable with arbitrary file modification with move: XblGameSave.dll
Listing 1: The RPC executable files filtered by the static parser
When analysing the output of our parser, as shown in Listing 1, it pointed out the StorSvc.dll that contained our desired import APIs. Upon reversing the DLL component, we came across this interface: BE7F785E-0E3A-4AB7-91DE-7E46E443BE29 When reversing one of its exposed RPC APIs, we found an interesting RPC API named, SvcSetStorageSettings. This came to our attention because this API involves creating a couple of Windows directories with predictable folder names. When the right parameters are passed to this API, the following folders will be created on the root directory of the external storage drive volume:
Astute readers might have noticed that these are the same default folders found under the user account profile root directory (i.e.: %USERPROFILE%). However, the catch is that these folders will only be created by the RPC API if an external hard disk drive volume exists. When the RPC API is triggered, you can see the Process Monitor output similar to the one shown in the screenshot below:
Figure 1: SvcSetStorageSettings creates multiple hardcoded folders
Looking at the Process Monitor output, we can see that this RPC API is susceptible to symbolic link attacks as it creates some predictable directories. From the Process Monitor call-stack information, we can pinpoint the function routines involved in a particular CreateFile event. When looking into the relevant function routines, we quickly identified issues in StorageService::CreateStorageCardDirectory, which had a missing impersonation when creating files and folders accessible by authenticated users. The problem is that it allowed an attacker to modify the ACL of an arbitrary file object specified through symlink.
Let’s look at the following code snippet:
StorageService::CreateStorageCardDirectory()
{
dwFileAttributes = GetFileAttributesW(&FileName);
if ( dwFileAttributes != -1 && !(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) // -- (1)
{
DeleteFileW(&FileName);
dwFileAttributes = -1;
}
if (CreateDirectoryW(&FileName, lpSecurityAttributes) ) // -- (2)
{
if (dwFileAttributes != -1 && (ExistingFileAttributes | 0x10) != (dwFileAttributes & 0xFFFFFFDF) )
SetFileAttributesW(&FileName, ExistingFileAttributes | 0x10)
}
else if (GetLastError() == ERROR_ALREADY_EXISTS)
{
result = SetNamedSecurityInfoW(&FileName, SE_FILE_OBJECT, SECURITY_DACL_INFORMATION, 0, 0, NewAcl, 0); // -- (3)
boolSetNameddSecInfo = result < 0;
if ( result > 0 )
{
result = (unsigned __int16)result | 0x80070000;
boolSetNameddSecInfo = result < 0;
}
if (!boolSetNameddSecInfo)
{
dwFileAttributes = GetFileAttributesW(&FileName);
SetFileAttributesW(&FileName, ExistingFileAttributes | 0x10)
}
}
}
Listing 2: Offending StorageService::CreateStorageCardDirectory missing impersonation
If the attacker has successfully created a symlink redirecting the FileName to the attacker’s desired file object, the ACL of the redirected file object can be modified at the code path in label (3) using the NewAcl - which is the ACL of the currently logged in user.
Before the symlink attack takes place, we need to tackle the conditional checks in labels (1) and (2). In a nutshell, we determined that the conditional checks in (1) and (2) will delete the file and attempt to create the directory with the same name if a file name collision happens. The caveat is that before the directory creation, it executes DeleteFileW that will delete the symlink pointing to our target file. So how do we prevent the symlink from being deleted?
As it turns out, it can be easily circumvented if the FileName has an exclusive file handle opened by the caller process. The execution will then continue even if DeleteFileW call fails with error access denied as there is no error check upon returning from the API call.
After we have setup the symlink pointing to our target file, and also created an exclusive handle on the target file, we can trigger SvcSetStorageSettings to modify the ACL of the arbitrary file object. The result of the PoC in the following screenshot illustrates how the vulnerability in SvcSetStorageSettings allows us to modify the ACL of the file located in the Windows directory that should be prohibited from modification by non-privileged users:
Figure 2: Result of exploiting SvcSetStorageSettings RPC API
Moving on to the parser output, we found another Windows AppX Deployment Service which suffered from the same symlink attack vulnerability, also due to the lack of impersonation.
During the installation of the AppX package downloadable from the Microsoft Store, we realized that the AppX Deployment Service saves the AppX package executable files and its corresponding resources in the following predictable file path:
As a result, the same symlink attack could occur if the service was going to modify the ACL on the files it dropped at the same time. (Notice that the E: drive is the external drive on our test system.) Astute readers may have noticed that this is somewhat similar to the issue described in the previous section. But we first needed to determine the accessibility of this file path.
We can determine the accessibility of files and folders by using the icacls command. It turns out that the currently logged in user has full access to this directory:
C:\>icacls E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData\Local\Packages\Microsoft.MicrosoftMahjong_8wekyb3d8bbwe
E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData\Local\Packages\Microsoft.MicrosoftMahjong_8wekyb3d8bbwe
NT AUTHORITY\SYSTEM:(CR)(F)
NT AUTHORITY\SYSTEM:(OI)(CI)(IO)(CR)(F)
DESKTOP-A7ABC1O\researcher:(CR)(F)
DESKTOP-A7ABC1O\researcher:(OI)(CI)(IO)(CR)(F)
BUILTIN\Administrators:(CR)(F)
BUILTIN\Administrators:(OI)(CI)(IO)(CR)(F)
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Administrators:(I)(OI)(CI)(F)
DESKTOP-A7ABC1O\researcher:(I)(OI)(CI)(F)
C:\>icacls E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData\Local\Packages
E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData\Local\Packages
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Administrators:(I)(OI)(CI)(F)
DESKTOP-A7ABC1O\researcher:(I)(OI)(CI)(F)
C:\>icacls E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData\Local
E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData\Local
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Administrators:(I)(OI)(CI)(F)
DESKTOP-A7ABC1O\researcher:(I)(OI)(CI)(F)
C:\>icacls E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData
E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001\AppData
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Administrators:(I)(OI)(CI)(F)
DESKTOP-A7ABC1O\researcher:(I)(OI)(CI)(F)
C:\>icacls E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001
E:\WpSystem\S-1-5-21-2264505789-2271452246-4192020221-1001
NT AUTHORITY\SYSTEM:(OI)(CI)(F)
BUILTIN\Administrators:(OI)(CI)(F)
DESKTOP-A7ABC1O\researcher:(OI)(CI)(F)
Obviously, a normal user account could manipulate the resources shared by the higher privilege services. There are a couple of ways to verify this issue: as mentioned in the previous blog post, you can use Process Monitor to capture the events during the AppX package installation and from there you can pinpoint the code paths by looking for the SetSecurityFile event. Instead, this time we performed static analysis against the DLL component, AppXDeploymentServer.dll, that contains the implementation of the service’s logics.
We ended up with the following code snippet, which corresponds to the folder creation operations:
// After created its parent directories, try to create E:\WpSystem\<SID>\AppData\Local\Packages\<AppX.PackageName>
if ( CreateDirectoryW(*(LPCWSTR *)(this - 28), 0) ) // -- (1)
v16 = 0;
else
v16 = getlasterror();
v15 = *(void **)(this + 4);
if ( v16 < 0 )
{
v17 = 0x4C8;
goto exit;
}
}
v15 = *(void **)(this + 4);
if ( v16 >= 0 )
{
if ( v13 == 1
|| sub_102335C9(v15)
// Set security descriptor on e:\WPSystem and its sub-directories to allow Administrator and System user access only
|| (v19 = wpsystem_setnamedsecurityinfo((int)v12, *(WCHAR **)(this - 16)),
v15 = *(void **)(this + 4),
v16 = v19,
v19 >= 0) )
{
// Encrypt and compress the files in Appx.Package
v20 = EncryptFile((int)v12, *(WCHAR **)(this - 16)); // -- (2)
v15 = *(void **)(this + 4);
v16 = v20;
if ( v20 >= 0 )
{
// Reset security descriptor on \\?\E:\WpSystem\<SID>\AppData\Local\Packages\<AppX.PackageName> to allow full access
// however, neither no verification is done on the assigned object name therefore it can be replaced with file object instead of directory object and impersonation here
v21 = SetNamedSecurityInfoW(*(LPWSTR *)(this - 28), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, *(PACL *)(this - 20), 0); // -- (3)
Listing 3: AppXDeploymentServer.dll lacks of user impersonation
As you can see in the code snippet in Listing 3, there is a potential race condition between the creation of the AppX package directory labelled in (1) and the setting of its security descriptor via the SetNamedSecurityInfoW labelled in (3), which can allow an adversary to modify the ACL of an arbitrary file object if the race is successful.
To validate this, our goal is to redirect the AppX folder name, the first parameter of SetNamedSecurityInfoW — as indicated by the code in label (3) — to an arbitrary file object of interest through symlink.
Before that happens, however, it is important to take note that the default save location needs to be set to an external drive. In Windows 10, this can be done under the Default Save Locations settings in the Control Panel, but we wanted to do it programmatically. As mentioned in the previous case study, found the SvcSetStorageSettings RPC API, which can be used to change the Default Save Locations directly. But defining RPC interfaces in the program is quite a tedious step, so we wanted a more convenient way to accomplish this.
As it turns out, most of the RPC APIs are wrapped and exported via a single DLL component. What we needed to do is look for this DLL by searching for its RPC UUID within the %WINDIR\SYSTEM32 directory, since most of the wrapped RPC APIs export functions are undocumented and implemented by Windows system components. After we searched through the SvcSetStorageSettings interface using its UUID (i.e. BE7F785E-0E3A-4AB7-91DE-7E46E443BE29), we were led to the StorageUsage.dll, where we found SetStorageSettings undocumented API. As a result, we are able to dynamically call this API using the regular LoadLibrary() and GetProcAddress().
Finally, we prepared the PoC and ran it with Process Monitor to illustrate the race condition, as shown in the following screenshot:
Figure 3: PoC screenshot to illustrate the infinite loop threads
a) Indicates the infinite loop thread operation being executing by our PoC in an attempt to remove the AppX folder created by the code in label (1) in Listing 3
b) Indicates the AppX folder that was created successfully by the AppX Deployment Service
c) Immediately after that, our thread has successfully removed the folder
Figure 4: PoC screenshot to illustrate the operation of modifying ACL
d) At this point, the AppX Deployment Server attempts to modify the security descriptor of the directory and its sub-directories by executing the wpsystem_setnamedsecurityinfo routine. However, the operation was not successful as the file was pending to be removed due to the operation at (a)
e) The operation mentioned at code label (2) in Listing 3 will be executed at this point
Figure 5: PoC screenshot to illustrate the successful exploitation of the race condition
f) Upon winning the race, our PoC would be able to create a symlink to the arbitrary file C:\Windows\system32\license.rtf in the PoC, before the code label (3) in Listing 3 is executed
g) Finally, our target file’s security descriptor is successfully modified by the privileged service
Figure 6: PoC that successfully exploited the race condition to overwrite an arbitrary file object
In this final installment of the blog post series, we have shown you our alternative approach to narrowing down the RPC services that should be looked into in the effort of finding local privilege escalation. This approach has proven to be quite effective so far, as we ended up finding similar vulnerabilities but in different components.
As a result, FortiGuard Labs has released corresponding IPS signatures to detect these issues, MS.RPC.AppXSvc.Privilege.Escalation and MS.RPC.AppXSvc.Privilege.Escalation, to protect our customers in advance.
-= FortiGuard Lion Team =
View the Fortinet Threat Landscape Indices for botnets, malware, and exploits for Q4, 2018.
Learn more about FortiGuard Labs and the FortiGuard Security Services portfolio. Sign up for the weekly FortiGuard Threat Intelligence Briefs.
Learn more about the FortiGuard Security Rating Service, which provides security audits and best practices.
Read more about our Network Security Expert program, Network Security Academy program or our FortiVets program.