And another Steam Windows Client Local Privilege Escalation 0day

In the previous series



Not so long ago I published a description of the vulnerability for Steam. I got a lot of feedback from readers. Valve did not say a word, and HackerOne sent a huge tearful letter and, basically, was silent. As a result, I was banned by Valve on H1 - I can’t participate in their program to reject vulnerabilities (the rest of H1 is available to me).







You can learn more about the story in a previous publication, here I’ll say a few words about the current status.



And it's simple and sad - Valve still fails. The latest update, which was designed to fix the problem, is easily bypassed and the vulnerability is still relevant. Yes, I checked it - it works great.



But this article is not about the fact that the old vulnerability is still present, but about the new one. Since Valve once again expressed a desire to read a public report, instead of a private one, we will not deprive them of this pleasure.



Vulnerability Brief



The general description of exploitation of the vulnerability is quite simple and consists of three steps:



  1. We prepare the environment for operation (as many as two ways to choose, using different security flaws).
  2. Make Steam copy and run our dll.
  3. Dll should meet small requirements.


All these actions can be performed by any user of the OS, or more precisely, any program on the computer. As a result, you can execute any code with maximum privileges ; this class of vulnerabilities is called escalation of privileges (eop) or local privilege escalation (lpe). Despite the fact that any application may in itself do some harm, obtaining maximum rights will lead to much more significant consequences. Turning off the antivirus and firewall, installing a rootkit, hiding the miner process, stealing the personal data of all PC users is only a small part of what you can think of.



Theoretical minimum



It was very funny to observe the comments on the previous article, where people wrote “The user cannot write registry keys in HKLM” or “Administrator rights are needed to create a symlink”. Interestingly, checking these allegations will hardly take longer than writing such a comment. And, yes, just in case: both statements are false. Therefore, in this article I decided to make a small section where I described a number of difficult moments from operation.



“You cannot write to the HKLM registry key”



There is no such general rule. There are specific security rules for specific registry keys. Valve set full access rights for all users to the HKLM \ SOFTWARE \ Wow6432Node \ Valve \ steam branch, and therefore, any user can do whatever he wants in this branch.



“You cannot start or stop a service without administrator rights”



There is no such general rule. There are specific security rules for specific services. Valve set the rights so that the Steam Client Service can be started and stopped by any user.



“To create a symlink, you need administrator rights”



This in itself is a funny question, given that of the 5 main types of links in Windows, only one and a half require these rights. So, meet: file symbolic link, object directory symbolic link, hard link, NTFS reparse point and reg_link. Administrator rights are needed only to create a file symbolic link and for a permanent object directory symbolic link (the temporary one lives exactly as long as the session in which it is created lives, in the general sense, until reboot, and does not require special rights).



Simlink from folder to folder



This is called an NTFS reparse point or NTFS mount point. The name is not particularly important, the fact is that this thing allows you to use one folder as a pointer to another. It can be created by an ordinary user from an empty folder if he has Write rights to it. For creation, we will use the CreateMountPoint.exe utility from a set of utilities for testing working with links .



Leaving Lock



Outgoing blocking ( OpLock or Opportunistic Lock ) is a special mechanism in which one application can temporarily block everyone from accessing a certain file resource. Here you can write a lot of all sorts of details, features of working with folders and different accesses. The bottom line is: the program can "catch" the event of accessing a certain file and hold it for a while. You can install oplocks using the SetOpLock.exe utility from the same test suite for working with links . Running the utility installs the required unlock; when access occurs, the utility writes a message; pressing enter removes the unlock.



Baitandndswitch



This is the name of the technique, which combines the creation of links and the installation of oplos to win TOCTOU (time of check \ time of use). The essence is easier to explain with an example.



Imagine that there is some program that does something like this in a row:



ReadContentFromFile(“C:\test\myfile.txt”); ReadContentFromFile(“C:\test\myfile.txt”);
      
      





It is just reading the same file two times in a row. Will the same always be read? No, not necessarily.



First, create two folders with the files C: \ test1 \ myfile.txt and C: \ test2 \ myfile.txt. And in general we will clear the C: \ test folder and create a reparse point on C: \ test1. Put the unlock on the file from the first directory and run the program. As soon as she opens the file, the unlock will work. We will change the reparse point and C: \ test will point to C: \ test2. Now, after the unlock is removed, the program will read the file a second time from another file.



Why is this needed? Very simple - a fairly typical situation where the file is first checked (first read) and then launched (second read). This is how we send one file for verification, and another for execution.



Now everything is ready for operation.



Operation 1. Preparing the environment



It is necessary to prepare a little work environment. To begin with, you need to take the executable files CreateMountPoint.exe and SetOpLock.exe.



Now we need to make small changes to the file structure of Steam. Our task is to get a folder with two files Steam.exe and steamclient.dll and the obligatory absence of the bin folder. There are two ways to do this.



Method 1



Rename \ delete the bin folder from the main Steam folder. That's all, you're great (Steam during installation gives any user the rights to everything in his folder).



Method 2



In the registry key HKLM \ SOFTWARE \ Wow6432Node \ Valve \ steam change the InstallPath parameter to some of our folder. In this folder, drop Steam.exe and steamclient.dll from the main folder of Steam.



