void DisplayDacl(HANDLE hToken); std::wstring GetAccountName(PSID pSid) { DWORD nameSize = 0, domSize = 0; SID_NAME_USE snu; LookupAccountSid(NULL, pSid, NULL, &nameSize, NULL, &domSize, &snu); if(nameSize) { std::wstring name(nameSize, 0), domain(domSize, 0); LookupAccountSid(NULL, pSid, &name[0], &nameSize, &domain[0], &domSize, &snu); name.erase(name.length() - 1); return name; } else return L""; } void DisplayGroupMembership(HANDLE hToken) { DWORD required = 0; GetTokenInformation(hToken, TokenGroups, NULL, 0, &required); std::vector buffer(required); if(GetTokenInformation(hToken, TokenGroups, &buffer[0], required, &required)) { PTOKEN_GROUPS pGrps = reinterpret_cast(&buffer[0]); for(DWORD i = 0; i < pGrps->GroupCount; ++i) { const SID_AND_ATTRIBUTES& attrs = pGrps->Groups[i]; std::wcout << L"Group: " << GetAccountName(attrs.Sid) << L", Attributes: " << std::hex << attrs.Attributes << '\n'; } } else { DWORD err = GetLastError(); std::cout << "DisplayGroupMembership failed " << err << '\n'; } } void PrintTokenUser(HANDLE hToken) { DWORD required = 0; GetTokenInformation(hToken, TokenUser, NULL, 0, &required); std::vector buffer(required); if(GetTokenInformation(hToken, TokenUser, &buffer[0], required, &required)) { PTOKEN_USER pUser = reinterpret_cast(&buffer[0]); const SID_AND_ATTRIBUTES& attrs = pUser->User; std::wcout << L"User: " << GetAccountName(attrs.Sid) << L", Attributes: " << std::hex << attrs.Attributes << '\n'; } else { DWORD err = GetLastError(); std::cout << "PrintTokenUser failed " << err << '\n'; } } HANDLE DisplayElevation(HANDLE hToken) { TOKEN_ELEVATION elevated = {0}; DWORD required = sizeof(elevated); if(GetTokenInformation(hToken, TokenElevation, &elevated, required, &required)) { std::cout << "Is token elevated? " << std::boolalpha << static_cast(elevated.TokenIsElevated) << '\n'; } else { DWORD err = GetLastError(); std::cout << "DisplayElevation, TokenElevation failed " << err << '\n'; } TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault; required = sizeof(type); bool thisIsElevated = false; if(GetTokenInformation(hToken, TokenElevationType, &type, required, &required)) { LPCSTR szElevatedType[] = {"", "TokenElevationTypeDefault", "TokenElevationTypeFull", "TokenElevationTypeLimited"}; std::cout << szElevatedType[type] << '\n'; thisIsElevated = (type == TokenElevationTypeFull); } else { DWORD err = GetLastError(); std::cout << "DisplayElevation, TokenElevationType failed " << err << '\n'; } TOKEN_STATISTICS stats; required = sizeof(stats); if(GetTokenInformation(hToken, TokenStatistics, &stats, required, &required)) { std::cout << "Type = " << stats.TokenType << '\n'; std::cout << "Impersonation level = " << stats.ImpersonationLevel << '\n'; } else { DWORD err = GetLastError(); std::cout << "DisplayElevation, TokenStatistics failed " << err << '\n'; } TOKEN_LINKED_TOKEN linkedToken = {0}; required = sizeof(linkedToken); if(!GetTokenInformation(hToken, TokenLinkedToken, &linkedToken, required, &required)) { DWORD err = GetLastError(); std::cout << "DisplayElevation, TokenLinkedToken failed " << err << '\n'; } if(linkedToken.LinkedToken) { std::cout << "Trying to run winver with linked token\n"; STARTUPINFO si = {sizeof(si), 0}; PROCESS_INFORMATION pi = {0}; if(!CreateProcessWithTokenW(linkedToken.LinkedToken, 0, NULL, L"C:\\Windows\\System32\\Winver.exe", 0, NULL, NULL, &si, &pi)) { DWORD err = GetLastError(); std::cout << "Initial attempt at CreateProcessWithTokenW failed " << err << '\n'; HANDLE hDupToken = NULL; DuplicateTokenEx(linkedToken.LinkedToken, READ_CONTROL | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, SecurityAnonymous, TokenPrimary, &hDupToken); if(hDupToken) { if(!CreateProcessWithTokenW(hDupToken, 0, NULL, L"C:\\Windows\\System32\\Winver.exe", 0, NULL, NULL, &si, &pi)) { DWORD err = GetLastError(); std::cout << "Second attempt at CreateProcessWithTokenW failed " << err << '\n'; } CloseHandle(linkedToken.LinkedToken); linkedToken.LinkedToken = hDupToken; } else { DWORD err = GetLastError(); std::cout << "DuplicateTokenEx failed " << err << '\n'; } } if(pi.hProcess) { CloseHandle(pi.hThread); WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); } } return linkedToken.LinkedToken; } BOOL StandardAccessDesc(ACCESS_MASK amPermissions) { GENERIC_MAPPING gm = {GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE, GENERIC_ALL}; if(amPermissions & DELETE) { _putts(TEXT("\t\tDelete the Object")); } if(amPermissions & READ_CONTROL) { _putts(TEXT("\t\tRead the Security Descriptor")); } if(amPermissions & WRITE_DAC) { _putts(TEXT("\t\tWrite/Amend the Object DACL")); } if(amPermissions & WRITE_OWNER) { _putts(TEXT("\t\tWrite/Amend the Object Owner")); } if(amPermissions & SYNCHRONIZE) { _putts(TEXT("\t\tUse Synchronization Functions on the Object")); } if(amPermissions & ACCESS_SYSTEM_SECURITY) { _putts(TEXT("\t\tRead/Write the SACL")); } if(amPermissions & GENERIC_READ) { _putts(TEXT("\t\tRequest Generic Read Permissions")); } if(amPermissions & GENERIC_WRITE) { _putts(TEXT("\t\tRequest Generic Write Permissions")); } if(amPermissions & GENERIC_EXECUTE) { _putts(TEXT("\t\tRequest Generic Executable Permissions")); } if(amPermissions & GENERIC_ALL) { _putts(TEXT("\t\tRequest All Object Specific Permissions")); } _putts(TEXT("")); MapGenericMask(&amPermissions, &gm); return !amPermissions; } void TokenAccessDesc(ACCESS_MASK amPermissions) { if(amPermissions == TOKEN_ALL_ACCESS) { _putts(TEXT("\t\tAccess All Object Specific Permissions\n")); return; } if(amPermissions & TOKEN_WRITE) { amPermissions &= (~TOKEN_WRITE); amPermissions |= TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_PRIVILEGES; } if(amPermissions & TOKEN_ADJUST_DEFAULT) { _putts(TEXT("\t\tAdjust the Default Owner, Group, or DACL")); } if(amPermissions & TOKEN_ADJUST_GROUPS) { _putts(TEXT("\t\tChange Attributes of the Token Groups")); } if(amPermissions & TOKEN_ADJUST_PRIVILEGES) { _putts(TEXT("\t\tModify Privileges")); } if(amPermissions & TOKEN_ADJUST_SESSIONID) { _putts(TEXT("\t\tChange the Session ID")); } if(amPermissions & TOKEN_ASSIGN_PRIMARY) { _putts(TEXT("\t\tAssign to a Process as a Primary Token")); } if(amPermissions & TOKEN_DUPLICATE) { _putts(TEXT("\t\tDuplicate the Token")); } if((amPermissions & TOKEN_EXECUTE) || (amPermissions & TOKEN_IMPERSONATE)) { _putts(TEXT("\t\tUse the Token in Impersonation")); } if((amPermissions & TOKEN_QUERY) || (amPermissions & TOKEN_READ)) { _putts(TEXT("\t\tQuery the Token")); } if(amPermissions & TOKEN_QUERY_SOURCE) { _putts(TEXT("\t\tQuery the Source of the Token")); } _putts(TEXT("")); } void PrintTokenSecurityInfo(const PACL lpAcl) { if(lpAcl == NULL) { _putts(TEXT("All accounts have full access (NULL DACL)")); return; } for(WORD i = 0; i < lpAcl->AceCount; ++i) { ACCESS_ALLOWED_ACE* pAce = NULL; if(!GetAce(lpAcl, i, (LPVOID*)&pAce)) { return; } std::wstring account = GetAccountName((PSID)&(pAce->SidStart)); std::wcout << account; if(pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE || pAce->Header.AceType == ACCESS_ALLOWED_CALLBACK_ACE_TYPE) { _tprintf(TEXT(" has access 0x%x and can:\n"), pAce->Mask); } else if (pAce->Header.AceType == ACCESS_DENIED_ACE_TYPE || pAce->Header.AceType == ACCESS_DENIED_CALLBACK_ACE_TYPE) { _tprintf(TEXT(" has denied access 0x%x and cannot:\n"), pAce->Mask); } if(StandardAccessDesc(pAce->Mask) == 0) { TokenAccessDesc(pAce->Mask); } } } void DisplayDacl(HANDLE hToken) { PSECURITY_DESCRIPTOR pSD = WinLib::GetSecurityDescriptor(hToken, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION); if(pSD) { PACL pAcl; BOOL bDacl, bDefault; GetSecurityDescriptorDacl(pSD, &bDacl, &pAcl, &bDefault); PrintTokenSecurityInfo(pAcl); CoTaskMemFree(pSD); } else { DWORD err = GetLastError(); std::cout << "Failed to get security descriptor for token " << err << '\n'; } } HANDLE PrintTokenInfo(HANDLE hToken) { static DWORD i = 0; ++i; std::cout << "*** Token #" << i << " ***\n"; PrintTokenUser(hToken); std::cout << std::endl; DisplayGroupMembership(hToken); std::cout << std::endl; DisplayDacl(hToken); HANDLE hLinkedToken = DisplayElevation(hToken); std::cout << std::endl; return hLinkedToken; } void DoTokenInfo() { HANDLE hToken = NULL; OpenProcessToken(GetCurrentProcess(), READ_CONTROL | TOKEN_QUERY | TOKEN_DUPLICATE, &hToken); if(hToken) { HANDLE hTemp = hToken; DWORD times = 0; while((hToken = PrintTokenInfo(hToken)) && (times < 3)) { CloseHandle(hTemp); hTemp = hToken; ++times; } CloseHandle(hToken); } return 0; } #include std::wstring GetAccountName(PSID pSid) { DWORD nameSize = 0, domSize = 0; SID_NAME_USE snu; LookupAccountSid(NULL, pSid, NULL, &nameSize, NULL, &domSize, &snu); if(nameSize) { std::wstring name(nameSize, 0), domain(domSize, 0); LookupAccountSid(NULL, pSid, &name[0], &nameSize, &domain[0], &domSize, &snu); name.erase(name.end() - 1); return name; } else return L""; } PSID GetAccountSid(const std::wstring& domain, const std::wstring& userName) { DWORD sidSize = 0, domSize = 0; SID_NAME_USE snu; LookupAccountName(domain.c_str(), userName.c_str(), NULL, &sidSize, NULL, &domSize, &snu); if(sidSize) { PSID pSid = LocalAlloc(LPTR, sidSize); std::wstring refedDomain(domSize, 0); if(LookupAccountName(domain.c_str(), userName.c_str(), pSid, &sidSize, &refedDomain[0], &domSize, &snu)) { return pSid; } LocalFree(pSid); return NULL; } else return NULL; } #include BOOL GetLogonSid(HANDLE hToken, PSID* ppSid) { DWORD dwLength = 0; PTOKEN_GROUPS ptuLogon = NULL; if(NULL == ppSid || NULL == hToken) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } GetTokenInformation(hToken, TokenLogonSid, NULL, 0, &dwLength); if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) { return FALSE; } ptuLogon = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, dwLength); if(!ptuLogon) { return FALSE; } if(!GetTokenInformation(hToken, TokenLogonSid, ptuLogon, dwLength, &dwLength)) { HeapFree(GetProcessHeap(), 0, ptuLogon); return FALSE; } RtlMoveMemory(ptuLogon, ptuLogon->Groups[0].Sid, GetLengthSid(ptuLogon->Groups[0].Sid)); *ppSid = (PSID)ptuLogon; return TRUE; } #include void PrintSidsAndUsers() { DWORD dwSession = 0; ProcessIdToSessionId(GetCurrentProcessId(), &dwSession); std::wofstream file(L"D:\\blog stuff\\test.txt", std::ios::app); file << L"Session: " << dwSession << L'\n'; HANDLE hWinSta = static_cast(GetProcessWindowStation()); DWORD lengthRequired = 0; GetUserObjectInformation(hWinSta, UOI_USER_SID, NULL, 0, &lengthRequired); std::vector sidBuffer(lengthRequired); LPWSTR sidAsString = NULL; if(lengthRequired) { GetUserObjectInformation(hWinSta, UOI_USER_SID, &sidBuffer[0], lengthRequired, &lengthRequired); PSID pWinstaSid = &sidBuffer[0]; ConvertSidToStringSid(pWinstaSid, &sidAsString); //std::wcout << L"\nWindowStation user: " << GetAccountName(pWinstaSid) << L", SID: " << sidAsString << L'\n'; file << L"\nWindowStation user: " << GetAccountName(pWinstaSid) << L", SID: " << sidAsString << L'\n'; LocalFree(sidAsString); } HANDLE hToken = NULL; if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { PSID pTokenSid = NULL; GetTokenInformation(hToken, TokenUser, NULL, 0, &lengthRequired); sidBuffer.resize(lengthRequired); GetTokenInformation(hToken, TokenUser, &sidBuffer[0], lengthRequired, &lengthRequired); PSID pLogonSid = NULL; if(GetLogonSid(hToken, &pLogonSid)) { ConvertSidToStringSid(pLogonSid, &sidAsString); //std::wcout << hToken << L" Token Logon SID: " << sidAsString << L", User: " << GetAccountName(pLogonSid) << L'\n'; file << hToken << L" Token Logon SID: " << sidAsString << L", User: " << GetAccountName(pLogonSid) << L'\n'; LocalFree(sidAsString); HeapFree(GetProcessHeap(), 0, pLogonSid); } else { DWORD err = GetLastError(); //std::cout << "GetLogonSid failed " << err << '\n'; file << L"GetLogonSid failed " << err << L'\n'; } CloseHandle(hToken); PTOKEN_USER pTokUser = reinterpret_cast(&sidBuffer[0]); ConvertSidToStringSid(pTokUser->User.Sid, &sidAsString); //std::wcout << L"Token user: " << GetAccountName(pTokUser->User.Sid) << L", SID: " << sidAsString << L'\n'; file << L"Token user: " << GetAccountName(pTokUser->User.Sid) << L", SID: " << sidAsString << L'\n'; LocalFree(sidAsString); LPWSTR lpName = NULL; WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSUserName, &lpName, &lengthRequired); if(lpName) { //std::wcout << L"WTS User " << lpName; file << L"WTS User " << lpName; PSID pWTSSid = GetAccountSid(L"", lpName); WTSFreeMemory(lpName); if(pWTSSid) { ConvertSidToStringSid(pWTSSid, &sidAsString); //std::wcout << L", SID: " << sidAsString; file << L", SID: " << sidAsString; LocalFree(sidAsString); LocalFree(pWTSSid); } //std::cout << std::endl; file << std::endl; } } } void CreateLuaProcess() { HANDLE hProcToken; BOOL bDuped = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, &hProcToken); TOKEN_LINKED_TOKEN tok = {0}; bDuped = GetTokenInformation(hProcToken, TokenLinkedToken, &tok, sizeof(tok), (PDWORD)&bDuped); HANDLE hElevatedToken = NULL; bDuped = DuplicateTokenEx(tok.LinkedToken, TOKEN_QUERY | TOKEN_IMPERSONATE, NULL, SecurityIdentification, TokenImpersonation, &hElevatedToken); SECURITY_IMPERSONATION_LEVEL impLevel = SecurityAnonymous; GetTokenInformation(tok.LinkedToken, TokenImpersonationLevel, &impLevel, sizeof(impLevel), (PDWORD)&bDuped); CloseHandle(tok.LinkedToken); TryCreateFile(); bDuped = ImpersonateLoggedOnUser(hElevatedToken); TryCreateFile(); HANDLE hDupToken = NULL; /*bDuped = DuplicateTokenEx(hElevatedToken, TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, NULL, SecurityIdentification, TokenPrimary, &hDupToken); if(hElevatedToken) { CloseHandle(hElevatedToken); }*/ // CreateRestrictedToken(LUA_TOKEN) with the settokeninformation below will create a knobbled process //bDuped = CreateRestrictedToken(hProcToken, LUA_TOKEN, 0, NULL, 0, NULL, 0, NULL, &hDupToken); CloseHandle(hProcToken); if(bDuped) { /*PSID pSid = NULL; SID_IDENTIFIER_AUTHORITY sla = SECURITY_MANDATORY_LABEL_AUTHORITY; AllocateAndInitializeSid(&sla, 1, SECURITY_MANDATORY_MEDIUM_RID, 0, 0, 0, 0, 0, 0, 0, &pSid); DWORD setVirtual = TRUE; bDuped = SetTokenInformation(hDupToken, TokenVirtualizationAllowed, &setVirtual, sizeof(setVirtual)); bDuped = SetTokenInformation(hDupToken, TokenVirtualizationEnabled, &setVirtual, sizeof(setVirtual)); SID_AND_ATTRIBUTES integrity = {pSid, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED}; bDuped = SetTokenInformation(hDupToken, TokenIntegrityLevel, &integrity, sizeof(integrity)); FreeSid(pSid);*/ STARTUPINFO si = {sizeof(si), 0}; PROCESS_INFORMATION pi = {0}; WCHAR process[] = L"D:\\Windows\\system32\\winver.exe"; //if(CreateProcessAsUser(hDupToken, NULL, process, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) if(CreateProcess(NULL, process, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { DWORD err = GetLastError(); std::cout << "Failed to start process: " << err << '\n'; } RevertToSelf(); CloseHandle(hDupToken); } return 0; }