Tuesday, November 9, 2010
Updating cached credentials
I have a client that uses a VPN client and does not allow users to logon from the Windows logon screen, rather they have to already be logged in using cached credentials and then launch the VPN client and authenticate...
Now this poses a significant issue deploying applications via SCCM based on a user's groups for those users who are full time work at home or road warriors, as the user's windows security token, that stores the SIDs for all their groups, never gets updated through an interactive domain logon...
thus far the only solution I've found is... write a utility that prompts for the user's current password and then launch a new process / thread with those credentials just like runas.exe. This then updates the cached credentials... force the user to logoff and logon and voila the token has the new groups...
Tuesday, September 15, 2009
SQL Authentication issues and MaxTokenSize
Saved my bacon yesterday so selflessly reposted the link below:
Problem
DBA's and web developers at our company are experiencing issues with connecting to SQL instances using SQL Server Management Studio and other SQL tools using Windows Integrated Authentication. Our company is large, with well over 70,000 users and groups in Active Directory. When we look in the NT event log on the SQL Server we see both MSSQL and Kerberos errors. What could be causing this?
Solution
The issue occurs when a user has membership in many Active Directory groups, usually over 100 (this number includes explicit membership as well as inherited membership from other groups). The default value for the MaxTokenSize is 12000 decimal, although there is no registry entry for the default value. In the great majority of organizations this size is more than adequate; however, in large organizations users' tokens may be larger than the default. Since Kerberos won't accept broken tokens, authentication fails. If you are encountering this issue you will see two errors indicating that the default MaxTokenSize is not sufficient:
| NT error log entry from the Kerberos service |
|
|
| NT error log entry from the MSSQL service |
|
|
Microsoft has a utility called TokenSZ that can be used to determine the MaxTokenSize for a user. There are a number of switches that can be used with the utility, but the general syntax to calculate the max token size is:
| Sample TokenSZ Syntax |
E:\>tokensz /compute_tokensize /user:Administrator /domain:CULLENSOLUTIONS.com /password:OU812 |
| Results of executing TOKENSZ |
|
|
At the top of the window above you can see that the default token size is 12000. The text outlined in red is the actual Max Token size for the Administrator of the domain...well below the MaxToken default. The company I am currently assigned to is encountering MaxTokenSizes between 12000 to 15000 so a modification was required.
A registry entry modification or addition is required to modify the default MaxTokenSize allowed by the server. The location of the registry change is in the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters section. Note that the server on which TOKENSZ was executed does not have an entry for MaxTokenSize:
To create the registry entry, open Registry Editor by clicking Start -> Run, then typing regedit. Once Registry Editor is open navigate to the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters section. Right-click the white area on the right side and choose New -> DWORD value:
Rename the entry to "MaxTokenSize", double-click to edit it, choose Decimal, and enter 65535:
Any server workstation or server that interacts with SQL Server will require the registry entry. Also, the machine will require a reboot for the change to take effect. Once the reboot has occurred you can execute TokenSZ again to see if the MaxTokenSize value has changed:
Thursday, June 25, 2009
Windows 7 Kerberos updates and foreign realms
I bit the bullet, bought a new 500Gb Seagate drive for my laptop, VM’d my Vista install, swapped the drive and changed my main laptop to Windows 7 over the weekend, and apart from Sony PC Suite, which just sits in the system tray looking dead, everything is running better than ever… 4Gb of ram certainly helps things along but this is faster than XP Sp3 in my FITA (Finger In The Air) opinion and light years ahead of Vista aka Windows Me 2007 …
So I added the laptop to my AD domain e.g. lingpopo.net and then while at a client site mapped a drive to a server in their AD domain e.g. bank.corp.com, saved the credentials and all worked as expected… but later while I was debugging a kerberos issue with some users on XP I forgot I was on 7 and ran klist (now an OS standard tool at least in 7 RC1) and noticed something strange but very pleasing. Rather than just seeing a TGT from my domain e.g. me @ lingpopo.net I now saw TGTs for the me @ bank.corp.com and cifs TGS tickets for the server in bank.corp.com! Sweetness! I’m getting TGTs and tickets for resource from an untrusted realm / forest / domain, no more failover to NTLM outside the forest / trust boundary, brilliant! but how? I need to know…This did not happen in XP or Vista, so what have Microsoft done? I’ve only noticed this behaviour today and have started digging out details on Kerberos improvements in Windows 7 but thus far i’ve found zip, nada, nowt… once I do I’ll be sure to post…
Anyway random stuff and quite interesting, at least to me…
Got a response from Microsoft Response from MS which says the functionality was always there but imho it wasn't... but going to dig out an xp and vista vpc and retest just to be sure...
Update 7/1/09 :- I recompiled and used this old tool of mine http://www.brianhehir.com/ktickets.exe to try and validate the tickets under Windows 7 and Windows XP. Running this tool under Windows 7 gives totally different results to running KLIST.EXE under Windows 7 but the results from kticket.exe are consistent between Windows 7 and Windows XP. So is it just Klist.exe that is different between Windows 7 and Windows XP or is there some underlying fundamental difference with Kerberos in Windows 7... Only way to be sure is going to take a network trace and compare....
Sunday, June 21, 2009
Here’s a little collection that sets up some Event Consumers on bad logon events and will launch a script to take action on the event. It can be used to take action on logon attempts using cached credentials. If used with the Purge Tickets code it can clear a users kerberos tickets if an intruder logon attempt is detected while disconnected from a domain. Kinda overkill but it was an interesting exercise in understanding event consumers, kerberos tickets and logon providers….
%SYSTEMROOT%\SYSTEM32\WBEM\MOFCOMP.EXE -N:root\default %SYSTEMROOT%\SYSTEM32\WBEM\scrcons.mof
%SYSTEMROOT%\SYSTEM32\WBEM\MOFCOMP.EXE “%HERE%\528SecEventTrig.mof”
%SYSTEMROOT%\SYSTEM32\WBEM\MOFCOMP.EXE “%HERE%\529SecEventTrig.mof”
%SYSTEMROOT%\SYSTEM32\WBEM\MOFCOMP.EXE “%HERE%\539SecEventTrig.mof”
529SecEventTrig.mof:
#pragma namespace (”\\\\.\\root\\subscription”)
instance of ActiveScriptEventConsumer as $Cons529
{
Name = “BadLogonConsumer”;
ScriptingEngine = “VBScript”;
ScriptFileName = “C:\\WINDOWS\\SYSTEM32\\DRIVERS\\HERACLES.VBS”;
KillTimeout = 1;
};
instance of __EventFilter as $Filt529
{
Name = “BadLogonFilter”;
Query = “SELECT * FROM __InstanceCreationEvent “
“WHERE TargetInstance ISA \”Win32_NTLogEvent\” “
“AND TargetInstance.LogFile = \”Security\” “
“AND TargetInstance.SourceName = \”Security\” “
“AND TargetInstance.EventCode = 529″;
QueryLanguage = “WQL”;
EventNamespace = “\\\\.\\root\\cimv2″;
};
instance of __FilterToConsumerBinding
{
Filter = $Filt529;
Consumer = $Cons529;
};
528SecEventtrig.mof:
#pragma namespace (”\\\\.\\root\\subscription”)
instance of ActiveScriptEventConsumer as $Cons539
{
Name = “AccountLockedConsumer”;
ScriptingEngine = “VBScript”;
ScriptFileName = “C:\\WINDOWS\\SYSTEM32\\DRIVERS\\HERACLES.VBS”;
KillTimeout = 1;
};
instance of __EventFilter as $Filt539
{
Name = “AccountLockedFilter”;
Query = “SELECT * FROM __InstanceCreationEvent “
“WHERE TargetInstance ISA \”Win32_NTLogEvent\” “
“AND TargetInstance.LogFile = \”Security\” “
“AND TargetInstance.SourceName = \”Security\” “
“AND TargetInstance.EventCode = 539″;
QueryLanguage = “WQL”;
EventNamespace = “\\\\.\\root\\cimv2″;
};
instance of __FilterToConsumerBinding
{
Filter = $Filt539;
Consumer = $Cons539;
};
539SecEventTrig.mof:
#pragma namespace (”\\\\.\\root\\subscription”)
instance of ActiveScriptEventConsumer as $Cons539
{
Name = “AccountLockedConsumer”;
ScriptingEngine = “VBScript”;
ScriptFileName = “C:\\WINDOWS\\SYSTEM32\\DRIVERS\\HERACLES.VBS”;
KillTimeout = 1;
};
instance of __EventFilter as $Filt539
{
Name = “AccountLockedFilter”;
Query = “SELECT * FROM __InstanceCreationEvent “
“WHERE TargetInstance ISA \”Win32_NTLogEvent\” “
“AND TargetInstance.LogFile = \”Security\” “
“AND TargetInstance.SourceName = \”Security\” “
“AND TargetInstance.EventCode = 539″;
QueryLanguage = “WQL”;
EventNamespace = “\\\\.\\root\\cimv2″;
};
instance of __FilterToConsumerBinding
{
Filter = $Filt539;
Consumer = $Cons539;
};
HERACLES.VBS:
‘
‘Check logon type from TargetEvent.TargetInstance.Message – 11 CachedInteractive, 7 Unlock,
‘Check the User name from TargetEvent.TargetInstance.Message against current interactive user
‘Get lockout count from RSOP
‘Increment consecutive failure count for user
‘On a good logon check the lockout counter for the user and launch chimaera.exe to purge tickets and lock account
‘ Constants:
Const strComputer = “.”
Const HKEY_LOCAL_MACHINE = &H80000002
Const path = “C:\WINDOWS\SYSTEM32\DRIVERS”
Dim strKeyPath : strKeyPath = “SYSTEM\CurrentControlSet\Control\MSReports”
‘Quit if run without the TargetEvent passed from the ActiveScriptEventConsumer
If (Not IsObject(TargetEvent)) Then WScript.Quit
‘Quit if Server
Dim objWMIService : Set objWMIService = GetObject(”winmgmts:{impersonationLevel=impersonate}!\\” _
& strComputer & “\root\CIMV2″)
Dim colItem :Set colItems = objWMIService.ExecQuery(”Select * From Win32_OperatingSystem”)
Dim objItem
For each objItem in colItems
if (instr(UCase(objItem.Caption),”SERVER”) > 0) then Wscript.Quit
Next
Set colItem = Nothing
Set objWMIService = Nothing
Dim objReg : Set objReg=GetObject(”winmgmts:{impersonationLevel=impersonate}!\\” _
& strComputer & “\root\default:StdRegProv”)
‘Run routine based on Event Code
Select Case TargetEvent.TargetInstance.EventCode
Case 528
Call GoodLogonEvent
Case 529
Call BadLogonEvent
Case 4201
Call TCPIPEvent
Case 539
Call AccountLockedEvent
End Select
Wscript.Quit
Sub GoodLogonEvent
On Error Resume Next
‘Quit if Network Service or SYSTEM
If InStr(UCase(TargetEvent.TargetInstance.Message),”NETWORK SERVICE”) > 0 Then WScript.Quit
If InStr(UCase(TargetEvent.TargetInstance.Message),”SYSTEM”) > 0 Then WScript.Quit
Dim arrMessage, arrUserName, objWMIService, objProcess, test
Dim strUserName, intLockout, errReturn, strValueName, strLogonGUID, arrLogonGUID
‘Parse message for required information
arrMessage = Split(TargetEvent.TargetInstance.Message,vbCrLf)
If IsArray(arrMessage) Then
arrUserName = Split(arrMessage(2),vbTab)
If IsArray(arrUserName) then
strUserName = arrUserName(2)
End If
arrLogonDomainName = Split(arrMessage(4),vbTab)
If IsArray(arrLogonDomainName) Then
strLogonDomainName = arrLogonDomainName(3)
End If
arrLogonComputerName = Split(arrMessage(14),vbTab)
If IsArray(arrLogonComputerName) Then
strLogonComputerName = arrLogonComputerName(UBound(arrLogonComputerName))
End If
arrLogonType = Split(arrMessage(8),vbTab)
If IsArray(arrLogonType) Then
intLogonType = arrLogonType(UBound(arrLogonType))
End If
arrLogonGUID = Split(arrMessage(16),vbTab)
If IsArray(arrLogonGUID) Then
strLogonGUID = arrLogonGUID(2)
End if
Else
WScript.Quit
End If
‘Set initial lockout counter
intLockout = &H0
‘Create user key, if not exist
strKeyPath = strKeyPath & “\” & strUserName
errReturn = objReg.CreateKey(HKEY_LOCAL_MACHINE,strKeyPath)
‘Read lockout trigger information
strValueName = strUserName & “-Lockout”
errReturn = objReg.GetDWORDValue(HKEY_LOCAL_MACHINE,strKeyPath,strValueName,intLockout)
If errReturn <> 0 Then
‘Lockout trigger not set so delete user key
objReg.DeleteKey HKEY_LOCAL_MACHINE,strKeyPath ‘,strValueName
Else
‘Lockout trigger set so launch chimaera.exe if it is not already running
Set objWMIService = GetObject(”winmgmts:{impersonationLevel=impersonate}!\\” _
& strComputer & “\root\CIMV2″)
Set objProcess = objWMIService.Get(”win32_Process”)
Set colProcesses = objWMIService.ExecQuery(”SELECT * FROM Win32_Process WHERE Name LIKE ‘%CHIMAERA.EXE%’”)
if colProcesses.Count = 0 then
‘errReturn = objProcess.Create(path & “\HYDRA.EXE /DOMAIN=” & strLogonDomainName & ” /USERID=” & strUserName, Null, Null, intProcessID)
‘Chimaera.exe not running so launch it to purge tickets and lock acocunt
errReturn = objProcess.Create(path & “\CHIMAERA.EXE /LOCK /DOMAIN=” & strLogonDomainName & ” /USERID=” & strUserName, Null, Null, intProcessID)
strValueName = strUserName & “-PurgeTktsErrReturn”
if errReturn = 1 then test = &H1 Else test = &H0
objReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,test
End if
Set objWMIService = Nothing
Set objProcess = Nothing
End If
Set objReg = Nothing
WScript.quit
End Sub
Sub BadLogonEvent
On Error Resume Next
Dim objreg, arrMessage, arrUserName, objWMIService, objProcess, colItems, objItems, test
Dim strUserName, intLockout, errReturn, strValueName, intLockoutBadCount, intBadLogonCount
Dim arrLogonDomainName, strLogonDomainName, strComputerName, arrLogonType
Dim intLogonType, arrLogonComputerName, strLogonComputerName
IntLockoutBadCount = 5
strComputerName = TargetEvent.TargetInstance.ComputerName
‘Parse message for required information
strUserName = “ERROR”
arrMessage = Split(TargetEvent.TargetInstance.Message,vbCrLf)
If IsArray(arrMessage) Then
arrUserName = Split(arrMessage(4),vbTab)
If IsArray(arrUserName) then
strUserName = arrUserName(2)
End If
arrLogonDomainName = Split(arrMessage(6),vbTab)
If IsArray(arrLogonDomainName) Then
strLogonDomainName = arrLogonDomainName(3)
End If
arrLogonComputerName = Split(arrMessage(14),vbTab)
If IsArray(arrLogonComputerName) Then
strLogonComputerName = arrLogonComputerName(UBound(arrLogonComputerName))
End If
arrLogonType = Split(arrMessage(8),vbTab)
If IsArray(arrLogonType) Then
intLogonType = arrLogonType(UBound(arrLogonType))
End If
Else
WScript.Quit
End If
‘If local logon exit
If UCase(strLogonDomainName) = UCase(strComputerName) Then WScript.Quit
If UCase(strLogonComputerName) <> UCase(strComputerName) Then WScript.Quit
strKeyPath = strKeyPath & “\” & strUserName
Set objReg=GetObject(”winmgmts:{impersonationLevel=impersonate}!\\” _
& strComputer & “\root\default:StdRegProv”)
‘Create user key if not exist and write data from message
errReturn = objReg.CreateKey(HKEY_LOCAL_MACHINE,strKeyPath)
errReturn = objReg.SetStringValue(HKEY_LOCAL_MACHINE,strKeyPath,”strLogonComputerName”,strLogonComputerName)
errReturn = objReg.SetStringValue(HKEY_LOCAL_MACHINE,strKeyPath,”strLogonDomainName”,strLogonDomainName)
errReturn = objReg.SetStringValue(HKEY_LOCAL_MACHINE,strKeyPath,”strUserName”,strUserName)
errReturn = objReg.SetStringValue(HKEY_LOCAL_MACHINE,strKeyPath,”strLogonType”,intLogonType)
errReturn = objReg.SetStringValue(HKEY_LOCAL_MACHINE,strKeyPath,”strComputerName”,strComputerName)
‘ ‘XP records logontype 11 first even if on the network so if logontype is 2 the reduce the counter by 1
‘ If (intLogonType = 2) Then
‘ strValueName = strUserName & “-BadLogonCount”
‘ errReturn = objReg.GetDWORDValue(HKEY_LOCAL_MACHINE,strKeyPath,strValueName,intBadLogonCount)
‘ If errReturn <> 0 Then
‘ intBadLogonCount = 0
‘ Else
‘ intBadLogonCount = intBadLogonCount – 1
‘ objReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,intBadLogonCount
‘ End If
‘ End if
‘ End if
‘Write and increment bad logon counter if unlock or cached
‘If not unlock or cached logon quit
If (intLogonType = 7) Or (intLogonType = 11) Then
strValueName = strUserName & “-BadLogonCount”
errReturn = objReg.GetDWORDValue(HKEY_LOCAL_MACHINE,strKeyPath,strValueName,intBadLogonCount)
If errReturn <> 0 Then
intBadLogonCount = 1
Else
intBadLogonCount = intBadLogonCount + 1
End If
objReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,intBadLogonCount
‘Read Account lockout threshold from RSOP
Set objWMIRSOPService = GetObject(”winmgmts:\\” & strComputer & “\root\rsop\computer”)
Set colItems = objWMIRSOPService.ExecQuery(”Select * from RSOP_SecuritySettingNumeric”)
For Each objItem in colItems
If objItem.KeyName = “LockoutBadCount” Then
intLockoutBadCount = objItem.Setting
End If
Next
Set ColItems = Nothing
Set objWMIRSOPService = Nothing
‘Write trigger if bad logon counter higher than threshold and purge user’s ticket cache
If (intBadLogonCount => intLockoutBadCount) Then
intLockout = 1
strValueName = strUserName & “-Lockout”
objReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,intLockout
Set objWMIService = GetObject(”winmgmts:{impersonationLevel=impersonate}!\\” _
& strComputer & “\root\CIMV2″)
Set objProcess = objWMIService.Get(”win32_Process”)
Set colProcesses = objWMIService.ExecQuery(”SELECT * FROM Win32_Process WHERE Name LIKE ‘%CHIMAERA.EXE%’”)
if colProcesses.Count = 0 then
‘errReturn = objProcess.Create(path & “\HYDRA.EXE /DOMAIN=” & strLogonDomainName & _
‘ ” /USERID=” & strUserName, Null, Null, intProcessID)
’strValueName = strUserName & “-PopupErrReturn”
‘if errReturn = 1 then test = &H1 Else test = &H0
‘objReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,test
errReturn = objProcess.Create(path & “\CHIMAERA.EXE /DOMAIN=” & strLogonDomainName & ” /USERID=” & strUserName, Null, Null, intProcessID)
strValueName = strUserName & “-PurgeTktsErrReturn”
if errReturn = 1 then test = &H1 Else test = &H0
objReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,test
End if
Set objWMIService = Nothing
Set objProcess = Nothing
End If
Set objReg = Nothing
End if
WScript.Quit
End Sub
Sub TCPIPEvent
WScript.quit
End Sub
Sub AccountLockedEvent
On Error Resume Next
If InStr(UCase(TargetEvent.TargetInstance.Message),”NETWORK SERVICE”) > 0 Then WScript.Quit
If InStr(UCase(TargetEvent.TargetInstance.Message),”SYSTEM”) > 0 Then WScript.Quit
Dim objreg, arrMessage, arrUserName, objWMIService, objProcess, test
Dim strUserName, intLockout, errReturn, strValueName
Dim objStartup, objConfig
‘Parse message for required information
arrMessage = Split(TargetEvent.TargetInstance.Message,vbCrLf)
If IsArray(arrMessage) Then
arrUserName = Split(arrMessage(4),vbTab)
If IsArray(arrUserName) then
strUserName = arrUserName(2)
‘As domain account is locked delete user’s counter key
strKeyPath = strKeyPath & “\” & strUserName
Set objReg=GetObject(”winmgmts:{impersonationLevel=impersonate}!\\” & strComputer & “\root\default:StdRegProv”)
errReturn = objReg.DeleteKey(HKEY_LOCAL_MACHINE,strKeyPath)
Set objReg = Nothing
‘Launch CHIMAERA.EXE and purge user’s ticket cache
Set objWMIService = GetObject(”winmgmts:{impersonationLevel=impersonate}!\\” _
& strComputer & “\root\CIMV2″)
Set objProcess = objWMIService.Get(”win32_Process”)
Set colProcesses = objWMIService.ExecQuery(”SELECT * FROM Win32_Process WHERE Name LIKE ‘%CHIMAERA.EXE%’”)
if colProcesses.Count = 0 then
errReturn = objProcess.Create(path & “\CHIMAERA.EXE /USERID=” & strUserName, Null, Null, intProcessID)
end if
Set objWMIService = Nothing
Set objProcess = Nothing
End If
Else
WScript.Quit
End If
Wscript.Quit
End Sub
‘ errReturn = objProcess.Create(”c:\windows\system32\rundll32.exe user32.dll, LockWorkStation”, Null, Null, intProcessID)
‘ strValueName = strUserName & “-LockErrReturn”
‘ if errReturn = 1 then test = &H1 Else test = &H0
‘ objReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,test
‘Dim i
‘For i = 0 To UBound(arrMessage)’ thing In arrMessage
‘If arrMessage <> “” then errReturn = objReg.SetDWORDValue(HKEY_LOCAL_MACHINE,strKeyPath,arrMessage(i),i)
‘errReturn = objReg.GetDWORDValue(HKEY_LOCAL_MACHINE,strKeyPath,strValueName,intBadLogonCount)
‘Next