Suppose we prepared the C: \ Steam folder in any of the ways (the path can be any, but in the examples I will use this). Now create another folder b1, b2, b3 and b4 in it. In the first three, we’ll upload the steamservice.dll file (from the Steam kit, in the original it was in the bin folder), and in the b4 folder we’ll drop the specially formed library with the same name - steamservice.dll. Details on the preparation of the library will be in paragraph 3.



We open two windows of the console. This completes the preparation of the environment.



Operation 2. Replacing the file



I think that from the preparations it has already become clear that there will be something like the BaitAndSwitch described above.



Screenshot from ProcMon:







This is part of the typical launch of the Steam Client Service. Note the part where the dll is first copied to C: \ Program Files (x86) \ Common Files \ Steam, and then loaded. We will make sure that our library is copied from C: \ Steam \ b4. Unfortunately, checks are first conducted, including the signature of the library, so that it cannot be replaced (oh, irony).



So, I will sign in steps. Steps are combined into groups of similar actions. For each step, it will be indicated where what to launch and what happens (I called the different console windows cmd1 and cmd2).



  1. Create the folder C: \ Steam \ bin and in cmd1 execute:

    CreateMountPoint.exe C: \ Steam \ bin C: \ Steam \ b1
  2. In cmd1 we put the oplock:

    SetOpLock.exe C: \ Steam \ b1 \ steamservice.dll
  3. We start the Steam Client Service, we see in cmd1 that we caught access to the file.



    ***
  4. Delete C: \ Steam \ bin, create the C: \ Steam \ bin folder in its place and in cmd2 execute:

    CreateMountPoint.exe C: \ Steam \ bin C: \ Steam \ b2
  5. In cmd2 we put the oplock:

    SetOpLock.exe C: \ Steam \ b2 \ steamservice.dll
  6. In cmd1 we release the unlock, we see that cmd2 has caught access to the file.



    ***
  7. Delete C: \ Steam \ bin, create the C: \ Steam \ bin folder in its place and execute cmd1:

    CreateMountPoint.exe C: \ Steam \ bin C: \ Steam \ b3
  8. In cmd1 we put the oplock:

    SetOpLock.exe C: \ Steam \ b3 \ steamservice.dll
  9. In cmd2 we release the unlock, we see that cmd1 has caught access to the file.



    ***
  10. Delete C: \ Steam \ bin, create the C: \ Steam \ bin folder in its place and execute cmd2:

    CreateMountPoint.exe C: \ Steam \ bin C: \ Steam \ b2
  11. In cmd2 we put the oplock:

    SetOpLock.exe C: \ Steam \ b2 \ steamservice.dll
  12. In cmd1 we release the unlock, we see that cmd2 has caught access to the file.



    ***
  13. Delete C: \ Steam \ bin, create the C: \ Steam \ bin folder in its place and execute cmd1:

    CreateMountPoint.exe C: \ Steam \ bin C: \ Steam \ b3
  14. In cmd1 we put the oplock:

    SetOpLock.exe C: \ Steam \ b3 \ steamservice.dll
  15. In cmd2 we release the unlock, we see that cmd1 has caught access to the file.



    ***
  16. Delete C: \ Steam \ bin, create the C: \ Steam \ bin folder in its place and execute cmd2:

    CreateMountPoint.exe C: \ Steam \ bin C: \ Steam \ b4
  17. In cmd1 we release the unlock


Although it looks complicated, in fact the idea is simple: from 6 accesses to the file C: \ Steam \ bin \ steamservice.dll the first 5 times the original files from different folders were given (in the order of access: b1, b2, b3, b2, b3), and for the sixth time a file with a payload was given for copying.



Schematically, I depicted it like this:





On the left is normal behavior, on the right is exploit behavior.



Operation 3. Implemented Library



For the payload, I first used my most typical dll, which in DllEntry creates an interactive console. Since the code from the dll will be executed in the context of the Steam Client Service, it will be executed with the same rights as the service itself - NT AUTHORITY \ SYSTEM. But as a result of operation, the console did not appear.



After the download, the Steam service still realizes that they slipped a linden up to it, and shuts down, so the payload from my dll did not manage to be executed.



I had to turn around a bit, and it turned out that the service after loading the dll checks the existence of functions



 int WINAPI SteamService_RunMainLoop() void WINAPI SteamService_Stop()
      
      





in library. Moreover, the service calls the first function, where I decided to put the payload (launching an interactive console with the rights of the service - NT AUTHORITY \ SYSTEM). Now, that's all - we repeat all the steps and get a console with maximum permissions.



Conclusion



You can wrap all this in an exe-file, but, frankly, I don’t really want to bother. I think that a video with a demonstration will be enough ( option with the registry , option with the file system ).

I will not copy here the section "Speculation" from a previous article. Just the facts: the old vulnerability is current, you just read about the new one, Valve still does not want to hear about the problems.



Update (08/22/2019)



At the moment, there are two news:



  1. Beta client received patch fix . I will watch when the update reaches the main client.
  2. Valve has changed the LPE policy . And this is great news!




This article in english.



All Articles