Normal view

There are new articles available, click to refresh the page.
Before yesterdayWindows LPE

CVE-2020-0668 - A Trivial Privilege Escalation Bug in Windows Service Tracing

By: itm4n
14 February 2020 at 00:00

In this post, I’ll discuss an arbitrary file move vulnerability I found in Windows Service Tracing. From my testing, it affected all versions of Windows from Vista to 10 but it’s probably even older because this feature was already present in XP.

TL;DR

Service Tracing is an old feature that I could trace back to Windows XP but it probably already existed in previous versions of the OS. It aims at providing some basic debug information about running services and modules. It can be configured by any local user, simply by editing some registry keys and values under HKLM\SOFTWARE\Microsoft\Tracing.

A service or module is associated to a registry key. Each key contains 6 values (i.e. settings). The 3 values we will focus on are: EnableFileTracing (enable / disable the “tracing”), FileDirectory (set the location of the output log file) and MaxFileSize (set the maximum file size of the log file).

Once EnableFileTracing is enabled, the target service will start writing to its log file in the directory of your choice. As soon as the size of the output file exceeds MaxFileSize, it will be moved (the .LOG extension is replaced by .OLD) and a new log file will be created.

Thanks to James Forshaw’s symbolic link testing tools, the exploit is quite simple. All you need to do is set the target directory as a mountpoint to the \RPC Control object directory and then create two symbolic links:

  • A symbolic link from MODULE.LOG to a file you own (its size must be greater than MaxFileSize).
  • A symbolic link from MODULE.OLD to any file on the file system (e.g.: C:\Windows\System32\WindowsCoreDeviceInfo.dll).

Finally, the file move can be triggered by targeting a service running as NT AUTHORITY\SYSTEM and, the Update Session Orchestrator service can then be leveraged to get arbitrary code execution.

The Tracing Feature for Services

As briefly mentioned before, the Service Tracing feature can be configured by any local user, simply by editing some registry keys and values under HKLM\SOFTWARE\Microsoft\Tracing.

Using AccessChk from the Windows Sysinternals tools suite, we can see that regular Users have Read/Write permissions on almost all the sub-keys.

For the rest of this article, I’ll use the RASTAPI module as an example since it’s the one I leveraged in my exploit. This module is used by the IKEEXT service. Therefore, log events can be easily triggered by initiating dummy VPN connections. The following screenshot shows the default content of the registry key. The exact same values are configured for the other services and modules.

From a local attacker’s standpoint, here are the most interesting values:

Name Possible values Description
EnableFileTracing 0 - 1 Start / Stop writing to the log file.
FileDirectory A String The absolute path of a directory.
MaxFileSize 0x00000000 - 0xffffffff The maximum size of the output log file.

By setting these values, we can:

  • Force a specific service or module to start or stop writing debug information to a log file by setting EnableFileTracing to either 0 or 1.
  • Specify the location of the log file by setting FileDirectory.
  • Specify the maximum size of the output file by setting MaxFileSize.

The only caveat is that we cannot choose the name of the output file since it’s based on the name of the debugged service or module. This issue can be easily addressed using symbolic links though.

The Arbitrary File Move Vulnerability

With all the previous elements of context in mind, the vulnerability can be easily explained.

Case #1: MaxFileSize - Default value

For this first test case, I simply set C:\LOGS as the output directory and enabled the File Tracing.

Now, if we want the target service to start writing to this file, we must generate some events. A very simple way to do so is to initiate a dummy VPN connection using the rasdial command and a PBK file.

It worked! The log file was written by NT AUTHORITY\SYSTEM. Its size is now around 24KB.

Case #2: MaxFileSize - Custom value

In the previous test, we saw that the final size of the output log file was around 24KB. Therefore, this time, we will set MaxFileSize to 0x4000 (16,384 bytes) and restart the test.

The events captured by “Process Monitor” can be summarized as follows:

  1. Basic information about the log file is fetched by the service. We can see that the EndOfFile is at offset 23,906, which is the size of the file at this moment. The problem is that we specified a max file size of 16,384 bytes so, the system will consider that there is no more free space.
  2. SetRenameInformationFile is called with FileName=C:\LOGS\RASTAPI.OLD. In other words, since the existing file is considered as full, it is moved from C:\LOGS\RASTAPI.LOG to C:\LOGS\RASTAPI.OLD.
  3. The service creates a new C:\LOGS\RASTAPI.LOG file and starts writing to it.

The “Move” operation is performed as NT AUTHORITY\SYSTEM. Therefore, it can be leveraged to move a user-owned file to any location on the file system, such as C:\Windows\System32\.

