EDITORIAL | May 27, 2020

File-Squatting Exploitation by Example

This will (hopefully) be a short story about a bug I found some time ago while auditing a .NET service from an OEM. It should be interesting as I have yet to find a description of how to exploit a similar condition.

Our service was running as SYSTEM and needed to periodically execute some other utilities as part of its workflow. Before running these auxiliary tools, it would check if the executable was properly signed by the vendor. Something like this:

public void CallAgent()
{
   string ExeFile = "C:\\Program Files\\Vendor\\Util.exe";
   if (!new Signtool().VerifyExe(ExeFile))
       return;
 
    // Execute Agent here
}

This is where it gets interesting. Of course we can’t control anything at that Program Files location, but what is that VerifyExe method doing?

internal class Signtool
    {
        private const string SignToolPath = "C:\\Windows\\Temp\\signtool.exe";
 
        private void ExtractSignTool()
        {
            byte[] signtool = QuatService.Resource1.signtool;
            using (FileStream fileStream = new FileStream("C:\\Windows\\Temp\\signtool.exe", FileMode.Create))
                fileStream.Write(signtool, 0, signtool.Length);
        }
 
        private void DeleteSignTool()
        {
            File.Delete("C:\\Windows\\Temp\\signtool.exe");
        }
 
        private bool Verify(string arg)
        {
            this.ExtractSignTool();
            Process process = new Process();
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            Path.GetDirectoryName(this.GetType().Assembly.Location);
            process.StartInfo.FileName = "C:\\Windows\\Temp\\signtool.exe";
            process.StartInfo.Arguments = arg;         
            process.Start();
            process.WaitForExit();
            this.DeleteSignTool();
            return process.ExitCode == 0 || process.ExitCode == 2;
        }
 
        public bool VerifyExe(string ExeFile)
        {
            return this.Verify("verify /pa \"" + ExeFile + "\"");
        }
 
    }

The code simply extracts a signature verification tool that it has embedded in C:\Windows\Temp as part of its resources, executes it to verify the target executable, and then deletes the tool as if nothing ever happened.

Did you catch the bug? The issue is in the FileMode.Create flag that gets passed as part of the FileStream call used to write the file.

What is object squatting?

