News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Process which is elevated as administrator

Started by Fraile, December 31, 2019, 03:50:59 AM

Previous topic - Next topic

Fraile

Hi all,


I am testing, executing, a process, using the Token, of another process already in memory. The problem is, in function, CreateProcessWithTokenW. It does not end, to execute, the new process.

This same code, on VB.net, if it works.

Code ASM:
This procedure is in a DLL.


.Const

.Data?

.Data

RunProg             DB "D:\MFTRead.exe", 0
PtrRutaNombre      DWord 0

.Code

ElavarPrvilegios Proc
Local Shell:DWord
Local ShellProcessId:DWord
Local hShellProcess:DWord
Local hShellToken:DWord
Local Security:SECURITY_ATTRIBUTES
Local MSi:STARTUPINFO
Local Pinf:PROCESS_INFORMATION
Local hToken:DWord

   ;Get window handle representing the desktop shell.  This might not work if there is no shell window, or when
    ;using a custom shell.  Also note that we' re assuming that the Shell is NOT running elevated.
   Invoke GetShellWindow
   Mov Shell, Eax

   .If Eax != 0


      ;Get the ID of the desktop shell process.
      Invoke GetWindowThreadProcessId, Shell, Addr ShellProcessId

      ;Open the desktop shell process in order to get the process token.
      Invoke OpenProcess, PROCESS_QUERY_INFORMATION, FALSE, ShellProcessId
      Mov hShellProcess, Eax

      .If Eax != 0


         ;Get the process token of the desktop shell.
         Invoke OpenProcessToken, hShellProcess, TOKEN_DUPLICATE, Addr hShellToken

         .If Eax != 0

            ;Duplicate the shell's process token to get a primary token.
            Invoke DuplicateTokenEx, hShellToken, TOKEN_QUERY + TOKEN_ASSIGN_PRIMARY + TOKEN_DUPLICATE + TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_SESSIONID, 0, 2, 1, Addr hToken

            .If Eax != 0

               Mov Eax, SizeOf MSi
               Mov MSi.cb, Eax

;               Invoke GetStartupInfo, Addr MSi
;               Mov MSi.dwFlags, STARTF_USESHOWWINDOW
;               Mov MSi.wShowWindow, 1

;                Invoke GlobalAlloc, GMEM_FIXED, 1024 ; Reservamos un buffer de memoria para nombre de programa a ejecutar.
;                Mov PtrRutaNombre, Eax
;;
;               Invoke MoverDatos, Offset RunProg, Addr PtrRutaNombre, 0, 0, SizeOf RunProg

               ;Invoke MessageBox, NULL, Addr PtrRutaNombre, NULL, MB_OK
               Invoke CreateProcessWithTokenW, hToken, 0, Offset RunProg, NULL, 0, NULL, NULL, Addr MSi, Addr Pinf

               Invoke PasarADecimal, Eax

;                Invoke GlobalUnlock, PtrRutaNombre
;                Invoke GlobalFree, PtrRutaNombre


            .EndIf

         .EndIf

      .EndIf

   .EndIf

   Xor Eax, Eax

   Ret
ElavarPrvilegios EndP


Code VB.NET:

