A Windows UAC Bypass using Device Manager

Today while working on a Windows 10 machine, I had the need to open the Device Manager for some hardware maintenance. While opening the Windows Device manager I noticed that there was no UAC prompt when I started it. This was a little strange because the Device Manager exists as a Management Console snap-in in %systemroot%\System32\devmgmt.msc and is launched by mmc.exe.

When you start the Device Manager, mmc.exe is launched with %systemroot%\System32\devmgmt.msc as an argument.

Independently, the Microsoft Management Console requires elevation to run. When you go to run and launch mmc.exe, Windows will ask you to allow elevation using the UAC prompt.

If the Device Manager can be opened without a UAC prompt it means that it was launched with High Integrity level. If this process can be used to spawn other processes, they will be launched with High integrity level too.
It was trivial from here to find a way to open an elevated Command Prompt without being prompted by UAC.
User Access Control on my machine was set to the default value of “Notify me only when apps try to make changes to my computer (default)”
To reproduce this:
1. Go to Start run and type devmgmt.msc. Notice that there is no UAC prompt.
2. Once the Device Manager opens, goto Help > Help Topics
3. This will open up the Microsoft Management Console Help window. Right click any where in the right pane and select View Source
4. This will open notepad (the editor may vary if you have set IE’s source viewer to a different text editor).
5. Using notepad’s File > Open menu, navigate to the System32 directory.
6. Set the File type to “All files (*.*) and right click select “Run as Administrator” on cmd.exe
7. This should launch a elevated Command Prompt without any UAC prompts. You can run whoami /priv to check that you have a lot of privileges available now (disabled but available).
8. The process tree also shows that the cmd.exe that was spawned was started with High Integrity level.
There are several other techniques available on Windows that allow you to bypass UAC and most of them are well documented (see references below).

Please note, according to Microsoft, UAC bypasses are not a security problem as UAC is a convenience feature (more references in that page).

Other UAC Bypass references

1. https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/
2. https://enigma0x3.net/2016/07/22/bypassing-uac-on-windows-10-using-disk-cleanup/
3. https://github.com/hfiref0x/UACME
4. https://habrahabr.ru/company/pm/blog/328008/ [Use Google translate, worth reading]

I will try and find other bypasses and post them here. Till then Happy Hacking!!

psexec using a local admin account to a UAC enabled system

To protect users across the network, Windows UAC imposes token restrictions on local administrators logging in via the network (using the net use \\computer\\c$ share for example). This means that a local administrator will not be able to perform administrative tasks and will not have the ability to elevate to full admin rights.

This works well if you are securing systems. However, during a pentest, hash/password reuse via psexec for example, will fail. Simply because connecting to the C$ admin share to run the psexec service will fail. My friend and systems hacker Anant Shrivastava pointed this out during some testing that he was doing, prompting me to blog about this.

I setup a Windows 7 machine with UAC enabled, an administrative account called “testadmin” with password “testadmin” and used the exploit/windows/smb/psexec exploit module from metasploit to test this in my lab environment and saw the following error:

Microsoft recommends a registry edit to disable UAC remote restrictions. To make this change, follow these steps:

  1. Open the registry editor using the regedit command via Start > Run
  2. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
  3. In the right pane, if the LocalAccountTokenFilterPolicy DWORD value doesn’t exist, create it.
  4. Set its value to 1

The changes take effect immediately. I tried the Metasploit exploit again and voila it worked this time:

This registry change allows Sysinternals Psexec utility to function as well apart from other utilities that require a privileged token on the C$ share (or any other admin share).

Happy Hacking!

Get username from PID in VB.NET

As part of a larger program that I’m writing to work with Windows processes, threads and window objects, I wrote a function that allows you to get the username of the user who owns a given process. As simple as it sounds, there is no straightforward way of obtaining the username given the process id in Windows. You could use a WMI query to get the username from a PID but that is painfully slow especially if you plan on doing enumeration for all the processes running on your system. The faster way is to use the Win32 API.  The primary APIs that are needed to achieve this are:

The flow would be as follows:

  1. Using OpenProcess with the PROCESS_QUERY_INFORMATION access right, you can open a handle to a process. This will fail if you do not have the necessary access levels. For example, a limited user using querying a process owned by NT Authority\System.
  2. Once you have the handle, you can call OpenProcessToken requesting the TOKEN_QUERY access right. This function returns a pointer to a handle that identifies the newly opened access token.
  3. Once you have obtained the handle to the access token, calling GetTokenInformation with the access token handle returns the length of the buffer for the TokenInformation parameter when a null TokenInformation value is passed.
  4. The GetTokenInformation function has to be called again with the length of the buffer obtained from the previous call along with a pointer to the buffer that will be populated via the TokenInformation parameter. The TokenInformation structure can then be cast to a structure that is defined as TOKEN_USER that contains a structure called SID_AND_ATTRIBUTES that defines the SID that represents the user associated with the access token that was passed to GetTokenInformation.
  5. Once the TokenUser variable is populated, we can use the ConvertSidToStringSid function which takes in a SID structure and provides a readable SID value.
  6. This SID value can then be passed to Principal.SecurityIdentifier to be translated to a username using the Principal.NTAccount type.

