dcsimg
Results 1 to 16 of 16

Thread: Run elevated

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    777

    Run elevated

    I really need some help on this one. When operating remotely and accessing an application that requires UAC elevation (such as VB6), I need to be able to access the elevation window that is presented. UltraVNC and Team Viewer are both capable of doing this, although UltraVNC must be run as a service to accomplish this. I suspect that Team Viewer also must run as a service, but I have not been able to confirm that.

    When I attempt that at the moment, I am presented with a black screen, and I am assuming that is because the UAC window is operating in Session "0" and I am operating in Session "1". Based upon uVNC code that I found on github, this is what I have come up with.
    Code:
    Option Explicit
    
    Private Declare Function WTSGetActiveConsoleSessionId Lib "kernel32.dll" () As Long
    
    Private Const MAX_PATH As Long = 260
    Private Const TH32CS_SNAPPROCESS As Long = 2&
    Private Const MAXIMUM_ALLOWED As Long = &H2000000
    Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Private Const TOKEN_ASSIGN_PRIMARY = &H1
    Private Const TOKEN_DUPLICATE = &H2
    Private Const TOKEN_IMPERSONATE = &H4
    Private Const TOKEN_QUERY = &H8
    Private Const TOKEN_QUERY_SOURCE = &H10
    Private Const TOKEN_ADJUST_PRIVILEGES = &H20
    Private Const TOKEN_ADJUST_GROUPS = &H40
    Private Const TOKEN_ADJUST_DEFAULT = &H80
    Private Const TOKEN_ADJUST_SESSIONID = &H100
    Private Const TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Xor TOKEN_ASSIGN_PRIMARY Xor TOKEN_DUPLICATE Xor TOKEN_IMPERSONATE Xor TOKEN_QUERY Xor TOKEN_QUERY_SOURCE Xor TOKEN_ADJUST_PRIVILEGES Xor TOKEN_ADJUST_GROUPS Xor TOKEN_ADJUST_DEFAULT
    
    Private Type PROCESSENTRY32
        dwSize As Long
        cntUsage As Long
        th32ProcessID As Long
        th32DefaultHeapID As Long
        th32ModuleID As Long
        cntThreads As Long
        th32ParentProcessID As Long
        pcPriClassBase As Long
        dwFlags As Long
        szExeFile As String * MAX_PATH
    End Type
    
    Private Type SECURITY_ATTRIBUTES
        nLength As Long
        lpSecurityDescriptor As Long
        bInheritHandle As Long
    End Type
    
    Enum SECURITY_IMPERSONATION_LEVEL
        SecurityAnonymous
        SecurityIdentification
        SecurityImpersonation
        SecurityDelegation
    End Enum
    
    Enum TOKEN_TYPE
        TokenPrimary = 1
        TokenImpersonation
    End Enum
    
    Private Declare Function CreateToolhelpSnapshot Lib "kernel32" Alias "CreateToolhelp32Snapshot" (ByVal lFlags As Long, ByVal lProcessID As Long) As Long
    Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
    Private Declare Function ProcessFirst Lib "kernel32" Alias "Process32First" (ByVal hSnapShot As Long, uProcess As PROCESSENTRY32) As Long
    Private Declare Function ProcessNext Lib "kernel32" Alias "Process32Next" (ByVal hSnapShot As Long, uProcess As PROCESSENTRY32) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Declare Function WaitForSingleObject Lib "kernel32.dll" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
    Private Declare Function DuplicateTokenEx Lib "advapi32.dll" (ByVal hExistingToken As Long, ByVal dwDesiredAccess As Long, ByVal lpTokenAttributes As Long, ImpersonationLevel As SECURITY_IMPERSONATION_LEVEL, ByVal TokenType As TOKEN_TYPE, phNewToken As Long) As Boolean
    Private Declare Function DuplicateToken Lib "Advapi32" (existing As Integer, impersonation As Integer, ByRef dupe As Integer) As Boolean
    Private Declare Function ProcessIdToSessionId Lib "kernel32" (ByVal dwProcessId As Long, ByRef pSessionID As Long) As Long
    
    Private Sub Command1_Click()
        Const SecurityImpersonation = 2
        Const TokenPrimary = 1
        Dim lRet As Long
        Dim sProcess As String
        Dim winlogonPID As Long
        Dim hProcess As Long
        Dim hPToken As Long
        Dim hUserTokenDup As Long
        Dim sa As SECURITY_ATTRIBUTES
        Dim TokenAccessLevel As Long
        sa.nLength = Len(sa)
        sProcess = "winlogon.exe"
        winlogonPID = FindProcessID(sProcess)
        Debug.Print sProcess & " PID = " & CStr(winlogonPID)
        hProcess = OpenProcess(MAXIMUM_ALLOWED, False, winlogonPID)
        Debug.Print sProcess & " Handle = " & CStr(hProcess)
        TokenAccessLevel = TOKEN_ASSIGN_PRIMARY Xor TOKEN_DUPLICATE Xor TOKEN_IMPERSONATE Xor TOKEN_QUERY Xor TOKEN_QUERY_SOURCE
        lRet = OpenProcessToken(hProcess, TokenAccessLevel, hPToken)
        If lRet = 0 Then
            CloseHandle (hProcess)
            Exit Sub
        End If
        lRet = DuplicateTokenEx(hPToken, TokenAccessLevel, VarPtr(sa.nLength), SecurityImpersonation, TokenPrimary, hUserTokenDup)
        If lRet = 0 Then
            Debug.Print Err.LastDllError
            '1346 = ERROR_BAD_IMPERSONATION_LEVEL
            'Either a required impersonation level was not provided,
            'or the provided impersonation level is invalid.
            CloseHandle (hProcess)
            CloseHandle (hPToken)
        End If
    End Sub
    
    Private Function FindProcessID(ByVal pExename As String) As Long
        Dim ProcessID As Long
        Dim hSnapShot As Long
        Dim uProcess As PROCESSENTRY32
        Dim rProcessFound As Long
        Dim Pos As Integer
        Dim szExename As String
        Dim dwSessionID As Long
        Dim pSessionID As Long
        dwSessionID = WTSGetActiveConsoleSessionId()
        Debug.Print "Current SessionID = " & CStr(dwSessionID)
        ' Create snapshot of current processes
        hSnapShot = CreateToolhelpSnapshot(TH32CS_SNAPPROCESS, 0&)
        ' Check if snapshot is valid
        If hSnapShot = -1 Then
            Exit Function
        End If
        'Initialize uProcess with correct size
        uProcess.dwSize = Len(uProcess)
        'Start looping through processes
        rProcessFound = ProcessFirst(hSnapShot, uProcess)
        Do While rProcessFound
            Pos = InStr(1, uProcess.szExeFile, vbNullChar)
            If Pos Then
                szExename = Left$(uProcess.szExeFile, Pos - 1)
            End If
            Debug.Print szExename
            If LCase$(szExename) = LCase$(pExename) Then
                'Found it
                ProcessID = uProcess.th32ProcessID
                Call ProcessIdToSessionId(ProcessID, pSessionID)
                If pSessionID = dwSessionID Then
                    Exit Do 'Correct ProcessID/SessionID found
                Else
                    'Debug.Print pExename & " SessionID = " & CStr(pSessionID)
                End If
            Else
                'Wrong, so continue looping
                rProcessFound = ProcessNext(hSnapShot, uProcess)
            End If
        Loop
        CloseHandle hSnapShot
        FindProcessID = ProcessID
    End Function
    The uVNC code uses "TOKEN_ASSIGN_PRIMARY|TOKEN_ALL_ACCESS" in both the "OpenProcessToken" and the "DuplicateTokenEx" call. Microsoft defines these variables like this:
    Code:
            public const int STANDARD_RIGHTS_REQUIRED = (0x000F0000);
            public const int TOKEN_ASSIGN_PRIMARY = (0x0001);
            public const int TOKEN_DUPLICATE = (0x0002);
            public const int TOKEN_IMPERSONATE = (0x0004);
            public const int TOKEN_QUERY = (0x0008);
            public const int TOKEN_QUERY_SOURCE = (0x0010);
            public const int TOKEN_ADJUST_PRIVILEGES = (0x0020);
            public const int TOKEN_ADJUST_GROUPS = (0x0040);
            public const int TOKEN_ADJUST_DEFAULT = (0x0080);
            public const int TOKEN_ADJUST_SESSIONID = (0x0100);
     
            public const int TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
                              TOKEN_ASSIGN_PRIMARY |
                              TOKEN_DUPLICATE |
                              TOKEN_IMPERSONATE |
                              TOKEN_QUERY |
                              TOKEN_QUERY_SOURCE |
                              TOKEN_ADJUST_PRIVILEGES |
                              TOKEN_ADJUST_GROUPS |
                              TOKEN_ADJUST_DEFAULT);
    TOKEN_ALL_ACCESS already includes TOKEN_ASSIGN_PRIMARY. But when I use TOKEN_ALL_ACCESS, the OpenProcessToken call produces error #5 (Access is denied). To get that function to work, the TokenAccessLevel had to be reduced to:
    TOKEN_ASSIGN_PRIMARY Xor TOKEN_DUPLICATE Xor TOKEN_IMPERSONATE Xor TOKEN_QUERY Xor TOKEN_QUERY_SOURCE

    Once past that hurdle, then the DuplicateTokenEx call produces error #1346 (ERROR_BAD_IMPERSONATION_LEVEL). Information on this stuff seems to be very limited, and what I do manage to find is often related to older operating systems. But I know it is possible because uVNC does it.

    J.A. Coutts

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,654

    Re: Run elevated

    The UAC dialog opens in the same session but on its secure desktop. Sessions may have multiple desktops.

  3. #3
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: Run elevated

    See this post, but I am not sure if it helps:

    http://www.vbforums.com/showthread.p...urning-off-UAC

  4. #4

  5. #5
    Member
    Join Date
    Aug 2013
    Posts
    54

    Re: Run elevated

    Quote Originally Posted by wqweto View Post
    If remote support tools were easy PSC would be full of wannabe submissions and TeamViewer wouldn't charge a grand for single license. . .

    cheers,
    </wqw>
    TeamViewer now worth the guts of €2 billion apparently!

  6. #6
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,584

    Re: Run elevated

    By the time OP finishes his PoC project he would want to monetize it already and doubt anything will be shared here. I can completely understand him though. . .

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    777

    Re: Run elevated

    Found another bit of code that upgrades the current user token by using a service.
    https://stackoverflow.com/questions/...ated-privilege
    This particular program uses "WTSQueryUserToken", and Microsoft says this about it:
    --------------------------------
    Caution WTSQueryUserToken is intended for highly trusted services. Service providers must use caution that they do not leak user tokens when calling this function. Service providers must close token handles after they have finished using them.
    --------------------------------
    I can get this code to work as a service up to the "DuplicateTokenEx" call, which produces the same 1346 error. I have also confirmed that TeamViewer operates as a service and supports WOL (Wake On LAN).

    J.A. Coutts

  8. #8
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: Run elevated

    Besides running as a service, one other option is running COM EXE as another user, which requires installation-time setup. You can use DCOMCNFG GUI as explained here to start it as another user. You may have to look at your AxEXE by GUID, rather than by name. Right-click(Double-click does nothing), then select Properties-->Identity tab. You can do the same programmatically from an installer, but it's not a simple code. See this link for details.

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    777

    Re: Run elevated

    It turns out that "DuplicateTokenEx" is not needed at all. When run as a service, "WTSQueryUserToken" already returns a Primary Token. I honestly don't know if "DuplicateTokenEx" works at all on modern systems.

    With feedback from gvb6, that token was run through "ImpersonateLoggedOnUser", which I assume gave the token the correct privileges. It was also run through "CreateEnvironmentBlock". This may not be necessary for smaller environments, but it doesn't add that much weight.

    The program attached will run in the IDE as downloaded, but it will produce a 1314 error (ERROR_PRIVILEGE_NOT_HELD). To get it to work, you must compile it to run as a service (RunAsSvc.exe). This is accomplished by changing the "IsService" flag to True before compilation.

    Once compiled, the service can be installed by executing the following command:
    RunAsSvc.exe /I
    Uninstall is accomplished by using /U instead of /I. You can then use the Service Manager (services.msc) to start the service. That starts a 5 second timer, which starts a copy of "NotePad.exe". The service then terminates itself.

    J.A. Coutts
    Note: Requires NTSVC.OCX
    Attached Files Attached Files

  10. #10
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: Run elevated

    There is a typo in the call to CreateProcessAsUser(). You used Xor instead of Or.

  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    777

    Re: Run elevated

    Quote Originally Posted by qvb6 View Post
    There is a typo in the call to CreateProcessAsUser(). You used Xor instead of Or.
    Sorry, but it's not a typo. Microsoft pretty much uses binary characters for their flags, so it really doesn't matter. I have just always done it this way.

    Once again, thank you for the assistance.

    J.A. Coutts

  12. #12

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    777

    Re: Run elevated

    After all that effort, it doesn't do the job. I need temporary system privileges in interactive sessions.

    J.A. Coutts

  13. #13

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    777

    Re: Run elevated

    Now I really don't understand. Experimenting a little, I removed a lot of the code from the "RunAs" function.
    Code:
    Private Function RunAs() As Boolean
        Dim dwSessionID As Long
        Dim hToken As Long
        Dim lEnvBlock As Long
        Dim sa As SECURITY_ATTRIBUTES
        Dim si As STARTUPINFO
        Dim pi As PROCESS_INFORMATION
        Dim lRet As Long
        If IsService Then
            dwSessionID = WTSGetActiveConsoleSessionId()
            lRet = WTSQueryUserToken(dwSessionID, hToken)
            If lRet = 0 Then
                If IsService Then
                    Call LogAccess("WTSQueryUserToken ERROR #" & CStr(Err.LastDllError))
                End If
                Exit Function
            Else
                Call LogAccess("hToken = " & CStr(hToken))
            End If
        Else
            Debug.Print ("hToken = " & CStr(hToken))
        End If
        lRet = CreateProcessAsUser(hToken, 0&, StrPtr(Application), 0&, 0&, False, NORMAL_PRIORITY_CLASS Xor CREATE_UNICODE_ENVIRONMENT, lEnvBlock, StrPtr(CurrentDirectory), si, pi)
        If lRet = 0 Then
            If IsService Then
                Call LogAccess("CreateProcessAsUser ERROR #" & CStr(Err.LastDllError))
            Else
                Debug.Print "CreateProcessAsUser ERROR #" & CStr(Err.LastDllError)
            End If
        Else
            If IsService Then
                Call LogAccess("CreateProcessAsUser Succeeded!")
            Else
                Debug.Print "CreateProcessAsUser Succeeded!"
            End If
        End If
        CloseHandle hToken
        RevertToSelf
        CloseHandle pi.hThread
        CloseHandle pi.hProcess
    End Function
    In the IDE and when compiled as a desktop executable, the function starts NotePad without any token at all. When operating as a service, it uses the token created by "WTSQueryUserToken".

    J.A. Coutts

  14. #14
    Junior Member
    Join Date
    Jun 2017
    Posts
    16

    Re: Run elevated

    Quote Originally Posted by couttsj View Post
    Now I really don't understand. Experimenting a little, I removed a lot of the code from the "RunAs" function.

    /code

    In the IDE and when compiled as a desktop executable, the function starts NotePad without any token at all. When operating as a service, it uses the token created by "WTSQueryUserToken".

    J.A. Coutts
    Did you ever figure this out? did you end up using DuplicateToken after all?

  15. #15

    Thread Starter
    Fanatic Member
    Join Date
    Dec 2012
    Posts
    777

    Re: Run elevated

    Quote Originally Posted by zambuka42 View Post
    Did you ever figure this out? did you end up using DuplicateToken after all?
    I have not been able to get DuplicateToken/DuplicateTokenEx to work. I found a way to bypass the elevation prompt using the Task Scheduler trick, but that is difficult (if not impossible) to set up remotely. So I am still searching for solutions.

    J.A. Coutts

  16. #16
    Junior Member
    Join Date
    Jun 2017
    Posts
    16

    Re: Run elevated

    thanks for the update

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width