// Copyright (C) 2024 Evan McBroom #include #include #include #include #include #include // The modified, compiled IDL file from: // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmi/ #include "ms_wmi_h.h" #include "ms_wmi_i.c" #pragma comment(lib, "WbemUuid.lib") WCHAR domainName[] = L"DOMAIN NAME"; WCHAR userName[] = L"USER NAME"; WCHAR password[] = L"PASSWORD"; WCHAR address[] = L"IP ADDRESS OR HOST NAME"; WCHAR process[] = L"calc.exe"; // An alternative option to set EOAC_STATIC_CLOAKING or EOAC_DYNAMIC_CLOAKING on an individual // interface instead of on the entire process (e.g., CoInitializeSecurity) if desired. bool SetProxyBlanket(IUnknown* iunknown) { return SUCCEEDED(CoSetProxyBlanket(iunknown, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_STATIC_CLOAKING)); } int main() { // Set an impersonation token that will use explicit credentials // when doing NTLM authentication to a remote host. Kerberos // tickets may also be added to the logon session via PTT while // the token is being impersonated. HANDLE token; size_t result = LogonUserW(userName, domainName, password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, &token); (void)ImpersonateLoggedOnUser(token); // Start COM and set it to always use the current impersonation token (e.g., EOAC_STATIC_CLOAKING), // and for COM to choose how to authenticate (e.g., authentication service = -1). NTLM and/or kerberos // can be explicitly set via the authentication list parameter if desired. (void)CoInitialize(nullptr); result = CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_STATIC_CLOAKING, nullptr); // Create an object on a remote host. // For the CLSID_WbemLevel1Login object, this requires you to use Administrative credentials. // CLSID_WbemLevel1Login does not allow you to immediately query IWbemLevel1Login so you // must query for IUnknown first. COSERVERINFO serverInfo = { 0 }; serverInfo.pwszName = address; MULTI_QI interfaces = { 0 }; interfaces.pIID = &IID_IUnknown; if (SUCCEEDED(result = CoCreateInstanceEx(CLSID_WbemLevel1Login, nullptr, CLSCTX_REMOTE_SERVER, &serverInfo, 1, &interfaces))) { // Convert IUnknown to IWbemLevel1Login. // This takes a few seconds to complete the first time you do it on the host, // or if you have not called it in a while and the previous instance has been // destroyed (e.g., due to a timeout). CComPtr iUnknown{ interfaces.pItf }; CComPtr wbemLevel1Login; if (SUCCEEDED(result = iUnknown.QueryInterface(&wbemLevel1Login))) { WCHAR address[] = L"ROOT\\CIMV2"; CComPtr wbemServices; if (SUCCEEDED(result = wbemLevel1Login->NTLMLogin(address, nullptr, 0, nullptr, &wbemServices))) { // Get the WMI object CComPtr win32Process; wbemServices->GetObjectW(CComBSTR{ L"Win32_Process" }, 0, nullptr, &win32Process, nullptr); // Get the signature (e.g., the definition) of the input parameters. CComPtr inSignature; win32Process->GetMethod(L"Create", 0, &inSignature, nullptr); CComPtr inParameters; // Create an instance of the input parameters for use to set them to // actual values. inSignature->SpawnInstance(0, &inParameters); CComVariant variant(process); inParameters->Put(L"CommandLine", 0, &variant, 0); // Execute the Win32_Process:Create and show its output parameters. CComPtr outParameters; wbemServices->ExecMethod(CComBSTR{ "Win32_Process" }, CComBSTR{ "Create" }, 0, nullptr, inParameters, &outParameters, nullptr); outParameters->Get(L"ProcessId", 0, &variant, nullptr, nullptr); std::cout << "ProcessId: " << variant.uintVal << std::endl; outParameters->Get(L"ReturnValue", 0, &variant, nullptr, nullptr); std::cout << "ReturnValue: " << variant.uintVal << std::endl; } std::cout << result; } } if (result) { std::cout << "Result: " << std::hex << result << std::endl; } }