BOOL My_CreateProcessAsUserA() { HANDLE hToken=NULL; LPCSTR lpApplicationName=NULL; LPSTR lpCommandLine=NULL; LPSECURITY_ATTRIBUTES lpProcessAttributes=NULL; LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL; BOOL bInheritHandles=NULL; DWORD dwCreationFlags=NULL; LPVOID lpEnvironment=NULL; LPCSTR lpCurrentDirectory=NULL; LPSTARTUPINFOA lpStartupInfo=NULL; LPPROCESS_INFORMATION lpProcessInformation=NULL; BOOL returnVal_Real = NULL; BOOL returnVal_Intercepted = NULL; DWORD error_Real = 0; DWORD error_Intercepted = 0; __try{ disableInterception(); returnVal_Real = CreateProcessAsUserA (hToken,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation); error_Real = GetLastError(); enableInterception(); returnVal_Intercepted = CreateProcessAsUserA (hToken,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation); error_Intercepted = GetLastError(); }__except(puts("in filter"), 1){puts("exception caught");} return ((returnVal_Real == returnVal_Intercepted) && (error_Real == error_Intercepted)); }
int pacifica_switch_process_user(char *user, char *pw, char *program) { DWORD len; HANDLE token; PROCESS_INFORMATION pi; STARTUPINFOA si; memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.lpDesktop = ""; //FIXME Still need to pull this out of storage somehow... int res = LogonUserA(user, ".", pw, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, &token); if(res == 0) { return GetLastError(); } res = CreateProcessAsUserA(token, NULL, program, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); if(res == 0) { return GetLastError(); } res = WaitForSingleObject(pi.hProcess, INFINITE); if(res == 0) { return GetLastError(); } res = GetExitCodeProcess(pi.hProcess, &len); if(res == 0) { return GetLastError(); } return 0; }
/* good1() uses if(5!=5) instead of if(5==5) */ static void good1() { if(5!=5) { /* INCIDENTAL: CWE 561 Dead Code, the code below will never run */ printLine("Benign, fixed string"); } else { { STARTUPINFOA si; PROCESS_INFORMATION pi; HANDLE pHandle = NULL; /* FIX: The commandLine parameter to CreateProcessAsUser() contains quotes surrounding the executable path. */ if(!CreateProcessAsUserA(pHandle, NULL, "\"C:\\Program Files\\GoodApp\" arg1 arg2", NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) { printLine("CreateProcessAsUser failed"); RevertToSelf(); CloseHandle(pHandle); return; } else { printLine("CreateProcessAUser successful"); } /* Wait until child process exits. */ WaitForSingleObject(pi.hProcess, INFINITE); /* Close process and thread handles.*/ CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(pHandle); } } }
void CWE272_Least_Privilege_Violation__w32_char_CreateProcessAsUser_03_bad() { if(5==5) { { STARTUPINFOA si; PROCESS_INFORMATION pi; HANDLE pHandle = NULL; /* FLAW: The commandLine parameter to CreateProcessAsUser() contains a space in it and does not surround the executable path with quotes. A malicious executable could be run because of the way the function parses spaces. The process will attempt to run "Program.exe," if it exists, instead of the intended "GoodApp.exe" */ if(!CreateProcessAsUserA(pHandle, NULL, "C:\\Program Files\\GoodApp arg1 arg2", NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) { printLine("CreateProcessAsUser failed"); RevertToSelf(); CloseHandle(pHandle); return; } else { printLine("CreateProcessAUser successful"); } /* Wait until child process exits. */ WaitForSingleObject(pi.hProcess, INFINITE); /* Close process and thread handles.*/ CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(pHandle); } } }
static BOOL WINAPI MyCreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { if (VERBOSITY >= 2) { debugPrintf("inject: intercepting %s(\"%s\", \"%s\", ...)\n", __FUNCTION__, lpApplicationName, lpCommandLine); } BOOL bRet; bRet = CreateProcessAsUserA(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); MyCreateProcessCommon(bRet, dwCreationFlags, lpProcessInformation); return bRet; }
static int CreateRestrictedProcess(char *command, PROCESS_INFORMATION *processInfo, bool as_service) { int r; BOOL b; STARTUPINFOA si; HANDLE origToken; HANDLE restrictedToken; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; SID_AND_ATTRIBUTES dropSids[2]; /* Functions loaded dynamically */ __CreateRestrictedToken _CreateRestrictedToken = NULL; __IsProcessInJob _IsProcessInJob = NULL; __CreateJobObjectA _CreateJobObject = NULL; __SetInformationJobObject _SetInformationJobObject = NULL; __AssignProcessToJobObject _AssignProcessToJobObject = NULL; __QueryInformationJobObject _QueryInformationJobObject = NULL; HANDLE Kernel32Handle; HANDLE Advapi32Handle; SECURITY_ATTRIBUTES sa = {0}; HANDLE hRead, hWrite; /* create unnamed pipes */ sa.lpSecurityDescriptor = NULL; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; if (!CreatePipe(&hRead, &hWrite, &sa, 0)) elog(ERROR, "cannot create pipes"); DuplicateHandle(GetCurrentProcess(), hWrite, GetCurrentProcess(), NULL, 0, FALSE, DUPLICATE_SAME_ACCESS); ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = hRead; si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); Advapi32Handle = LoadLibraryA("ADVAPI32.DLL"); if (Advapi32Handle != NULL) { _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken"); } if (_CreateRestrictedToken == NULL) { /* * NT4 doesn't have CreateRestrictedToken, so just call ordinary * CreateProcess */ if (Advapi32Handle != NULL) FreeLibrary(Advapi32Handle); b = CreateProcessA(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo); goto done; } /* Open the current token to use as a base for the restricted one */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken)) { elog(WARNING, "could not open process token: %lu", GetLastError()); return -1; } /* Allocate list of SIDs to remove */ ZeroMemory(&dropSids, sizeof(dropSids)); if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) || !AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid)) { elog(WARNING, "could not allocate SIDs: %lu", GetLastError()); return -1; } b = _CreateRestrictedToken(origToken, DISABLE_MAX_PRIVILEGE, sizeof(dropSids) / sizeof(dropSids[0]), dropSids, 0, NULL, 0, NULL, &restrictedToken); FreeSid(dropSids[1].Sid); FreeSid(dropSids[0].Sid); CloseHandle(origToken); FreeLibrary(Advapi32Handle); if (!b) { elog(WARNING, "could not create restricted token: %lu", GetLastError()); return -1; } #ifndef __CYGWIN__ AddUserToTokenDacl(restrictedToken); #endif r = CreateProcessAsUserA(restrictedToken, NULL, command, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo); Kernel32Handle = LoadLibraryA("KERNEL32.DLL"); if (Kernel32Handle != NULL) { _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob"); _CreateJobObject = (__CreateJobObjectA) GetProcAddress(Kernel32Handle, "CreateJobObjectA"); _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject"); _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject"); _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject"); } /* Verify that we found all functions */ if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL) { /* * IsProcessInJob() is not available on < WinXP, so there is no need * to log the error every time in that case */ OSVERSIONINFO osv; osv.dwOSVersionInfoSize = sizeof(osv); if (!GetVersionEx(&osv) || /* could not get version */ (osv.dwMajorVersion == 5 && osv.dwMinorVersion > 0) || /* 5.1=xp, 5.2=2003, etc */ osv.dwMajorVersion > 5) /* anything newer should have the API */ /* * Log error if we can't get version, or if we're on WinXP/2003 or * newer */ elog(WARNING, "could not locate all job object functions in system API"); } else { BOOL inJob; if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob)) { if (!inJob) { /* * Job objects are working, and the new process isn't in one, * so we can create one safely. If any problems show up when * setting it, we're going to ignore them. */ HANDLE job; char jobname[128]; sprintf(jobname, "PostgreSQL_%lu", processInfo->dwProcessId); job = _CreateJobObject(NULL, jobname); if (job) { JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit; JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions; JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit; OSVERSIONINFO osv; ZeroMemory(&basicLimit, sizeof(basicLimit)); ZeroMemory(&uiRestrictions, sizeof(uiRestrictions)); ZeroMemory(&securityLimit, sizeof(securityLimit)); basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS; basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS; _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit)); uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS | JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD | JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD; if (as_service) { osv.dwOSVersionInfoSize = sizeof(osv); if (!GetVersionEx(&osv) || osv.dwMajorVersion < 6 || (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0)) { /* * On Windows 7 (and presumably later), * JOB_OBJECT_UILIMIT_HANDLES prevents us from * starting as a service. So we only enable it on * Vista and earlier (version <= 6.0) */ uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES; } } _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions)); securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN; securityLimit.JobToken = restrictedToken; _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit)); _AssignProcessToJobObject(job, processInfo->hProcess); } } } } CloseHandle(restrictedToken); ResumeThread(processInfo->hThread); FreeLibrary(Kernel32Handle); done: /* * We intentionally don't close the job object handle, because we want the * object to live on until this program shuts down. */ if (r) { int fd; CloseHandle(hRead); if ((fd = _open_osfhandle((intptr_t) hWrite, O_WRONLY | O_TEXT)) != -1) return fd; else CloseHandle(hWrite); } else { CloseHandle(hRead); CloseHandle(hWrite); } return -1; }
bool ProcessStarter::Run(bool forceRun) { OSVERSIONINFO version = {sizeof(OSVERSIONINFO)}; GetVersionEx(&version); if (version.dwMajorVersion <= 5 && !forceRun) //dont need this on XP/Win2K return false; char winDir[260]; GetSystemDirectoryA(winDir,sizeof(winDir)); PHANDLE primaryToken = 0; try { if (version.dwMajorVersion <= 5) //win2K/XP primaryToken = GetCurrentUserTokenOld(); else primaryToken = GetCurrentUserToken(); } catch(std::exception &ex) { log << "exception :" << ex.what() << std::endl; } if (primaryToken == 0) { log << "primtok = 0" << std::endl; return false; } STARTUPINFOA StartupInfo; PROCESS_INFORMATION processInfo; memset(&StartupInfo,0,sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); #if 0 std::string command = std::string("\"") + winDir + "\\cmd.exe\" /C \""+ processPath_ + " " + arguments_ + "\""; #else std::string command = "\"" + processPath_ + "\""; if (arguments_.length() != 0) { command += " " + arguments_; } #endif log << "command:" << command << std::endl; void* lpEnvironment = NULL; if (!forceRun) { BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, primaryToken, FALSE); if (resultEnv == 0) { long nError = GetLastError(); } log << "CreateEnvironmentBlock ok" << std::endl; } BOOL result = CreateProcessAsUserA(*primaryToken, 0, (LPSTR)(command.c_str()), NULL,NULL, FALSE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, 0, &StartupInfo, &processInfo); log << "CreateProcessAsUserA " << result << " err 0x" << std::hex << std::setfill('0') << std::setw(8) << GetLastError() << std::endl; if (result != FALSE) log << "launched" << std::endl; else log << "didnt launch" << std::endl; if (!forceRun) CloseHandle(primaryToken); return (result != FALSE); }