Introduction Over the past few months, FortiGuard Labs has been working closely with the Microsoft Security Response Centre (MSRC) to address multiple local privilege escalation (LPE) vulnerabilities that we discovered on the Windows platform. One of the most notable LPE vulnerabilities we reported to MSRC was found on the Windows Network Connectivity Assistant (NCA), which is only enabled on the Enterprise or Education versions of Microsoft Windows 10. The nature of this LPE vulnerability had previously been reported to MSRC as proof-of-concept (POC) by James Forshaw, an author and security researcher in Google's Project Zero. However, MSRC decided not to fix it at the time as they believed Windows was not vulnerable to such an attack. In this blog post, I will discuss how to use simple vulnerability modeling to discover this vulnerable LPE code pattern. Process Creation Impersonation Vulnerability Modeling Since the concept of this logical issue is well documented elsewhere, we do not need to reinvent the wheel here. But we do need to identify the common vulnerability pattern. Fortunately, James provided a handy POC which we were able to use as our starting point. Basically, the POC includes simple Remote Procedure Call (RPC) client and server applications that are used to demonstrate how process creation impersonation can lead to privilege escalation. In a nutshell, privilege escalation can happen when the RPC server attempts to impersonate the client and spawns a process at the same time without using an explicit token. If you found it difficult to visualize that problem, you are not alone. Reviewing the following code snippet might help:

extern "C" void TestCreateProcess(handle_t hBinding, int level) { if (RpcImpersonateClient(hBinding) == 0) { STARTUPINFO startInfo = { 0 }; PROCESS_INFORMATION procInfo = { 0 }; HANDLE hToken = nullptr; HANDLE hDuplicateToken = nullptr; startInfo.cb = sizeof(startInfo); WCHAR cmdline[] = L"c:\\windows\

otepad.exe"; if (level == Medium) // -- (1) { // Open and create client impersonated token if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE | TOKEN_QUERY, true, &hToken)) { printf("Error OpenThreadToken: 0x%x

", GetLastError()); } else { if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, nullptr, SecurityImpersonation, TokenPrimary, &hDuplicateToken)) { printf("Error duplicate token (0x%x)

", GetLastError()); } else { LPVOID lpEnv; // Create interactive process startInfo.lpDesktop = _T("winsta0\\default"); if (!CreateEnvironmentBlock(&lpEnv, hDuplicateToken, false)) { printf("Error create env block (0x%x)

", GetLastError()); } else { if (!CreateProcessAsUser(hDuplicateToken, cmdline, cmdline, nullptr, nullptr, false, 0, nullptr, nullptr, &startInfo, &procInfo)) { printf("Error CreateProcessAsUser (0x%x)

", GetLastError()); } else { printf("[+] CreateProcessAsUser: %d

", procInfo.dwProcessId); } DestroyEnvironmentBlock(lpEnv); } CloseHandle(hDuplicateToken); CloseHandle(hToken); } } } else // -- (2) { if (CreateProcess(cmdline, cmdline, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startInfo, &procInfo)) { printf("[+] CreateProcess: %d

", procInfo.dwProcessId); CloseHandle(procInfo.hThread); CloseHandle(procInfo.hProcess); } else { printf("Error creating process: %d

", GetLastError()); } } RpcRevertToSelf(); } else { printf("Error impersonating user

"); } }

Listing 1: Typical RPC server with a vulnerable process creation routine due to a client being impersonated by a server

As you can see in the prologue of the TestCreateProcess() function, the server first impersonates the caller process – typically the client application with lower privilege will trigger this RPC API given that the remaining operation will be executed under the caller context. The code labelled at (1) indicates that the caller would like to run notepad.exe at a medium integrity level. In fact, this branch is used to demonstrate the proper way for a server to create an external process when the client is being impersonated. The interesting part is at label (2), which shows you the wrong way for process creation to take place under impersonation. The code starting from label (2) does nothing more than call the CreateProcess() API. However the problem here is that since the process creation API was called by the server, the new process inherits its token from the server and not the client, regardless of its impersonation state. In conjunction with the infamous symbolic link attacks, one can then hijack user-drive mapping, which is one of the variants of the symlink attacks that could redirect the default root drive (e.g. C: ), to an arbitrary location that is controlled by the attacker. As a result, a fake target executable – in this example notepad.exe – will be spawned with elevated privilege by the server process through the CreateProcess() API. With this information in mind, we are now going to look for similar vulnerable code patterns within Windows. Generally, the approach is very similar to what we had discussed in our RPC bug hunting blog series. In this case, we are going to look for any Windows components that spawn an external process via CreateProcess or ShellExecute API under impersonation. This should be quite straight forward if you have experience in writing static PE parser script using Python. Otherwise, you can write an IDA script to do the same job. I will leave this as exercise for the readers. As a result, we were able to collect a shortlist of Windows components that could be potentially vulnerable to process creation hijacking. Among those shortlisted Windows components, we found two additional Windows services that contain the vulnerable code pattern – namely NcaSvc.dll and rascustom.dll. CVE-2019-1287: Network Connectivity Assistant Service The Network Connectivity Assistant is used to view the current connection status and to gather detailed information that is helpful for troubleshooting failed DirectAccess connections. The NCA was first integrated with the client operating system beginning with Windows 8.

Figure 1: Windows 10 Enterprise with DirectAccess Enabled

DirectAccess is a feature available on the Enterprise or Education versions of Windows 10. This feature can be understood as a VPN-like technology that provides intranet connectivity to client computers when they are connected to the Internet. DirectAccess can be enabled only when the client computers are connected to the Domain Controller from the Windows Server. In other words, DirectAccess connections are designed to connect automatically as soon as the computer connects to the Internet. Under the hood, NCA exposes some RPC interfaces to client applications. During our investigation, we realized that one of its RPC APIs, Rpc_NcaExecuteAndCaptureLogs, is vulnerable to a process creation hijack due to the impersonated client calling the external powershell.exe executable when gathering network diagnostics information on the client machine. In fact, there are multiple PowerShell executables being spawned to generate this network diagnostic information. One of these calls CreateProcessAsUser with an explicitly impersonated token, and it also calls CreateProcess at the same time. This bug was spotted during the latter’s process creation within the NcaScriptLogsStartProcess function. We are not exactly sure why both process creations use the same command line parameters; perhaps the engineer chose to execute administrative PowerShell commands without the impersonation token in order to generate more comprehensive diagnostic information. This vulnerability is now fixed and has been assigned with CVE-2019-1287.

Figure 2: Exploiting DirectAccess Local Privilege Escalation through fake PowerShell