MSBuild (T1127.001) is a sub-technique of Trusted Developer Utilities Proxy Execution. MITRE places it under stealth and execution and lists Windows.
MSBuild is the Microsoft Build Engine that Visual Studio uses. It reads XML project files and builds software. That is a legitimate job, and it is exactly why it is a useful proxy for running something else.
How attackers use it
MITRE explains that adversaries can use MSBuild to proxy execution of code through a trusted Windows utility. The inline task capability, introduced with .NET version 4, lets C# or Visual Basic code be placed in an XML project file. MSBuild compiles and runs that inline task.
Because MSBuild.exe is a signed Microsoft binary, using it this way can execute arbitrary code and bypass application control defenses that are set to allow MSBuild.exe. The control sees a trusted program, while the real behavior is defined by a text file.
This has an important implication for software teams. A project file is code. It deserves review like code, especially when it comes from outside the team or changes in a pull request.
How to detect it
MITRE's strategy is a behavior chain for MSBuild on Windows. The analytic looks for MSBuild.exe invoked outside expected developer or build contexts, or with unusual arguments such as non-standard paths, remote shares or Base64 or obfuscated property values. Within a short window, it then looks for any of:
- spawning high-risk living-off-the-land binaries or script interpreters,
- writing new executables, DLLs or scripts into user-writable paths and running them,
- loading unsigned or user-writable modules,
- memory injection or thread creation into other processes, or
- outbound network connections.
Data to collect:
- Process creation with parent, full command line and image path. Security event 4688 with command line auditing, or Sysmon event ID 1.
- Image load events, such as Sysmon event ID 7.
- Network connection events, such as Sysmon event ID 3.
- File creation events, such as Sysmon event ID 11.
Baselines help. Know which hosts legitimately run msbuild.exe, which accounts run it, and from which parent processes. On a machine with no Visual Studio or build agent, any execution is a finding. On a build server, focus on project files from unexpected locations, such as temp folders or network shares.
How to reduce the risk
MITRE lists two mitigations:
- Disable or remove a feature or program. MSBuild.exe may not be necessary in your environment, and should be removed if it is not used.
- Execution prevention. Use application control to block msbuild.exe where it is not required. MITRE gives the example that in Windows 10 and Windows Server 2016 and later, Windows Defender Application Control policy rules can block msbuild.exe.
For the places where MSBuild must stay, narrow the exposure:
- Restrict where project files may be loaded from.
- Run build agents as low-privilege accounts, with limited network egress.
- Require review of changes to build and project files in your repositories, the same as for source code.
Check your own environment
- Which machines have MSBuild installed? Do they all need it?
- Is msbuild.exe blocked by application control on user workstations and servers that do not build software?
- Do you log process command lines and parents everywhere?
- Do you alert on msbuild.exe launched by Office, a browser, a script host or a service?
- Who can change build files in your repositories, and does a second person review them?
# Windows (PowerShell): check whether MSBuild is on the path of this machine (read-only)
Get-Command msbuild.exe -ErrorAction SilentlyContinue
# Windows (PowerShell): show any running MSBuild processes with their command lines (read-only)
Get-CimInstance Win32_Process -Filter "Name='MSBuild.exe'" | Select-Object ProcessId, ParentProcessId, CommandLine
A note for software and platform teams
Teams that build software on Windows often hold the strongest reason to keep MSBuild around, and the weakest controls around it. A few habits close most of the gap.
Treat project files and build scripts as code. They should live in version control, have an owner, and go through review. A change to a project file that adds an inline task, or points at an unfamiliar path, should be questioned as readily as a change to application code.
Separate build duties from everything else. A build agent that only builds, runs as a low-privilege account, and can reach only the package sources and artifact stores it needs, is much harder to turn into a foothold. Network egress limits on build agents also cut off the follow-on step in MITRE's chain, the outbound connection.
Finally, keep an eye on where project files come from at run time. A build started from a temp folder, a user download directory or a remote share is out of pattern for most teams. That one check, applied to process creation logs, catches a lot.
Try it yourself
Build files and pipeline changes belong in your pull request controls. This demo shows a pull request gate that checks changes before they merge. For a quick look at your own dependency manifests, the free in-browser scan at gold.safeguard.sh/scan needs no login and the file never leaves your machine.
Click through it at your own pace, or open it full screen.
Quick check
Why does MSBuild bypass some application control?
It is a signed Microsoft binary, so controls that allow msbuild.exe will let it run the inline code in a project file.
Which MSBuild capability makes this possible?
Inline tasks, introduced with .NET version 4, which let C# or Visual Basic code sit in an XML project file that MSBuild compiles and runs.
What is the cleanest mitigation?
Remove MSBuild where it is not needed, or block msbuild.exe with application control such as WDAC policy.