Here’s the code in VB.NET.

Imports System.Runtime.InteropServices
Imports System.Security
Imports System.ComponentModel

Module ProcessFunctions
 <DllImport("kernel32.dll")> _
 Public Function OpenProcess(processAccess As ProcessAccessFlags, bInheritHandle As Boolean, processId As Integer) As Integer
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function GetTokenInformation(ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS, _
 ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32, ByRef ReturnLength As System.UInt32) As Boolean
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function ConvertSidToStringSid(ByVal psid As IntPtr, ByRef pStringSid As String) As Boolean
 End Function

 <DllImport("kernel32.dll", SetLastError:=True)> _
 Public Function GetExitCodeProcess(ByVal hProcess As IntPtr, ByRef lpExitCode As System.UInt32) As Boolean
 End Function

 Public Structure SID_AND_ATTRIBUTES
   Public Sid As IntPtr
   Public Attributes As Int32
 End Structure

 Public Structure TOKEN_USER
   Public User As SID_AND_ATTRIBUTES
 End Structure

 Enum ProcessAccessFlags
   All = &H1F0FFF
   Terminate = &H1
   CreateThread = &H2
   VirtualMemoryOperation = &H8
   VirtualMemoryRead = &H10
   VirtualMemoryWrite = &H20
   DuplicateHandle = &H40
   CreateProcess = &H80
   SetQuota = &H100
   SetInformation = &H200
   QueryInformation = &H400
   QueryLimitedInformation = &H1000
   Synchronize = &H100000
 End Enum

 Enum TOKEN_INFORMATION_CLASS
   TokenUser = 1
   TokenGroups
   TokenPrivileges
   TokenOwner
   TokenPrimaryGroup
   TokenDefaultDacl
   TokenSource
   TokenType
   TokenImpersonationLevel
   TokenStatistics
   TokenRestrictedSids
   TokenSessionId
   TokenGroupsAndPrivileges
   TokenSessionReference
   TokenSandBoxInert
   TokenAuditPolicy
   TokenOrigin
 End Enum

Public Function GetUsernameFromProcessID(pid As Long) As String
  Dim phnd As Integer = OpenProcess(ProcessAccessFlags.QueryInformation, False, pid)
  If phnd <> 0 Then
    Dim Thnd As Integer
    OpenProcessToken(phnd, Principal.TokenAccessLevels.Query, Thnd)
    Dim TokenUser As TOKEN_USER
    Dim TokenInfLength As Integer = 0
    Dim sUserSid As String = ""
    Dim TokenInformation As IntPtr

    GetTokenInformation(Thnd, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, TokenInfLength)
    TokenInformation = Marshal.AllocHGlobal(TokenInfLength)
    GetTokenInformation(Thnd, TOKEN_INFORMATION_CLASS.TokenUser, TokenInformation, TokenInfLength, TokenInfLength)

    TokenUser = DirectCast(Marshal.PtrToStructure(TokenInformation, TokenUser.GetType), TOKEN_USER)

    ConvertSidToStringSid(TokenUser.User.Sid, sUserSid)

    Dim username As String = New Principal.SecurityIdentifier(sUserSid).Translate(GetType(Principal.NTAccount)).ToString()
    Return username
 Else : Return "<access denied>"
 End If
End Function
End Module
Add this code as part of your project in a module and access the function using GetUsernameFromProcessID(pid) which will return the username if you have access to the process and “<access denied>” if you don’t.
Happy Hacking!

Volume Mute and SendMessage() Fun

As the owner of the @wincmdfu twitter account, I try and find alternate ways of doing stuff in Windows. I normally have a bunch of batch files, VB script files and powershell cmdlets in a custom folder in %PATH% that I call when required. While listening to some music the other day, I realized there is no shortcut that I know (or have discovered yet) that allows me to mute the Audio on my system. I have a hardware key on the keyboard that mutes the volume, but no command to do this (remotely for example – which is cooler).

Enter the Windows SendMessage API. This is a fantastic API that Windows uses to send messages to windows given the handle of the target window. This window could be in a different process as well. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.

I will be writing about additional fun stuff you can do with the SendMessage API, but for now coming back to my problem statement. SendMessage can be used to send the WM_APPCOMMAND with the APPCOMMAND_VOLUME_MUTE parameter to the current window handle to toggle mute. This can programmatically be put into a Form/console application and run from command line. Here’s my VB.NET code:

[code language=”vb” gutter=”false”]
Public Class Form1

<Runtime.InteropServices.DllImport("user32.dll")> _
Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function

Private Const APPCOMMAND_VOLUME_MUTE As Integer = &H80000
Private Const WM_APPCOMMAND As Integer = &H319

Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SendMessageW(Me.Handle, WM_APPCOMMAND, Me.Handle, APPCOMMAND_VOLUME_MUTE)
End
End Sub
End Class
[/code]

Compile this into an executable called mute.exe, store it in %PATH% and you are done!
Happy Hacking!