Skip to content

MSBuild Inline Task Execution

Attackers abuse the signed MSBuild.exe to compile and run inline C# tasks from a project file, executing code under a trusted developer binary.

MSBuild.exe is the signed, Microsoft-shipped build engine that ships with the .NET Framework and Visual Studio. Its legitimate job is to read a project file (.csproj, .proj, .xml) and execute the build tasks it describes. Because MSBuild can compile and run arbitrary C# defined inline in that project file — through the Microsoft.Build.Tasks.CodeTaskFactory "inline task" feature — it doubles as a fully featured code-execution and compilation engine that lives on disk as a trusted binary.

Attackers favour this because the malicious source never has to be a PE on disk: the payload is plain C# embedded in an XML project file, compiled in memory at build time by a Microsoft-signed process. This bypasses application allow-listing that trusts MSBuild, defeats signature-based AV scanning of the dropped file (it is text), and blends into environments where developer tooling is expected. Analysts encounter it as an MSBuild process loading a .csproj or oddly-named project file from a user-writable path.

How it works

The attacker drops an XML project file containing a UsingTask with an inline Task body, then points MSBuild at it:

text
MSBuild.exe C:\Users\Public\build.csproj

Inside build.csproj, a CodeTaskFactory task wraps C# in a <Code Type="Class" Language="cs"> block. At build time MSBuild compiles that snippet and invokes its Execute() method — which is where the shellcode loader or beacon lives. There is no compiler invocation visible on the command line and no second binary: the build engine itself does the compiling.

The recognisable indicators are MSBuild.exe run with a single project-file argument from %TEMP%, %APPDATA%, \Public\, or a Downloads folder, and a project file whose contents reference CodeTaskFactory, Microsoft.Build.Tasks.v4.0.dll, <Code, or P/Invoke strings like VirtualAlloc and CreateThread — none of which belong in a normal build.

Detection & analysis

Static analysis:

  • Triage the referenced project file as the real sample: it is XML text. Search it for CodeTaskFactory, UsingTask, <Code Type=, Language="cs", and inline C# that imports kernel32/ntdll or contains base64/hex blobs. Legitimate build files orchestrate compilers and copy outputs; they rarely contain raw P/Invoke shellcode loaders.
  • Flag project files in user-writable directories, with mismatched extensions (.xml, .txt, .log that are actually MSBuild XML), or that are launched standalone rather than as part of a solution build.

Dynamic analysis:

  • In a sandbox, watch for MSBuild.exe writing compiler temp artifacts to %TEMP% and then allocating executable memory, spawning children, or opening outbound sockets. A build engine making C2 connections or injecting into another process is the giveaway.
  • Inspect the parent/child tree. Benign MSBuild is spawned by devenv.exe, dotnet.exe, CI agents, or cmd/powershell inside a developer context with a solution. Malicious instances are commonly spawned by Office apps, wscript.exe, mshta.exe, or a phishing-delivered loader, on hosts with no developer footprint.

Detection rule hint:

Alert on Sysmon Event ID 1 where Image ends with \MSBuild.exe AND the command line references a project file outside normal source/build directories (e.g. under \Users\Public\, \AppData\, \Temp\, \Downloads\), OR the parent process is an Office application or script host. Correlate with Event ID 7 (image loaded — Microsoft.Build.Tasks*.dll), Event ID 11 (file create of compiler temp output), and Event ID 3 (network connection) from the same PID to confirm inline-task abuse rather than a real build.

Votes

Comments(0)