Jump to content

Elevate Your Script to the SYSTEM Account


wraithdu
 Share

Recommended Posts

  • 2 weeks later...

Arghh, wish I had seen this post before posting my request yesterday

http://www.autoitscript.com/forum/index.php?showtopic=105441

It's along the lines of what I've been trying to achieve except, I'm trying to toggle between the System Account and Logged on User Account.

Unfortunately it doesn't work exactly the way I thought it would for example:

_ImpersonateUserStart()

... Code here still appears to run under the context of the user executioner

_ImpersonateUserEnd()

_CreateProcessAsUser("notepad.exe", "explorer.exe") ; Works as intended i.e. under the logged on users account.

Also found that it only works for applications run from the Local System, if I try to runas another user for example:

- C:\>RUNAS /USER:Administrator "C:\Scripts\SystemElevate.exe -run explorer.exe notepad.exe"

The example messages all display the Administrator (I thought that after _ImpersonateUserStart() it will display the actual logged on user).

If I wanted to use an internal function like _IECreateEmbedded() I assume I'd have to create another script compile it and then use _CreateProcessAsUser("Explorer.exe, "CompiledScript") is that correct? Does anyone know a better way of achieving this?

Summary of what I'm trying to achieve:

- Using SCCM 2007, run a custom AutoIT Script using the Local System Account.

- Within the Script Toggle between the Local System Account and the Logged on User (Allows opening URLs, Documents in the Users Context, which by proxy will allow the user to connect to the intranet, print, save the documents.

- Continue the Script as the Local System Account.

If anyone could assist with that it'd be great.

Cheers

Link to comment
Share on other sites

Unfortunately it doesn't work exactly the way I thought it would for example:

_ImpersonateUserStart()

... Code here still appears to run under the context of the user executioner

_ImpersonateUserEnd()

It works exactly how I said it would. Code run between those commands runs as the currently logged on user. How did you expect it to work?

_CreateProcessAsUser() only works when launching a new process...hence the 'CreateProcess' part. So yes, you'll need another compiled executable to use that command.

Link to comment
Share on other sites

My understanding is that "ImpersonateLoggedOnUser" will run under the logged on user context. The two functions I'd really like to use are _ImpersonateUserStart() and _ImpersonateUserEnd(). If I compile the code below and set it up to runas System Account in SCCM 2007. When I run the script:

LoggedOnUser.txt @Username = SYSTEM

ScriptExecutor.txt @Username = SYSTEM

I believe that it should be:

LoggedOnUser.txt @Username = Username

ScriptExecutor.txt @Username = SYSTEM

Is my understanding incorrect?

_ImpersonateUserStart()

$file = FileOpen("C:\Script\LoggedOnUser.txt", 10)
    FileWriteLine($file, @UserName & @CRLF)
    FileClose($file)

_ImpersonateUserEnd()

$file = FileOpen("C:\Script\ScriptExecutor.txt", 10)
    FileWriteLine($file, @UserName & @CRLF)
    FileClose($file)

Functions...
Link to comment
Share on other sites

Without your whole script, I can't tell you what's going on. My guess...you're using the functions incorrectly in the context of the rest of the script. Post something I can run and reproduces the problem. The example I posted correctly returns the logged on user from the @UserName macro.

It would also help to know what version of AutoIt you're trying to use. At some point AutoIt changed the way the @ macros determined things like directories. In current betas it is done correctly (through API calls). In older version is was reading the registry I believe, which may or may not produce the intended result when impersonating a user / security context.

Edited by wraithdu
Link to comment
Share on other sites

Sorry for the delay, the entire code below, as I mentioned this is running from SCCM 2007 as the Local System Account, strange thing is if I create a scheduled Task to RunAs System, it does output the correct information in the two text files, but for what ever reason when using SCCM the output is "System" for both txt files.

Cheers

Global $ghADVAPI32 = DllOpen("advapi32.dll")
Global $sLog = @ScriptDir & "\SystemElevateService.log" ; debug log
Global $SVC_DEBUG = True ; write debug log

_ImpersonateUserStart()

$file = FileOpen"C:\Script\LoggedOnUser.txt", 10)
    FileWriteLine($file, @UserName & @CRLF)
    FileClose($file)

_ImpersonateUserEnd()

$file = FileOpen("C:\Script\ScriptExecutor.txt", 10)
    FileWriteLine($file, @UserName & @CRLF)
    FileClose($file)

Func _ImpersonateUserStart($sProcess = "explorer.exe")
    Local Const $MAXIMUM_ALLOWED = 0x02000000

    Local $ret = 0
    Local $dwSession = DllCall("kernel32.dll", "dword", "WTSGetActiveConsoleSessionId")
    If @error Or $dwSession[0] = 0xFFFFFFFF Then Return 0
    $dwSession = $dwSession[0]
    ; get PID of process in current session
    Local $aProcs = ProcessList($sProcess), $processPID = -1, $ret
    For $i = 1 To $aProcs[0][0]
        $ret = DllCall("kernel32.dll", "int", "ProcessIdToSessionId", "dword", $aProcs[$i][1], "dword*", 0)
        If Not @error And $ret[0] And ($ret[2] = $dwSession) Then
            $processPID = $aProcs[$i][1]
            ExitLoop
        EndIf
    Next
    If $processPID = -1 Then Return 0 ; failed to get PID
    ; open process
    Local $hProc = DllCall("kernel32.dll", "ptr", "OpenProcess", "dword", $MAXIMUM_ALLOWED, "int", 0, "dword", $processPID)
    If @error Or Not $hProc[0] Then Return 0
    $hProc = $hProc[0]
    ; open process token
    $hToken = DllCall($ghADVAPI32, "int", "OpenProcessToken", "ptr", $hProc, "dword", $MAXIMUM_ALLOWED, "ptr*", 0)
    If @error Or Not $hToken[0] Then
        DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hProc)
        Return 0
    EndIf
    $hToken = $hToken[3]
    ; impersonate the logged on user
    $ret = DllCall($ghADVAPI32, "int", "ImpersonateLoggedOnUser", "ptr", $hToken)
    If @error Or Not $ret[0] Then
        _DebugLog("Error impersonating user.")
    Else
        _DebugLog("Successfully impersonated user.")
        $ret = 1
    EndIf
    DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hToken)
    DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hProc)
    Return $ret
