Opened on Jan 23, 2012 at 9:49:32 PM
Closed on Feb 26, 2012 at 11:09:53 PM
Last modified on Mar 6, 2012 at 10:17:06 PM
#2111 closed Bug (Fixed)
RunAs broken when Authenticated Users added to Replace a process level token
| Reported by: | Owned by: | Valik | |
|---|---|---|---|
| Milestone: | 3.3.9.1 | Component: | AutoIt |
| Version: | 3.3.6.1 | Severity: | None |
| Keywords: | RunAs, Replace a process level token | Cc: |
Description
We have an application that adds 'Authenticated Users' to 'Replace a process level token' security on XP machines (via secpol.msc). Once this is in place & the PC rebooted AutoIt's RunAs fails.
I'm using RunAs to grant local support staff access to an Admin Console so they don't have to logoff the current user. This feature is broken on several thousand machines where the bogus security modifying app is installed. The problem has existed for a several years now & we JUST found the root cause.
These are XP SP3 x86 devices joined to a domain.
Working (Windows Default):
Computer Configuration\Windows Settings\Security Settings\Local Policies\User Rights Assignment\Replace a process level token
Network Service, Local System
Broken:
Computer Configuration\Windows Settings\Security Settings\Local Policies\User Rights Assignment\Replace a process level token
Authenticated Users, Network Service, Local System
http://technet.microsoft.com/en-us/library/cc784623(WS.10).aspx
Attachments (0)
Change History (9)
comment:2 by , on Jan 23, 2012 at 11:33:54 PM
Doh. We'll call this an oversight on my part. To be fair, I'm not really sure where this would be documented. You have the right privileges but they are disabled. They must be enabled before they can be used. Pretty trivial for AutoIt to do that, of course. I didn't realize it was necessary because the SYSTEM account always has those privileges enabled.
comment:3 by , on Feb 4, 2012 at 10:21:15 PM
| Milestone: | → 3.3.9.0 |
|---|---|
| Owner: | set to |
| Resolution: | → Fixed |
| Status: | new → closed |
Fixed by revision [6764] in version: 3.3.9.0
comment:4 by , on Feb 21, 2012 at 6:47:01 PM
It still appears to be broken in 3.3.9.0 compiled scripts. Here's my testing example:
;constants
Global Const $tagBOOL = "int"
Global Const $tagSTRING64 = "char[64]"
Global Const $tagSTRING128 = "char[128]"
Global Const $tagSTRING256 = "char[256]"
Global Const $tagSTRING32767 = "char[32767]"
Global Const $tagSTRING_CRED_MAX_USERNAME_LENGTH = "char[513]"
Global Const $tagCREDUI_INFO = "DWORD cbSize;HWND hwndParent;PTR pszMessageText;PTR pszCaptionText;HBITMAP hbmBanner"
;Flags for CredUIPromptForCredentials
Global Const $CRED_MAX_USERNAME_LENGTH = (256+1+256)
Global Const $CREDUI_MAX_PASSWORD_LENGTH = 256
Global Const $CRED_MAX_GENERIC_TARGET_NAME_LENGTH = 32767
Global Const $CRED_MAX_STRING_LENGTH = 256
Global Const $CREDUI_FLAGS_INCORRECT_PASSWORD = 0x00001 ;indicates the username is valid, but password is not
Global Const $CREDUI_FLAGS_DO_NOT_PERSIST = 0x00002 ;Do not show "Save" checkbox, and do not persist credentials
Global Const $CREDUI_FLAGS_REQUEST_ADMINISTRATOR = 0x00004 ;Populate list box with admin accounts
Global Const $CREDUI_FLAGS_EXCLUDE_CERTIFICATES = 0x00008 ;do not include certificates in the drop list
Global Const $CREDUI_FLAGS_REQUIRE_CERTIFICATE = 0x00010
Global Const $CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX = 0x00040
Global Const $CREDUI_FLAGS_ALWAYS_SHOW_UI = 0x00080
Global Const $CREDUI_FLAGS_REQUIRE_SMARTCARD = 0x00100
Global Const $CREDUI_FLAGS_PASSWORD_ONLY_OK = 0x00200
Global Const $CREDUI_FLAGS_VALIDATE_USERNAME = 0x00400
Global Const $CREDUI_FLAGS_COMPLETE_USERNAME = 0x00800
Global Const $CREDUI_FLAGS_PERSIST = 0x01000 ;Do not show "Save" checkbox, but persist credentials anyway
Global Const $CREDUI_FLAGS_SERVER_CREDENTIAL = 0x04000
Global Const $CREDUI_FLAGS_EXPECT_CONFIRMATION = 0x20000 ;do not persist unless caller later confirms credential via CredUIConfirmCredential() api
Global Const $CREDUI_FLAGS_GENERIC_CREDENTIALS = 0x40000 ;Credential is a generic credential
Global Const $CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS = 0x80000 ;Credential has a username as the target
Global Const $CREDUI_FLAGS_KEEP_USERNAME = 0x100000 ;don't allow the user to change the supplied username
If IsArray($cmdline) Then
If UBound($cmdline) > 1 Then
If $cmdline[1] = "/AdminConsole" Then
MsgBox(0,"Admin Console",@username & @CRLF & @WorkingDir)
Exit
EndIf
EndIf
EndIf
CredTest()
Exit
Func CredTest()
Local $lCreds, $lBslashLoc, $lDomain, $lUser, $lRPID
$lCreds = _CredUIPromptForCredentials(0, "", "", "", " Admin Console", "", "", "", "", -1)
If IsArray($lCreds) Then
If $lCreds[0] = 1223 Then
;user canceled credentials box
$lDone = 1
ElseIf $lCreds[1] <> "" Then
If StringInStr($lCreds[1],"\") Then
$lBslashLoc = StringInStr($lCreds[1],"\")
$lDomain = StringLeft($lCreds[1], $lBslashLoc - 1)
$lUser = StringTrimLeft($lCreds[1], $lBslashLoc)
ElseIf StringInStr($lCreds[1],"@") Then
$lBslashLoc = StringInStr($lCreds[1],"@")
$lUser = StringLeft($lCreds[1], $lBslashLoc - 1)
$lDomain = StringTrimLeft($lCreds[1], $lBslashLoc)
EndIf
If ($lUser <> "") And ($lDomain <> "") And ($lCreds[2] <> "") Then
;RunAs ( "username", "domain", "password", logon_flag, "filename" [, "workingdir" [, show_flag [, opt_flag ]]] )
$lRPID = RunAs($lUser, $lDomain, $lCreds[2],1,'"' & @ScriptFullPath & '" /AdminConsole', @SystemDir)
MsgBox(0,"Creds",$lUser & @CRLF & $lDomain & @CRLF & "PWLen: " & StringLen($lCreds[2]) & @CRLF & "PID: " & $lRPID)
If $lRPID = 0 Then
;log- Admin Console - Access Denied. Unknown user name or bad password
$lMsgRslt = MsgBox(BitOR(0x1,0x30,0x40000)," Admin Console","Access Denied" & @CRLF & @CRLF & "Unknown user name or bad password." & @CRLF & "RunAs process could not be created.",120)
If ($lMsgRslt = -1) or ($lMsgRslt = 2) Then
;user has canceled or the message timed out
$lDone = 1
EndIf
Else
;admin console was started
$lDone = 1
EndIf
EndIf
EndIf
Else
MsgBox(0,Default,"Array not returned")
EndIf
EndFunc
Func _CredUIPromptForCredentials($lHWndParentUI = 0, $lpszMessageText = "", $lpszCaptionText = "", $lhbmBanner = "", $lpszTargetName = "", $ldwAuthError = "", $lpszUserName = "", $lpszPassword = "", $lpfSave = "", $ldwFlags = "")
Local $sCREDUI_INFO, $spszMessageText, $spszCaptionText
Local $spszTargetName, $spszUserName, $spszPassword, $spfSave, $lCredUIPromptForCredentials, $retArray[4]
;configure CREDUI_INFO structures
$spszMessageText = DllStructCreate($tagSTRING32767)
$spszCaptionText = DllStructCreate($tagSTRING128)
DllStructSetData($spszMessageText, 1, $lpszMessageText)
DllStructSetData($spszCaptionText, 1, $lpszCaptionText)
$sCREDUI_INFO = DllStructCreate($tagCREDUI_INFO)
DllStructSetData($sCREDUI_INFO, "cbSize", DllStructGetSize($sCREDUI_INFO))
DllStructSetData($sCREDUI_INFO, "hwndParent", $lHWndParentUI)
DllStructSetData($sCREDUI_INFO, "pszMessageText", DllStructGetPtr($spszMessageText))
DllStructSetData($sCREDUI_INFO, "pszCaptionText", DllStructGetPtr($spszCaptionText))
DllStructSetData($sCREDUI_INFO, "hbmBanner", $lhbmBanner)
;configure CredUIPromptForCredentials structures
$spszTargetName = DllStructCreate($tagSTRING32767)
$spszUserName = DllStructCreate($tagSTRING_CRED_MAX_USERNAME_LENGTH)
$spszPassword = DllStructCreate($tagSTRING256)
$spfSave = DllStructCreate($tagBOOL)
DllStructSetData($spszTargetName,1,$lpszTargetName)
DllStructSetData($spszUserName,1,$lpszUserName)
DllStructSetData($spszPassword,1,$lpszPassword)
DllStructSetData($spfSave,1,$lpfSave)
;configure default prompting options
If $ldwFlags = -1 Then
$ldwFlags = BitOR($CREDUI_FLAGS_DO_NOT_PERSIST,$CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS,$CREDUI_FLAGS_REQUEST_ADMINISTRATOR)
EndIf
;prompting for credentials
$lCredUIPromptForCredentials = DllCall("Credui.dll","DWORD", "CredUIPromptForCredentials","ptr", DllStructGetPtr($sCREDUI_INFO), "ptr", DllStructGetPtr($spszTargetName),"ptr", "", "DWORD", $ldwAuthError, "ptr", DllStructGetPtr($spszUserName),"ULONG", $CRED_MAX_USERNAME_LENGTH, "ptr", DllStructGetPtr($spszPassword), "ULONG", $CREDUI_MAX_PASSWORD_LENGTH, "ptr", DllStructGetPtr($spfSave), "DWORD", $ldwFlags)
;results array
If IsArray($lCredUIPromptForCredentials) Then
$retArray[0] = $lCredUIPromptForCredentials[0]
$retArray[1] = DllStructGetData($spszUserName,1)
$retArray[2] = DllStructGetData($spszPassword,1)
$retArray[3] = DllStructGetData($spfSave,1)
EndIf
;release structures
$spszMessageText = 0
$spszCaptionText = 0
$sCREDUI_INFO = 0
$spszTargetName = 0
$spszUserName = 0
$spszPassword = 0
$spfSave = 0
Return $retArray
EndFunc
;script end
comment:5 by , on Feb 23, 2012 at 3:59:39 AM
| Resolution: | Fixed |
|---|---|
| Status: | closed → reopened |
I'm more interested in seeing what privileges the account in question has than a test script. Download the following program. It's a custom program I wrote that lists the privileges an access token has. Run it using the account where RunAs() fails. Show me the output so I can see what privileges the account in question has and what state they are in.
comment:7 by , on Feb 26, 2012 at 11:09:53 PM
| Milestone: | → 3.3.9.1 |
|---|---|
| Resolution: | → Fixed |
| Status: | reopened → closed |
Fixed by revision [6820] in version: 3.3.9.1
comment:8 by , on Feb 26, 2012 at 11:11:17 PM
There were a couple additional privileges that are required. In addition the calling user must be in the administrators group. These conditions are now tested for and the code correctly falls back onto alternate methods unless all conditions are met.
comment:9 by , on Mar 6, 2012 at 10:17:06 PM
I verified it's fixed with our whacky vendor app & 3.3.9.1 compiled scripts. Thanks Valik!

!! Also requires Authenticated Users be added to 'Adjust memort quotas for a process' to fail.