The Exploit

The exploit is simple and can be summarized as follows:

  1. Create (or copy) a file with a size greater than 0x8000 (32,768) bytes.
  2. Create a new directory (C:\EXPLOIT\mountpoint\ for example) and set it as a mountpoint to \RPC Control.
  3. Create the following symbolic links:
    \RPC Control\RASTAPI.LOG -> \??\C:\EXPLOIT\FakeDll.dll (owner = current user)
    \RPC Control\RASTAPI.OLD -> \??\C:\Windows\System32\WindowsCoreDeviceInfo.dll
    
  4. Configure the following values in the registry:
    FileDirectory = C:\EXPLOIT\mountpoint
    MaxFileSize = 0x8000 (32,768‬ bytes)
    EnableFileTracing = 1
    
  5. Trigger RASTAPI related events using the RasDial function from the Windows API.
  6. Trigger the Update Session Orchestrator service to load the DLL in the context of NT AUTHORITY\SYSTEM.

Demo

Links & Resources

CDPSvc DLL Hijacking - From LOCAL SERVICE to SYSTEM

By: itm4n
11 December 2019 at 00:00

A DLL hijacking “vulnerability” in the CDPSvc service was reported to Microsoft at least two times this year. As per their policy though, DLL planting issues that fall into the category of PATH directories DLL planting are treated as won’t fix , which means that it won’t be addressed (at least in the near future). This case is very similar to the IKEEXT one in Windows Vista/7/8. The big difference is that CDPSvc runs as LOCAL SERVICE instead of SYSTEM so getting higher privileges requires an extra step.

CDPSvc DLL Hijacking

Before we begin, I’ll assume you know what DLL hijacking is. It’s probably one of the oldest and most basic privilege escalation techniques in Windows. Besides, the case of the CDPSvc service was already well explained by Nafiez in this article: (MSRC Case 54347) Microsoft Windows Service Host (svchost) - Elevation of Privilege.

Long story short, the Connected Devices Platform Service (or CDPSvc) is a service which runs as NT AUTHORITY\LOCAL SERVICE and tries to load the missing cdpsgshims.dll DLL on startup with a call to LoadLibrary(), without specifying its absolute path.

Therfore, following the DLL search order of Windows, it will first try to load it from the “system” folders and then go through the list of directories which are stored in the PATH environment variable. So, if one of these folders is configured with weak permissions, you could plant a “malicious” version of the DLL and thus execute arbitrary code in the context of NT AUTHORITY\LOCAL SERVICE upon reboot.

Note: the last PATH entry varies depending on the current user profile. This means that you will always see this folder as writable if you look at your own PATH variable in Windows 10. If you want to see the PATH variable of the System, you can check the registry with the following command: reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /V Path.

That’s it for the boring stuff. :sleeping: Now let’s talk about some Windows internals and lesser known exploitation techniques. :smiley:

A Word (Or Maybe Two…) About Tokens And Impersonation

In my previous article, I discussed the specific case of service accounts running without impersonation privileges. As it turns out, it’s not the case of CDPSvc so we will be able to take advantage of this. However, I realize that I didn’t say much about the implications of each impersonation privilege. It’s not overly complicated but I know that it’s easy to overlook this kind of things because there are so many other things to learn.

Since I worked quite a bit on the inner working of tools such as RottenPotato or JuicyPotato, I’d like to share what I learned in an hopefully clear and concise way. If you’re already familiar with these concepts, you may skip to the next part.

Token Types

First things first. Let’s talk about tokens. There are 2 types of tokens: Primary tokens and Impersonation tokens. A Primary token represents the security information of a process whereas an Impersonation token represents the security context of another user in a thread.

  • Primary token: one per process.
  • Impersonation token: one per thread which impersonates another user.

Note: an Impersonation token can be converted to a Primary token with a call to DuplicateTokenEx().

Impersonation Levels

An Impersonation token comes with an impersonation level: Anonymous, Identification, Impersonation or Delegation. You can use a token for impersonation only if it has an Impersonation or Delegation level associated with it.

  • Anonymous: The server cannot impersonate or identify the client.
  • Identification: The server can get the identity and privileges of the client, but cannot impersonate the client.
  • Impersonation: The server can impersonate the client’s security context on the local system.
  • Delegation: The server can impersonate the client’s security context on remote systems.

Impersonation

Regarding the impersonation methods, there are 3 different ways to create a process as a different user in Windows as I far as I know.

