UAC Bypass or a Story of Three Elevations
As part of my job, I study the operating system and software security. Below, I will tell you about a study that resulted in a fully functional exploit of the UAC bypass type (and yes, you’ll find the source code and nice .gif files).
By the way, Microsoft got notified and pretended they were not interested.
GUI UAC bypas
Sure, there are lots of ways to find a vulnerability. The simplest one is to reproduce a known attack but on another target. That’s exactly how I decided to conduct my experiment, to start an application using the file selection menu (save or open commands).
The .gif file shows how this attack looked like in Windows 98. An attacker uses intricate manipulations to start the file opening window and launch Explorer from it.
First, let’s perform a simple test to find out what’s really happening. Let’s start Notepad. On the menu, select Open, then, in the displayed window, go to the following folder: C:\Windows\system32\. However, the window displays only .txt files and folders. To fix this, you only need to type *.* instead of the file name. Thus you will see all the files (in Notepad, it’s even easier — you just need to select the All files filter. The problem is that the filter is not always available and the star symbol will not always work). Let’s browse to Notepad.exe and start it from the context menu.
The results in Process Explorer are predictable:
one process has been started after the other. Typically, in such process inheritance, the child process has the same privilege as its parent. Thus, if we want to start a process with an elevated privilege, we should utilize a process that already has the required privilege level.
Then I thought of the applications that elevate privileges automatically, in other words, applications whose manifests specify the privilege elevation without the UAC dialog box (autoElevate element). In the first experiment, I selected an overused eventvwr.exe (it has already been spotted in UAC bypasses a couple of times).
Everything turned out quite simple. If you click Open Saved Log on the Action menu, the file opening window will be displayed, and that’s exactly what we need.
Here’s what we see after the start of cmd.exe:
I’ve started the console with the administrator privileges without causing the UAC dialog box to open.
This vulnerability type is called the UAC bypass (bypassing the UAC dialog box). There’s an important remark to make: the automatic elevation works only if the user belongs to the administrator group. That’s why exploiting this vulnerability does not elevate the user privileges. Still, the vulnerability is quite dangerous because many Windows users choose the administrator account for everyday work. When a user with the administrator account starts some malware, it will get the administrator privileges and then even NT AUTHORITY\SYSTEM privileges if it needs so, all without any external manifestations. It’s very easy with the administrator privileges.
There’s an excellent project on GitHub https://github.com/hfiref0x/UACME, which contains a collection of virtually all publicly available vulnerabilities of this type. It even specifies the version of Windows, in which the vulnerability was exploited first and in which version it was fixed if ever.
I’m far from being the first to think about such vulnerabilities. Below are two animated images that make two other ways of bypassing the UAC abundantly clear.
Files courtesy of msitpros.com/?p=3692.
I went over various applications and added 18 more ways for this bypass (see below).
Another 18 ways to bypass UAC manually
Warning! Some application versions and editions may not elevate the privileges automatically. The version list is updated from time to time.
Moreover, if a printer is installed, you will most likely discover lots of other ways to open the file selection window from the print-related dialog boxes.
1) Click Help; in the Help window, right-click the work pane and then click View Source; in the Notepad window, click File and then click Open.
2) Click Help; in the Help window, right-click the work pane and then click Print; in the Find Printer window, in the search box, click File and then click Save Search.
3) Click Action and then click Export List.
4) Click Help and then click Help Topics; in the Help window, right-click the work pane and then click View Source; in the Notepad window, click File and then click Open.
5) Click Help and then click Help Topics; in the Help window, right-click the work pane and then click Print; in the Find Printer window, in the search box, click File and then click Save Search.
6) In the left pane, right-click Services (Local) and then click Export List.
7) After you start the program, you will be prompted to select a code. Select any code and click ОК. Click File and then click Font Links; in the displayed window, select Link with Selected Fonts, after that the Save As button will become available.
8) Click Action and then click Open Saved Log.
9) Click Help and then click Help Topics; in the Help window, right-click the work pane and then click View Source; in the Notepad window, click File and then click Open.
10) Click Help and then click Help Topics; in the Help window, right-click the work pane and then click Print; in the Find Printer window, in the search box, click File and then click Save Search.
11) Open the Advanced tab; under Advanced user management, click Advanced. The lusrmgr.msc snap-in will be opened. Click Action and then click Export List.
12) Click Help; in the Help window, right-click the work pane and then click View Source; in the Notepad window, click File and then click Open.
13) Click Help; in the Help window, right-click the work pane and then click Print; in the Find Printer window, in the search box, click File and then click Save Search.
14) Open the Tracing tab and click Browse
15) Open the Tracing tab and click Select DLL
16) In the left pane, click Reports, then click User Defined; on the context menu, click Export List.
17) Click Help and then click Help Topics; in the Help window, right-click the work pane and then click View Source; in the Notepad window, click File and then click Open.
18) Click Help and then click Help Topics; in the Help window, right-click the work pane and then click Print; in the Find Printer window, in the search box, click File and then click Save Search.
Although I now have the administrator console with the administrator privileges, I can hardly name it a vulnerability or an exploit because it still requires deliberate user actions. To make this vulnerability practical, not theoretical, I need to automate the actions.
Automation? A piece of cake! Let’s use AutoIt to quickly cobble together an application that will emulate keystrokes.
WIN-R, eventvwr, ENTER — starts the application
ALT-press-and-release — focuses on the main menu
Right-Down-Down-ENTER — selects the required menu item
C:\windows\system32 ENTER — moves to the required folder
* ENTER — resets the filter
SHIFT-TAB, SHIFT-TAB — shifts focus to the file list
сmd — selects the cmd.exe file
App (context menu button, normally near the right Ctrl and right Alt), down, down, ENTER — selects the Open command
It’s just like a ready-to-use instruction for the BadUSB-Keyboard attack of the Teensy or Rubber Ducky type. Everything’s fine but it’s not woking. More precisely, it’s not always working — unless I run the script with the administrator privilege. But if I start the script with the administrator privileges, where’s an exploit in that?
It all appears to be quite simple: Microsoft uses the UIPI (User Interface Privilege Isolation) technology. In a nutshell, interface interactions are blocked if the initiator’s Integrity Level (IL) is lower than that of the target application. Processes with the administrator privileges have High IL and higher. The application started by a user without elevation has Medium IL. This level does not allow sending most of the messages, emulating a mouse or a keyboard.
So how can one bypass UIPI? Microsoft specifies that it has another fascinating parameter, UIAccess, which can be set in the manifest. If several strict requirements are satisfied, the application will be capable of interacting with other programs’ interfaces. Basically, here are the requirements:
UIAccess=“true” in the manifest.
- The application must have a digital signature and the signing certificate must be recognized by the computer as a trusted one.
The application must be installed in a secure location or deeper. The secure locations are C:\Windows (with some exceptions), C:\Program Files, C:\Program Files (x86).
If you search for files that meet these requirements, you will find, for example, the following application: C:\Windows\system32\osk.exe. It’s the on-screen keyboard. It’s reasonable to think that this application must have access to the program interfaces without requiring the administrator privileges because it can be started by an ordinary user. If we look into this process in Process Explorer, we’ll get an understanding of how it works. When UIAccess=“true”, another automatic elevation happens, specifically, the application’s IL gets elevated. Osk.exe starts with High IL but without the administrator privileges. That’s an interesting case.
We might come up with an idea of trying to copy Osk.exe somewhere else, which still will be considered a secure location. Then we will be able to control this application and all the UIPI bypassing requirements will be satisfied.
I wrote a simple search engine to search in the C:\Windows, C:\Program Files, C:\Program Files (x86) directories for locations to which files can be copied without the administrator privileges. Surprisingly, plenty of such directories were found. Unfortunately, most of them either belong to the C:\Windows exceptions or cannot be written to, only allowing you to start applications. Still, I found two suitable folders:
C:\Program Files\Microsoft SQL Server\130\Shared\ErrorDumps
On the one hand, it’s good as we have something to test. On the other hand, it’s not all good.
The minidump folder appears if the operating system went to a blue screen of death. If no BSOD ever occurred, there will be no such directory. Moreover, by default, the directory cannot be accessed. The administrator must open it at least and only after that it will become available. Considering all this, it’s not an option.
The second folder is better, except that it only appears if you install Microsoft Visual Studio (2017 in this case; if you install some other version, you will see other numbers instead of 130, for example, 120 for MSVS 2015).
Copy osk.exe to the following folder: C:\Program Files\Microsoft SQL Server\130\Shared\ErrorDumps. Let’s see the application’s import table. I selected osksupport.dll from among the imported libraries. This library exports only 2 functions, therefore I can create a fake one.
Let’s assemble a .dll file and copy it to the same location. This will be a .dll injection. Let’s start it and check. The copied osk.exe starts with High IL, the code from the .dll file gets executed.
Let’s add the keystroke automation code to the .dll file (here I’m not using not AutoIt, but rather keybd_event code quickly converted to C++). Everything seems to work. The exploit is almost ready. Let’s run a clean test.
Let’s create a virtual machine with only Visual Studio installed and then write a simple program tp copy osk.exe and the library with a payload. Everything works fine. Let’s start the binary file, and, a moment later, the automation magic will appear on the screen.
That’s what can be really called an exploit because this program bypasses the UAC without any user participation. Certainly, the user sees the actions but these are nuances.
This is just the first version of the exploit, with two elevations (autoElevate and UIAccess). In this version, the user can see that something wrong happens.
I sunk into Windows Internals by M. Russinovich, namely, the chapters that mention UIAccess and UIPI. Suddenly, down there in black and white, it says that UIPI prevents the use of SetWindowsHookEx. But I’ve just bypassed UIPI, which means that I’m able to use this function — that’s even better! I was able to inject the code instead of sending keystrokes. This is the second version of the exploit, with the same elevations but without any visible actions on the screen. The console with high privileges starts almost immediately after the exploit is started.
At this stage, I sent a letter to Microsoft with the vulnerability description, exploit code, and step-by-step explanation. I was slightly surprised by the response of the Support Team: “So it turns out that one needs to have administrator privileges to start the exploit?” I was trying to explain that this was not the elevation from the user to administrator privileges, but the UAC bypass. However, I was not successful.
The last thing that I could also improve was to remove the requirement that the folder must be writeable. For starters, I decided to try an old-fashioned WUSA method.
Overview of file copying using WUSA
Wusa.exe is an application that automatically elevates privileges. To start this application, specify a .cab archive with the /extract switch. WUSA will unpack the file from the archive at the specified location. To create a .cab archive, you can use a standard MakeCab tool.
First, I tried to unpack a random file to C:\windows\system32. I got the Access Denied error. It makes sense, I read long ago that this method was removed. But, just in case, I decided to check it for the location in Program Files. The utility worked and the file got copied. Now it smells of trouble. The requirement that the folder must be writeable in Program Files is being gradually eliminated.
I decided to give up the WUSA method. In Windows 10 (10147), the /extract option was removed from this application. Nevertheless, I did not get discouraged. Based on the WUSA example, I realized that the protection of C:\Windows does not always mean that C:\Program Files is protected. Aside from WUSA, the IFileOperation interface is another method how to copy files without invoking the UAC dialog box.
If started from a secure location, a process with Medium IL (approximately the same as in UIAccess) can use the IFileOperation interface with the automated elevation of privileges.
After that, it was easy. I wrote a code that used the above method (third elevation) and it worked perfectly fine. To be on the safe side, I took a clean virtual machine with the maximum number of updates installed for the latest version of Windows 10 (RS2, 15063). This was particularly important because RS2 fixed a part of the UAC bypasses. With all the updates, my entire sequence of actions worked perfectly. This was the third version of the exploit, with 3 elevations and no special requirements.
The exploit performance has been tested in Windows 8, Windows 8.1 and Windows 10 (RS2, 15063), and it works. With a 99% probability, it will work in earlier versions starting from Windows Vista but the code will require some modifications (another name and export table for .dll at steps 2 and 3). The UAC settings must be set to default and the user whose account starts the initiating program must belong to the group of administrators on this computer.
Step 1. The program starts without asking for the privilege elevation. The program has Medium IL, which allows injecting the code into the explorer.exe process (for example, using SetWindowsHookEx).
Step 2. The code that runs within explorer.exe initiates the file copying using IFileOperation. This is the first automatic elevation: explorer.exe is recognized as a trusted process that’s why it can copy files to Program Files without the UAC confirmation. The osk.exe system file, which was initially located at C:\Windows\system32\osk.exe, can be copied to any folder in Program Files. A library with a payload named osksupport.dll should be copied to the same folder.
Step 3. The osk.exe is started from the folder it was copied to. As all the requirements to provide UIAccess are satisfied, the file has High IL. This is the second automatic elevation of privileges (only the IL is elevated, the program still does not have the administrator privileges). Right after the start, the .dll injection is triggered and, as part of this process, the code from the osksupport.dll is executed. The payload of this library awaits waits for a privileged process to start and then injects the code into it.
Step 4. Any process is started and automatically elevated to the administrator privilege level (for example, eventvwr.exe, note that it’s the third elevation). The code is injected into the process. At this step, the code will be executed with the administrator privileges.
Proof of Concept
PoC includes two parts, .dll (in C++) and .exe (in C#). First, you need to assemble .dll and connect the library as the code resource. Make sure to pay attention to comments in the code.
I deliberately refrain from publishing the ready-to-use binary code. For the same reason, I do not publish the source codes on GitHub.
I’d like to draw your attention to the fact the described vulnerability applies not only to specific applications. Osk.exe and eventvwr.exe are taken only as an example. I could have used some other pair from among about 150 options (5 variants for osk × 30 variants for eventvwr). It seems to me that the very mechanisms of privilege elevation and UAC are broken.