Imports System.Runtime.InteropServices
Public Class Form1
    <DllImport("advapi32.dll", SetLastError:=True)> _
    Private Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
    End Function

    <DllImport("advapi32.dll", SetLastError:=True)> _
    Public Shared 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("User32.dll", SetLastError:=True)> _
    Public Shared Function GetShellWindow() As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, _
                          ByRef lpdwProcessId As IntPtr) As Integer
    End Function

    <DllImport("kernel32.dll")> _
    Private Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
    End Function

    <DllImport("advapi32.dll", SetLastError:=True)> _
    Private Shared Function DuplicateTokenEx( _
    ByVal ExistingTokenHandle As IntPtr, _
    ByVal dwDesiredAccess As UInt32, _
    ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, _
    ByVal ImpersonationLevel As Integer, _
    ByVal TokenType As Integer, _
    ByRef DuplicateTokenHandle As System.IntPtr) As Boolean
    End Function

    <DllImport("advapi32.dll", SetLastError:=True)> _
    Private Shared Function LookupPrivilegeValue(ByVal lpSystemName As String, _
   ByVal lpName As String, ByRef lpLuid As LUID) As Boolean
    End Function

    ' Use this signature if you want the previous state information returned
    <DllImport("advapi32.dll", SetLastError:=True)> _
    Private Shared Function AdjustTokenPrivileges( _
    ByVal TokenHandle As IntPtr, _
    ByVal DisableAllPrivileges As Boolean, _
    ByRef NewState As TOKEN_PRIVILEGES, _
    ByVal BufferLengthInBytes As Integer, _
    ByRef PreviousState As TOKEN_PRIVILEGES, _
    ByRef ReturnLengthInBytes As Integer _
  ) As Boolean
    End Function

    <DllImport("advapi32", SetLastError:=True, CharSet:=CharSet.Unicode)>
    Public Shared Function CreateProcessWithTokenW(ByVal hToken As IntPtr, ByVal dwLogonFlags As Integer, ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal dwCreationFlags As Integer, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As IntPtr, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
    End Function

    <StructLayout(LayoutKind.Sequential)> _
    Structure SECURITY_ATTRIBUTES
        Public nLength As Integer
        Public lpSecurityDescriptor As IntPtr
        Public bInheritHandle As Integer
    End Structure

    Public Enum TOKEN_INFORMATION_CLASS
        TokenUser = 1
        TokenGroups
        TokenPrivileges
        TokenOwner
        TokenPrimaryGroup
        TokenDefaultDacl
        TokenSource
        TokenType
        TokenImpersonationLevel
        TokenStatistics
        TokenRestrictedSids
        TokenSessionId
        TokenGroupsAndPrivileges
        TokenSessionReference
        TokenSandBoxInert
        TokenAuditPolicy
        TokenOrigin
        TokenElevationType
        TokenLinkedToken
        TokenElevation
        TokenHasRestrictions
        TokenAccessInformation
        TokenVirtualizationAllowed
        TokenVirtualizationEnabled
        TokenIntegrityLevel
        TokenUIAccess
        TokenMandatoryPolicy
        TokenLogonSid
        MaxTokenInfoClass
    End Enum

    Structure TOKEN_PRIVILEGES
        Public PrivilegeCount As Integer
        Public TheLuid As LUID
        Public Attributes As Integer
    End Structure

    Structure LUID
        Public LowPart As UInt32
        Public HighPart As UInt32
    End Structure

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    Structure STARTUPINFO
        Public cb As Integer
        Public lpReserved As String
        Public lpDesktop As String
        Public lpTitle As String
        Public dwX As Integer
        Public dwY As Integer
        Public dwXSize As Integer
        Public dwYSize As Integer
        Public dwXCountChars As Integer
        Public dwYCountChars As Integer
        Public dwFillAttribute As Integer
        Public dwFlags As Integer
        Public wShowWindow As Short
        Public cbReserved2 As Short
        Public lpReserved2 As Integer
        Public hStdInput As Integer
        Public hStdOutput As Integer
        Public hStdError As Integer
    End Structure

    Structure PROCESS_INFORMATION
        Public hProcess As IntPtr
        Public hThread As IntPtr
        Public dwProcessId As Integer
        Public dwThreadId As Integer
    End Structure

    Public Const SE_PRIVILEGE_ENABLED = &H2L
    Public Const PROCESS_QUERY_INFORMATION = &H400
    Public Const TOKEN_ASSIGN_PRIMARY = &H1
    Public Const TOKEN_DUPLICATE = &H2
    Public Const TOKEN_IMPERSONATE = &H4
    Public Const TOKEN_QUERY = &H8
    Public Const TOKEN_QUERY_SOURCE = &H10
    Public Const TOKEN_ADJUST_PRIVILEGES = &H20
    Public Const TOKEN_ADJUST_GROUPS = &H40
    Public Const TOKEN_ADJUST_DEFAULT = &H80
    Public Const TOKEN_ADJUST_SESSIONID = &H100
    Public Const SecurityImpersonation = 2
    Public Const TokenPrimary = 1
    Public Const SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim currentProcess As Process = Process.GetCurrentProcess
        'Enable SeIncreaseQuotaPrivilege in this process.  (This requires administrative privileges.)
        Dim hProcessToken As IntPtr = Nothing
        'OpenProcessToken(currentProcess.Handle, TOKEN_ADJUST_PRIVILEGES, hProcessToken)
        Dim tkp As TOKEN_PRIVILEGES
        'tkp.PrivilegeCount = 1
        'LookupPrivilegeValue(Nothing, SE_INCREASE_QUOTA_NAME, tkp.TheLuid)
        'tkp.Attributes = SE_PRIVILEGE_ENABLED

        'AdjustTokenPrivileges(hProcessToken, False, tkp, 0, Nothing, Nothing)

        'Get window handle representing the desktop shell.  This might not work if there is no shell window, or when
        'using a custom shell.  Also note that we're assuming that the shell is not running elevated.
        Dim hShellWnd As IntPtr = GetShellWindow()

        'Get the ID of the desktop shell process.
        Dim dwShellPID As IntPtr
        GetWindowThreadProcessId(hShellWnd, dwShellPID)

        'Open the desktop shell process in order to get the process token.
        Dim hShellProcess As IntPtr = OpenProcess(PROCESS_QUERY_INFORMATION, False, dwShellPID)
        Dim hShellProcessToken As IntPtr = Nothing
        Dim hPrimaryToken As IntPtr = Nothing

        'Get the process token of the desktop shell.
        OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, hShellProcessToken)

        'Duplicate the shell's process token to get a primary token.
        Dim dwTokenRights As Integer = TOKEN_QUERY Or TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_ADJUST_DEFAULT Or TOKEN_ADJUST_SESSIONID
        DuplicateTokenEx(hShellProcessToken, dwTokenRights, Nothing, SecurityImpersonation, TokenPrimary, hPrimaryToken)

        Dim si As STARTUPINFO = Nothing
        Dim pi As PROCESS_INFORMATION = Nothing

        si.cb = Marshal.SizeOf(si)
        CreateProcessWithTokenW(hPrimaryToken, 0, "D:\MFTRead.exe", Nothing, 0, Nothing, Nothing, si, pi)
        Console.WriteLine(pi.dwProcessId)


    End Sub

    <DllImport("kernel32.dll")> _
    Shared Function CreateProcess(ByVal lpApplicationName As IntPtr, _
   ByVal lpCommandLine As IntPtr, ByRef lpProcessAttributes As SECURITY_ATTRIBUTES, _
   ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Boolean, _
   ByVal dwCreationFlags As UInt32, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As String, _
   <[In]()> ByRef lpStartupInfo As STARTUPINFO, _
   <[Out]()> ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
    End Function


    Private Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim p As Process = New Process
        p.StartInfo.FileName = "D:\MFTRead.exe"
        p.StartInfo.Arguments = ""
        p.Start()
        Console.WriteLine(p.Id)
    End Sub
End Class



aw27

The error may happen even before, namely on the DuplicateTokenEx .
You can't simply drop every access right you have in mind and hope the function will comply.
You have not enabled SE_ASSIGNPRIMARYTOKEN_NAME privilege  and you don't hold the SE_TCB_NAME privilege.
Surprisingly, from your listing it is not causing errors.  :rolleyes:

So, specifically for the CreateProcessWithTokenW, names have to be in UNICODE, not what you are doing.




Fraile

Hello AW, thank you very much for your contribution. Could you tell me how I put the name in unicode ?. Some example.

aw27

When we talk about Unicode here we are talking about word size characters.
So, it should be:
RunProg             DW "D",":","\","M","F","T","R","e","a","d",".","e","x","e", 0

Note that there are macros in the Masm32 SDK that do this automatically (not to talk about many other alternatives).

Fraile


I tried it, but it still fails in the same place. Attachment asm, complete. It's treated with EasyCode.

Fraile


if in the example, of VB.net, in the definition of the library

   <DllImport ("advapi32", SetLastError: = True, CharSet: = CharSet.Unicode)>
    Public Shared Function CreateProcessWithTokenW (ByVal hToken As IntPtr, ByVal dwLogonFlags As Integer, ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal dwCreationFlags As Integer, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As IntPtr, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) Ace Boolean
    End function

I delete, CharSet: = CharSet.Unicode. So, it happens the same as with the asm code, it doesn't work.

Aw is right, but I don't know how to apply unicode to the CreateProcessWithTokenW function.

aw27

I already showed you how to produce the Unicode, but there is also the problem of "ERROR_PRIVILEGE_NOT_HELD" which you can verify looking at GetLastError.

The elevated administrator account has a number of privileges that need to be Enabled before being used. You are not doing anything to enable the ones that are required.

Here are are the privileges the elevated Administrator account has:



I am not going to fix it for you after this stage.

BTW, try to learn true MASM to produce the examples unless you are in the specialized forum. Remember there are literally hundreds of editors, EasyCode is just another one.

Fraile

Ok AW, I really appreciate your help. I do not understand, because in vb.net if it works and the same code in asm, no ?. Well I'll keep trying ...

Again, thank you very much.

aw27

If the error says that privileges are not enabled, then enable them.
I see code in the VB section that you commented out to enable the privileges, so it is necessary. Of course once the privileges are enabled they will remain enabled on that window that's why you believe it is not necessary. It is necessary, you had already enabled them.



Fraile


aw27

The SeTcbPirivilege by default is not available to Administrators, you will need to change Local Security Policy. But since you say it works in VB so you have already done that.

Have fun then,  :thumbsup:

Fraile


I already have it. I leave the code in case someone can reuse it.



Code:

ElavarPrvilegios Proc
Local Shell:DWord
Local ShellProcessId:DWord
Local hShellProcess:DWord
Local hShellToken:DWord
Local Security:SECURITY_ATTRIBUTES
Local hToken:DWord
Local MSi:STARTUPINFO
Local Pinf:PROCESS_INFORMATION
Local TP:TOKEN_PRIVILEGES
Local Ph:DWord

   Invoke GetCurrentProcess
   Mov Ph, Eax

   Invoke OpenProcessToken, Ph, TOKEN_ADJUST_PRIVILEGES, Addr hToken
;
;Invoke PasarADecimal, hToken
;
;
   Mov TP.PrivilegeCount, 1
   Invoke LookupPrivilegeValue, NULL, Offset SEShutName, Addr TP.Privileges
  • .Luid
       Mov TP.Privileges
  • .Attributes, SE_PRIVILEGE_ENABLED
    ;;
       Invoke AdjustTokenPrivileges, hToken, FALSE, Addr TP, NULL, NULL, NULL


    ;   Invoke GetCurrentProcessId
    ;   Mov Ph, Eax
    ;   Invoke OpenProcessToken, Ph, TOKEN_ADJUST_PRIVILEGES, Addr hToken
    ;
    ;Invoke PasarADecimal, Eax
    ;
    ;
    ;   Mov TP.PrivilegeCount, 1
    ;   Invoke LookupPrivilegeValue, NULL, Offset SEShutName, Addr TP.Privileges
  • .Luid
    ;   Mov TP.Privileges
  • .Attributes, SE_PRIVILEGE_ENABLED
    ;;
    ;   Invoke AdjustTokenPrivileges, hToken, FALSE, Addr TP, NULL, NULL, NULL
    ;
    ;Invoke PasarADecimal, Eax


       ;Get window handle representing the desktop shell.  This might not work if there is no shell window, or when
        ;using a custom shell.  Also note that we' re assuming that the Shell is NOT running elevated.
       Invoke GetShellWindow
       Mov Shell, Eax

       .If Eax != 0


          ;Get the ID of the desktop shell process.
          Invoke GetWindowThreadProcessId, Shell, Addr ShellProcessId

          ;Open the desktop shell process in order to get the process token.
          Invoke OpenProcess, PROCESS_QUERY_INFORMATION, FALSE, ShellProcessId
          Mov hShellProcess, Eax

          .If Eax != 0


             ;Get the process token of the desktop shell.
             Invoke OpenProcessToken, hShellProcess, TOKEN_DUPLICATE, Addr hShellToken

             .If Eax != 0


                ;Duplicate the shell's process token to get a primary token.
                Invoke DuplicateTokenEx, hShellToken, TOKEN_QUERY + TOKEN_ASSIGN_PRIMARY + TOKEN_DUPLICATE + TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_SESSIONID, 0, 2, 1, Addr hToken


                .If Eax != 0

                         Invoke RtlZeroMemory, Addr MSi, SizeOf MSi
                         Invoke RtlZeroMemory, Addr Pinf, SizeOf Pinf

                           Mov Eax, SizeOf MSi
                         Mov MSi.cb, Eax

                         Invoke CreateProcessWithTokenW, hToken, LOGON_WITH_PROFILE, 0, TextAddrW("D:\MFTRead.exe"), 0, 0, 0, Addr MSi, Addr Pinf

                .EndIf
    ;
             .EndIf
    ;
          .EndIf

       .EndIf

       Xor Eax, Eax

       Ret
    ElavarPrvilegios EndP

Fraile


For a moment, I thought, I could inherit privileges, from another application. no need to run the latter, as administrator. aw, you were right, trying it is a lot of fun .... :thumbsup:

aw27

In your case you are using CreateProcessWithTokenW to launch an application in Medium Integrity Level (Windows Explorer.exe IL) from an application with High Integrity Level (i.e. your app elevated to Administrator).
This is mostly done to reduce security risks. You can play further and reduce the IL to low, the level at which internet browsers run.
But you can also use CreateProcessWithTokenW to create a Local System Service. This is not really an escalation because Local System accounts are always created from an Elevated Administrator account. It is simply a different way of doing it.

Fraile