This function doesn’t require any specific privilege. Any user can call this function. However you must know the password of the target account. That’s typically the method used by runas.

This function requires the SeImpersonatePrivilege privilege, which is enabled by default (for the LOCAL SERVICE account). As an input, it requires a Primary token.

This function requires the SeAssignPrimaryTokenPrivilege and SeIncreaseQuotaPrivilege privileges, which are both disabled by default (for the LOCAL SERVICE account) but only SeAssignPrimaryTokenPrivilege really needs to be enabled. SeIncreaseQuotaPrivilege will be transperently enabled/disabled during the API call. As an input, it also requires a Primary token.

API function Privilege(s) required Input
CreateProcessWithLogon() None Domain / Username / Password
CreateProcessWithToken() SeImpersonatePrivilege Primary token
CreateProcessAsUser() SeAssignPrimaryTokenPrivilege AND SeIncreaseQuotaPrivilege Primary token

The CDPSvc Case

As you can see on the below screenshot, the process in which CDPSvc runs has the three privileges I’ve just talked about so it can impersonate any local user with CreateProcessWithToken() or CreateProcessAsUser() provided that you have a valid token for this user.

As a conclusion, we have the appropriate privileges to impersonate NT AUTHORITY\SYSTEM. The second thing we need is a valid token but how can we get one of them? :thinking:

Bringing Back An Old Technique From The Dead: Token Kidnapping

In the old days of Windows, all services ran as SYSTEM, which means that when one of them was compromised all the other services and the host itself were also compromised. Therefore Microsoft added some segregation and introduced two other accounts with less privileges: NETWORK SERVICE and LOCAL SERVICE.

Unfortunately, this wasn’t enough. Indeed, if a service running as LOCAL SERVICE was compromised for example, it could execute code in any other service running as the same user account, access its memory space and extract privileged impersonation tokens: this is the technique called Token Kidnapping, which was presented by Cesar Cerrudo at several conferences in 2008.

To counter this attack, Microsoft had to redesign the security model of the services. The main feature they implemented was Service Isolation. The idea is that each service runs with a dedicated Security Identifier (SID). If you consider a service A with SID_A and a service B with SID_B, service A won’t be able to access the ressources of service B anymore because the two processes are now running with two different identities (although it’s the same account).

Here is a quote from MS Blog, Token Kidnapping in Windows.

The first issue to address is to make sure that two services running with the same identity not be able to access each other’s tokens freely. This concern has been mostly addressed with service hardening done in Windows Vista and above. There are some minor changes that would need to be done to strengthen service hardening to close some gaps identified during our investigation of this issue.

OK so, basically, you’re telling me that Token Kidnapping is now useless because of Service Isolation. What’s the point in talking about that then? :unamused:

Well, the fun fact about CDPSvc is that it runs within a shared process so Service Isolation is almost pointless here since it can access the data of almost a dozen services. CDPSvc runs within a shared process by default only if the machine has less than 3.5GB of RAM (See Changes to Service Host grouping in Windows 10). The question is, among all these services, is there at least one that leaks interesting token handles?

Let’s take a look at the properties of the process once again. Process Hacker provides a really nice feature. it can list all the Handles that are open in a given process.

It looks like the process currently has 5 open Handles to Impersonation tokens which belong to the SYSTEM account. How convenient! :sunglasses:

Fine! How do we proceed?! :grin:

A Handle is a reference to an object (such as a Process, a Thread, a File or a Token for example) but it doesn’t hold the address of the object directly. It’s just an entry in an internally maintained table where the “actual” address is stored. So, it can be seen as an ID, which can be easily bruteforced. That’s the idea behind the Token Kidnapping technique.

Token Kidnapping consists in opening another process and then bruteforcing the open Handles by duplicating them inside the current process. For each valid Handle, we check whether it’s a Handle to a Token, if it’s not the case, we go to the next one.

If we find a valid Token Handle, we must check the following:

  • The corresponding account is SYSTEM?
  • Is it an Impersonation token?
  • The Impersonation Level of the token is at least Impersonation?

Of course, because of Service Isolation, this technique can’t be applied to services running in different processes. However, if you are able to “inject” a DLL into one of these services, you can then access the memory space of the corresponding process without any restrictions. So, you can apply the same bruteforce technique from within the current process. And, once you’ve found a proper impersonation token, you can duplicate it and use the Windows API to create a process as NT AUTHORITY\SYSTEM. That’s as simple as that.

No conclusion for this post. I just hope that you learned a few things. Here is the link to my PoC.

Demo

Links & Resources

❌
❌