I first read about squatting attacks in “The Art of Software Security Assessment” (which I highly recommend by the way). Essentially, squatting is an attack where you create an object before the legitimate application does. You can then manipulate the object and affect the normal behavior of the application. If an application is not careful and attempts to create a named object (such as Mutex, an Event, a Semaphore, etc.) in the global namespace, it might open an existing object instead, because another application could have already created an object with the exact same name. In this case, the Create method will succeed (https://docs.microsoft.com/en-us/windows/win32/sync/object-names):

This same method can be used for file squatting: the application acts as if it has created a file when it has actually opened an existing file.

There are two conditions necessary for this to be exploitable:

  1. The dwCreationDisposition parameter of the
    CreateFile function must be set incorrectly, leading the application to open an
    existing file instead of creating a new one. An incorrect setting is any
    setting except CREATE_NEW.
  2. The location where the file is being created must
    be writeable by potentially malicious users.

So in C/C++ code, if you see a call to CreateFile using CREATE_ALWAYS, it should raise a flag:

In .NET code, FileMode.Create maps to CREATE_ALWAYS:

Exploitation

At this point, we have a confirmed file squatting vulnerability:

  • The service is not using FileMode.CreateNew.
  • The location C:\Windows\Temp is writable by authenticated
    users.

We also have a race condition because there is a time window between when signtool.exe is extracted and when it is executed.

Therefore, we can exploit this vulnerability by leveraging Hardlinks and OpLocks:

The steps would be the following:

  1. Create
    a directory such as C:\Users\Public\Exploit.
  2. Create
    a file named dummy.txt inside the directory.
  3. Place
    payload.exe inside the directory.
  4. Create
    the Hardlink in C:\Windows\Temp\Signtool.exe to point to C:\Users\Public\Exploit\Dummy.txt.
  5. Set
    an OpLock on dummy.txt.
  6. When
    the OpLock triggers, recreate the Hardlink to point to payload.exe (we can do
    this because the file is ours and the ACL hasn’t changed).

Not so fast! If we check the behavior of the vulnerable “QuatService” with ProcMon, we see there are actually five calls to CreateFile instead of just three:

The first CreateFile is used by FileStream to write the signtool to disk. The second, third, and fourth calls are all part of the inner workings of CreateProcess. The final CreateFile is called with delete access in order to erase the file.

At a practical level, because of the short time window, the two additional CreateFile calls from CreateProcess could interfere with our goal. I found that the best settings for reliable, reproducible results were:

  • Use a second OpLock on dummy.txt after the first
    one is hit.
  • Call Sleep(1) to skip the third CreateFile
    (second one from CreateProcess).
  • Attempt to create the Hardlink to payload.exe in
    a loop. This is necessary because the Hardlink creation could fail due to the
    fact the service could still hold the handle from the third CreateFile.

Here is the code for a functional exploit for the vulnerability (tested on Windows 10 19041 and 18363):
https://github.com/IOActive/FileSquattingExample/blob/master/SquatExploit/SquatExploit/SquatExploit.c

Video demo of the exploit working:

The vulnerable service is included in the same GitHub project in case you want to play with it. If you come up with a better approach to increase the reliability of the exploit, please send me a message.

Mitigations

As already discussed, to avoid this situation there are two options:

  1. Use
    CREATE_NEW / FileMode.CreateNew and
    handle the potential error caused by an existing file.
  2. Write
    to a protected filesystem location.

What about the path redirection mitigations?

  • The Hardlink mitigation doesn’t apply here because we’re creating a link to our own file.
  • The SYSTEM %TEMP% change is not implemented yet. Even though this mitigation will definitely fix the vulnerability, it is worth noting that there will be still room for squatting other directories:
    • C:\Windows\Tasks
    • C:\windows\tracing
    • C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys
    • C:\Windows\System32\spool\drivers\color
    • C:\Windows\SysWOW64\Tasks\Microsoft\Windows\PLA\System

References

More on Object Squatting mitigations:

RESEARCH | November 25, 2015

Privilege Escalation Vulnerabilities Found in Lenovo System Update

Lenovo released a new version of the Lenovo System Update advisory (https://support.lenovo.com/ar/es/product_security/lsu_privilege) about two new privilege escalation vulnerabilities I had reported to Lenovo a couple of weeks ago (CVE-2015-8109, CVE-2015-8110). IOActive and Lenovo have issued advisories on these issues.
 

Before digging into the details, let’s go over a high-level overview of how the Lenovo System Update pops up the GUI application with Administrator privileges.
 
Here is a discussion of the steps depicted above:


1 – The user starts System Update by running the tvsu.exe binary which runs the TvsuCommandLauncher.exe with a specific argument. Previously, Lenovo fixed vulnerabilities that IOActive discovered where an attacker could impersonate a legitimate caller and pass the command to be executed to the SUService service through named pipes to gain a privilege escalation. In the newer version, the argument is a number within the range 1-6 that defines a set of tasks within the dll TvsuServiceCommon.dll

 

2 – TvsuCommandLauncher.exe then, as usual, contacts the SUService service that is running with System privileges, to process the required query with higher privileges.

 

3 – The SUService service then launches the UACSdk.exe binary with System privileges to prepare to execute the binary and run the GUI interface with Administrator privileges.

 

4 – UACSdk.exe checks if the user is a normal unprivileged user or a Vista Administrator with the ability to elevate privileges.

 

5 – Depending on user privileges:

 

    • For a Vista Admin user, the user’s privileges are elevated.
    • For an unprivileged user, UACSdk.exe creates a temporary Administrator account with a random password which is deleted it once the application is closed.

The username for the temporary Administrator account follows the pattern tvsu_tmp_xxxxxXXXXX, where each lowercase x is a randomly generated lower case letter and each uppercase X is a randomly generated uppercase letter. A 19-byte, random password is generated.


Here is a sample of a randomly created user:    



6 – Through tvsukernel.exe binary, the main Lenovo System Update GUI application is then run with Administrator privileges. 




BUG 1 : Lenovo System Update Help Topics Privilege Escalation
The first vulnerability is within the Help system and has two entry points by which a user can open an online help topic that starts an instance of Internet Explorer.

1 – The link in the main application interface 

 
 

2 – By clicking on the Help icon 
at top right and then clicking Settings
 

 

 

 
Since the main application Tvsukernel.exe is running as Administrator, the web browser instance that starts to open a Help URL inherits the parent Administrator privileges.
From there, an unprivileged attacker has many ways to exploit the web browser instance running under Administrator privileges to elevate his or her own privileges to Administrator or SYSTEM.
BUG 2 : Lenovo System Weak Cryptography Function Privilege Escalation
Through a more technical bug and exploitable vulnerability, the temporary administrator account is created in specific circumstances related to Step 5b in the overview.
The interesting function for setting the temporary account is sub_402190 and contains the following important snippets of code:
 
 
The function sub_401810 accepts three arguments and is responsible for generating a random string pattern with the third argument length.
 
Since sub_401810 generates a pattern using RAND, the initialization of the seed is based on the addition of current time and rand values and defined as follows:
 
 
 
Once the seed is defined, the function generates the random value using a loop with RAND and division/multiplication with specific values.
 
Rather than posting the full code, I’ll note that a portion of those loops looks like the following:
 
 
 
The first call to this function is used to generate the 10-letter suffix for the Administrator username that will be created as “tvsu_tmp_xxxxxXXXXX”
 
Since it is based on rand, the algorithm is actually predictable. It is possible for an attacker to regenerate the same username based on the time the account was created.
 
To generate the password (which is more critical), Lenovo has a more secure method: Microsoft Crypto API (Method #1) within the function sub_401BE0. We will not dig into this method, because the vulnerability IOActive discovered is not within this function. Instead, let’s look at how Method #2 generates a password, if Method #1 fails.
 
Let’s return to the snippets of code related to password generation:
 
 
 
We can clearly see that if function sub_401BE0 fails, the execution flow fails back using the custom RAND-based algorithm (defined earlier in function sub_401810) to generate a predictable password for the temporary Administrator account. In other words, an attacker could predict the password created by Method #2.
 

This means an attacker could under certain circumstances predict both the username and password and use them to elevate his or her privileges to Administrator on the machine.