EndFunc   ;==>_ImpersonateUserStart

Func _ImpersonateUserEnd()
    Local $ret = DllCall($ghADVAPI32, "int", "RevertToSelf")
    If @error Or Not $ret[0] Then
        _DebugLog("Error reverting to self.")
        Return 0
    Else
        _DebugLog("Successfully reverted to self.")
        Return 1
    EndIf
EndFunc   ;==>_ImpersonateUserEnd()

Func _DebugLog($sEvent)
    If $SVC_DEBUG Then FileWriteLine($sLog, @YEAR & @MON & @MDAY & " " & @HOUR & @MIN & @SEC & " [" & @AutoItPID & "] >> " & $sEvent)
EndFunc
Link to comment
Share on other sites

Hmm, you're using a server OS? I'm not familiar with SCCM 2007, so I can't help there. Strange that the result would differ from a scheduled task as Local System. Are there any errors in the debug log? Are there success messages? Can you try with the latest beta? Does my original example work properly?

Link to comment
Share on other sites

  • 2 weeks later...

Sorry in the middle of a merger so been flat out, I have tried the Beta Version with the same results and using your original example. It's quite puzzling as I mentioned previously it does work if I create a scheduled task and as you verified via System Internals PSExec, but not via SCCM. Anyway thankyou for looking at it for me, I'll try look into it further and will post back if I resolve the issue.

Thanks again.

Cheers

Link to comment
Share on other sites

  • 1 month later...
  • 4 weeks later...

My understanding is that "ImpersonateLoggedOnUser" will run under the logged on user context. The two functions I'd really like to use are _ImpersonateUserStart() and _ImpersonateUserEnd(). If I compile the code below and set it up to runas System Account in SCCM 2007. When I run the script:

LoggedOnUser.txt @Username = SYSTEM

ScriptExecutor.txt @Username = SYSTEM

I believe that it should be:

LoggedOnUser.txt @Username = Username

ScriptExecutor.txt @Username = SYSTEM

Is my understanding incorrect?

_ImpersonateUserStart()

$file = FileOpen("C:\Script\LoggedOnUser.txt", 10)
    FileWriteLine($file, @UserName & @CRLF)
    FileClose($file)

_ImpersonateUserEnd()

$file = FileOpen("C:\Script\ScriptExecutor.txt", 10)
    FileWriteLine($file, @UserName & @CRLF)
    FileClose($file)

Functions...

First of all, wraithdu: nicely done!

Second of all, for user impersonation to be complete we have to add two calls on RegCloseKey(HKEY_CURRENT_USER) to SystemElevate.au3:

;...snip
    $ret = DllCall($ghADVAPI32, "int", "ImpersonateLoggedOnUser", "ptr", $hToken)
    If @error Or Not $ret[0] Then
        _DebugLog("Error impersonating user.")
    Else
        DllCall($ghADVAPI32, "long", "RegCloseKey", "handle", 0x80000001)
        _DebugLog("Successfully impersonated user.")
        $ret = 1
    EndIf
;...snap
;...snip
    Local $ret = DllCall($ghADVAPI32, "int", "RevertToSelf")
    If @error Or Not $ret[0] Then
        _DebugLog("Error reverting to self.")
        Return 0
    Else
        DllCall($ghADVAPI32, "long", "RegCloseKey", "handle", 0x80000001)
        _DebugLog("Successfully reverted to self.")
        Return 1
    EndIf
;...snap

The background is, Windows doesn't unload registry hives immediately after context switch, so depending on system load and performance it could take several minutes before HKEY_CURRENT_USER actually points to the current user's hive.

Hope, it helps.

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ 

Link to comment
Share on other sites

Two more notes.

1. Before you compile SystemElevate and run it, ensure that either MustDeclareVars = 0 or check the script with Au3Check and correct 2 undeclared $hToken variables. Otherwise the created service would silently crash and hang there until killed from Task Manager.

2. NEVER use local variables inside the block between _ImpersonateUserStart() and _ImpersonateUserEnd() and then reference them from outside the block! Those variables revert to their uninitialized state after _ImpersonateUser...() is called and data saved in them is lost. Declare such variables as global and outside the impersonation scope. Examples below.

Data lost:

_ImpersonateUserStart()
Local $test = @UserName
MsgBox(0, "Impersonated", "data: " & $test)
_ImpersonateUserEnd()
; $test is now empty!!!
MsgBox(0, "Self", "data: " & $test)

Data preserved:

Global $test = ""
_ImpersonateUserStart()
$test = @UserName
MsgBox(0, "Impersonated", "data: " & $test)
_ImpersonateUserEnd()
; $test contains impersonated user name
MsgBox(0, "Self", "data: " & $test)

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...