Created
February 17, 2026 14:06
-
-
Save derekxmartin/e4cad69955ea5cb68c317cf2b0a4d6e4 to your computer and use it in GitHub Desktop.
msbuild Test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # MSBuild.exe Detection Signal — Purple Team Testing Plan | |
| **Classification:** Internal — PCSIRT / Red Team Use Only | |
| **Author:** Red Team Operations | |
| **Date:** February 2026 | |
| **Version:** 1.0 | |
| ----- | |
| ## 1. Objective | |
| Validate the PCSIRT detection signal for `msbuild.exe` abuse across three threat categories: | |
| 1. **Manual MSBuild execution** from interactive command prompts | |
| 1. **Atypical project file extensions** (`.csproj`, `.xml`, `.rsp`, `.proj`) | |
| 1. **Nonstandard command-line usage** deviating from normal developer build workflows | |
| Each test case includes the expected telemetry the detection should capture, enabling your PCSIRT team to confirm signal fidelity and coverage gaps. | |
| ----- | |
| ## 2. Scope & Prerequisites | |
| ### In-Scope Systems | |
| - Windows 10/11 endpoints with .NET Framework 4.x+ or .NET SDK installed | |
| - Endpoints with EDR/SIEM telemetry forwarding enabled | |
| ### Prerequisites | |
| - MSBuild available at standard paths: | |
| - `C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe` | |
| - `C:\Program Files\Microsoft Visual Studio\2022\<Edition>\MSBuild\Current\Bin\MSBuild.exe` | |
| - Test user account (non-admin preferred for baseline; admin for escalation tests) | |
| - Purple team coordination channel open with SOC/PCSIRT | |
| - **Change ticket approved** and test window scheduled | |
| - Sysmon (or equivalent) configured with ProcessCreate (Event ID 1), FileCreate (Event ID 11), and command-line logging | |
| ### Safety Controls | |
| - All test payloads are **benign** (calc.exe, whoami, or write to a local temp file) | |
| - No persistence mechanisms are installed | |
| - All test artifacts are cleaned up post-execution | |
| - Tests should be conducted on isolated/lab endpoints first | |
| ----- | |
| ## 3. Test Matrix Overview | |
| |Test ID|Category |Description |MITRE ATT&CK| | |
| |-------|---------------|----------------------------------------------------|------------| | |
| |MSB-01 |Manual Exec |MSBuild from cmd.exe |T1127.001 | | |
| |MSB-02 |Manual Exec |MSBuild from powershell.exe |T1127.001 | | |
| |MSB-03 |Manual Exec |MSBuild from non-standard parent (explorer, wscript)|T1127.001 | | |
| |MSB-04 |Atypical Files |Inline task in `.csproj` file |T1127.001 | | |
| |MSB-05 |Atypical Files |Inline task in `.xml` file |T1127.001 | | |
| |MSB-06 |Atypical Files |Response file (`.rsp`) execution |T1127.001 | | |
| |MSB-07 |Atypical Files |Custom `.proj` file with UsingTask |T1127.001 | | |
| |MSB-08 |Nonstandard CLI|Execution from temp/user directories |T1127.001 | | |
| |MSB-09 |Nonstandard CLI|Unusual flags and verbosity suppression |T1127.001 | | |
| |MSB-10 |Nonstandard CLI|MSBuild with no Visual Studio/SDK context |T1127.001 | | |
| |MSB-11 |Nonstandard CLI|MSBuild spawning suspicious child processes |T1127.001 | | |
| |MSB-12 |Negative Test |Legitimate developer build (should NOT alert) |N/A | | |
| ----- | |
| ## 4. Benign Payload Templates | |
| All test cases reference these project file templates. Save each to the test endpoint before starting. | |
| ### 4A. Inline C# Task — calc.exe (benign_calc.csproj) | |
| ```xml | |
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
| <Target Name="TestTarget"> | |
| <TestTask /> | |
| </Target> | |
| <UsingTask | |
| TaskName="TestTask" | |
| TaskFactory="CodeTaskFactory" | |
| AssemblyFile="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll"> | |
| <Task> | |
| <Code Type="Fragment" Language="cs"> | |
| <![CDATA[ | |
| System.Diagnostics.Process.Start("calc.exe"); | |
| ]]> | |
| </Code> | |
| </Task> | |
| </UsingTask> | |
| </Project> | |
| ``` | |
| ### 4B. Inline C# Task — whoami to file (benign_whoami.xml) | |
| ```xml | |
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
| <Target Name="TestTarget"> | |
| <TestTask /> | |
| </Target> | |
| <UsingTask | |
| TaskName="TestTask" | |
| TaskFactory="CodeTaskFactory" | |
| AssemblyFile="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll"> | |
| <Task> | |
| <Using Namespace="System.IO" /> | |
| <Code Type="Fragment" Language="cs"> | |
| <![CDATA[ | |
| string user = System.Security.Principal.WindowsIdentity.GetCurrent().Name; | |
| File.WriteAllText(@"C:\Temp\msbuild_test_output.txt", "Test executed by: " + user); | |
| ]]> | |
| </Code> | |
| </Task> | |
| </UsingTask> | |
| </Project> | |
| ``` | |
| ### 4C. Response File (test.rsp) | |
| ``` | |
| /nologo | |
| /verbosity:quiet | |
| benign_calc.csproj | |
| ``` | |
| ### 4D. Benign Legitimate Build Project (legit_build.csproj) | |
| ```xml | |
| <Project Sdk="Microsoft.NET.Sdk"> | |
| <PropertyGroup> | |
| <OutputType>Exe</OutputType> | |
| <TargetFramework>net6.0</TargetFramework> | |
| </PropertyGroup> | |
| </Project> | |
| ``` | |
| With accompanying `Program.cs`: | |
| ```csharp | |
| Console.WriteLine("Hello from legitimate build"); | |
| ``` | |
| ----- | |
| ## 5. Detailed Test Procedures | |
| ----- | |
| ### MSB-01: Manual MSBuild from cmd.exe | |
| **Objective:** Detect MSBuild launched interactively from `cmd.exe` executing an inline task. | |
| **Steps:** | |
| 1. Open `cmd.exe` as the test user | |
| 1. Execute: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj | |
| ``` | |
| 1. Confirm `calc.exe` launches | |
| 1. Record timestamp | |
| **Expected Telemetry:** | |
| - Process Create: `MSBuild.exe` with parent `cmd.exe` | |
| - Command line contains a `.csproj` path outside a typical source/build directory | |
| - Child process: `calc.exe` spawned by `MSBuild.exe` | |
| **Detection Signal Should Fire:** YES | |
| ----- | |
| ### MSB-02: Manual MSBuild from PowerShell | |
| **Objective:** Detect MSBuild launched from `powershell.exe` or `pwsh.exe`. | |
| **Steps:** | |
| 1. Open PowerShell as the test user | |
| 1. Execute: | |
| ```powershell | |
| & "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe" C:\Temp\benign_calc.csproj | |
| ``` | |
| 1. Repeat with `pwsh.exe` if installed | |
| 1. Record timestamps | |
| **Expected Telemetry:** | |
| - Process Create: `MSBuild.exe` with parent `powershell.exe` or `pwsh.exe` | |
| - Command line referencing project file in non-development directory | |
| **Detection Signal Should Fire:** YES | |
| ----- | |
| ### MSB-03: MSBuild from Non-Standard Parent Process | |
| **Objective:** Detect MSBuild spawned by unusual parent processes (simulates malware dropper behavior). | |
| **Steps:** | |
| 1. Create `launch_msbuild.vbs`: | |
| ```vbscript | |
| Set objShell = CreateObject("WScript.Shell") | |
| objShell.Run "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj", 0, True | |
| ``` | |
| 1. Double-click the `.vbs` file (parent = `wscript.exe`) | |
| 1. Alternatively, create a scheduled task: | |
| ``` | |
| schtasks /create /tn "MSBuildTest" /tr "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj" /sc once /st 23:59 | |
| schtasks /run /tn "MSBuildTest" | |
| schtasks /delete /tn "MSBuildTest" /f | |
| ``` | |
| 1. Record parent process chains | |
| **Expected Telemetry:** | |
| - `MSBuild.exe` with parent `wscript.exe`, `svchost.exe`, or `taskeng.exe`/`taskhostw.exe` | |
| - These parent processes almost never legitimately invoke MSBuild | |
| **Detection Signal Should Fire:** YES (high confidence) | |
| ----- | |
| ### MSB-04: Atypical File — .csproj with Inline Task (Non-Build Context) | |
| **Objective:** Detect `.csproj` files containing inline C# tasks executed outside of Visual Studio or `dotnet build`. | |
| **Steps:** | |
| 1. Copy `benign_calc.csproj` to `C:\Temp\` | |
| 1. Execute from cmd: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj | |
| ``` | |
| 1. Record command line and file hash | |
| **Expected Telemetry:** | |
| - MSBuild executing `.csproj` from `C:\Temp\` (not a VS solution directory) | |
| - Project file contains `<UsingTask>` with `CodeTaskFactory` | |
| - No corresponding `.sln` file in directory | |
| **Detection Signal Should Fire:** YES | |
| **Note to PCSIRT:** The key differentiator from legitimate use is the file location and the absence of a solution context. Consider building detection logic that correlates file path patterns. | |
| ----- | |
| ### MSB-05: Atypical File — .xml Extension | |
| **Objective:** Detect MSBuild processing XML files that contain project definitions (commonly used by attackers to evade extension-based filtering). | |
| **Steps:** | |
| 1. Copy payload template 4B as `C:\Temp\benign_whoami.xml` | |
| 1. Execute: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_whoami.xml | |
| ``` | |
| 1. Verify `C:\Temp\msbuild_test_output.txt` was created | |
| 1. Record command line | |
| **Expected Telemetry:** | |
| - MSBuild command line references a `.xml` file (not `.csproj`, `.vbproj`, `.sln`) | |
| - File contains MSBuild project schema | |
| **Detection Signal Should Fire:** YES | |
| ----- | |
| ### MSB-06: Atypical File — Response File (.rsp) | |
| **Objective:** Detect MSBuild using response files, which can obscure the actual project being built from command-line logging. | |
| **Steps:** | |
| 1. Save payload template 4C as `C:\Temp\test.rsp` | |
| 1. Ensure `benign_calc.csproj` is at `C:\Temp\` | |
| 1. Execute: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe @C:\Temp\test.rsp | |
| ``` | |
| 1. Confirm calc launches | |
| 1. Record command line | |
| **Expected Telemetry:** | |
| - Command line contains `@` prefix indicating response file usage | |
| - The actual project file name may not appear in the process command line | |
| - `/verbosity:quiet` and `/nologo` flags present (suppresses build output) | |
| **Detection Signal Should Fire:** YES | |
| **PCSIRT Note:** This is a critical gap to test. If your signal only inspects the command line for project file names, `.rsp` usage will evade it. Consider alerting on the `@` prefix itself when combined with other indicators. | |
| ----- | |
| ### MSB-07: Atypical File — .proj Extension with UsingTask | |
| **Objective:** Detect `.proj` files, which are valid MSBuild files but rarely used in standard development workflows. | |
| **Steps:** | |
| 1. Copy `benign_calc.csproj` content to `C:\Temp\payload.proj` | |
| 1. Execute: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\payload.proj | |
| ``` | |
| 1. Confirm calc launches | |
| **Expected Telemetry:** | |
| - `.proj` extension in MSBuild command line | |
| - File contains `CodeTaskFactory` / inline code | |
| **Detection Signal Should Fire:** YES | |
| ----- | |
| ### MSB-08: Nonstandard CLI — Execution from User/Temp Directories | |
| **Objective:** Detect MSBuild processing project files from directories that are not typical build paths. | |
| **Steps:** | |
| 1. Copy `benign_calc.csproj` to each of these locations: | |
| - `C:\Users\<testuser>\Downloads\build.csproj` | |
| - `C:\Users\<testuser>\AppData\Local\Temp\build.csproj` | |
| - `C:\Users\Public\build.csproj` | |
| - `C:\ProgramData\build.csproj` | |
| 1. Execute MSBuild against each: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe "C:\Users\<testuser>\Downloads\build.csproj" | |
| ``` | |
| 1. Record each execution’s command line and parent process | |
| **Expected Telemetry:** | |
| - Project file path in user-writable directories (Downloads, Temp, AppData, Public, ProgramData) | |
| - Legitimate builds almost always reference paths under source repos or VS solution directories | |
| **Detection Signal Should Fire:** YES | |
| ----- | |
| ### MSB-09: Nonstandard CLI — Suspicious Flags & Verbosity Suppression | |
| **Objective:** Detect command-line patterns that suppress output or use unusual flag combinations. | |
| **Steps:** | |
| 1. Execute with stealth flags: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj /nologo /verbosity:quiet /noconsolelogger | |
| ``` | |
| 1. Execute with property overrides (common in staged attacks): | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj /p:Configuration=Release /p:Platform=x64 /nologo /v:q | |
| ``` | |
| 1. Execute with target specification: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj /t:TestTarget | |
| ``` | |
| 1. Record all command lines | |
| **Expected Telemetry:** | |
| - `/noconsolelogger` — suppresses all console output (very rare in legitimate use) | |
| - `/verbosity:quiet` or `/v:q` combined with non-standard file paths | |
| - Explicit `/t:` targeting unusual target names (not Build, Clean, Rebuild, Publish) | |
| **Detection Signal Should Fire:** YES (especially for `/noconsolelogger` combinations) | |
| ----- | |
| ### MSB-10: Nonstandard CLI — MSBuild Without Visual Studio / SDK Context | |
| **Objective:** Detect direct invocation of the .NET Framework MSBuild binary without any developer tooling context. | |
| **Steps:** | |
| 1. Open a plain `cmd.exe` (not Developer Command Prompt) | |
| 1. Invoke MSBuild by full path with no environment variables set: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\benign_calc.csproj | |
| ``` | |
| 1. Compare: Open a Visual Studio Developer Command Prompt and run a legitimate build | |
| 1. Document the environment differences (presence of `VSINSTALLDIR`, `MSBuildSDKsPath`, etc.) | |
| **Expected Telemetry:** | |
| - MSBuild invoked without `VSINSTALLDIR` or related environment variables | |
| - No prior `devenv.exe`, `dotnet.exe`, or `nuget.exe` process in the session | |
| **Detection Signal Should Fire:** YES (lower confidence — use as a signal enrichment, not standalone) | |
| ----- | |
| ### MSB-11: Nonstandard CLI — MSBuild Spawning Suspicious Child Processes | |
| **Objective:** Detect MSBuild spawning processes that are inconsistent with compilation (cmd, PowerShell, net, whoami, etc.). | |
| **Steps:** | |
| 1. Create `child_proc_test.csproj`: | |
| ```xml | |
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
| <Target Name="TestTarget"> | |
| <TestTask /> | |
| </Target> | |
| <UsingTask | |
| TaskName="TestTask" | |
| TaskFactory="CodeTaskFactory" | |
| AssemblyFile="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll"> | |
| <Task> | |
| <Code Type="Fragment" Language="cs"> | |
| <![CDATA[ | |
| var psi = new System.Diagnostics.ProcessStartInfo("cmd.exe", "/c whoami > C:\\Temp\\msbuild_child_test.txt"); | |
| psi.CreateNoWindow = true; | |
| System.Diagnostics.Process.Start(psi); | |
| ]]> | |
| </Code> | |
| </Task> | |
| </UsingTask> | |
| </Project> | |
| ``` | |
| 1. Execute: | |
| ``` | |
| C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe C:\Temp\child_proc_test.csproj | |
| ``` | |
| 1. Verify `C:\Temp\msbuild_child_test.txt` contains the username | |
| 1. Record the full process tree | |
| **Expected Telemetry:** | |
| - Process tree: `cmd.exe` → `MSBuild.exe` → `cmd.exe` → `whoami.exe` | |
| - Legitimate MSBuild child processes are typically: `csc.exe`, `vbc.exe`, `al.exe`, `ResGen.exe`, `aspnet_compiler.exe` | |
| - Suspicious children: `cmd.exe`, `powershell.exe`, `whoami.exe`, `net.exe`, `certutil.exe`, `rundll32.exe`, `regsvr32.exe`, `bitsadmin.exe` | |
| **Detection Signal Should Fire:** YES (high confidence) | |
| ----- | |
| ### MSB-12: Negative Test — Legitimate Developer Build | |
| **Objective:** Confirm the detection signal does NOT fire on standard developer build activity. | |
| **Steps:** | |
| 1. Open Visual Studio Developer Command Prompt | |
| 1. Navigate to a legitimate .NET project directory | |
| 1. Execute standard builds: | |
| ``` | |
| msbuild MySolution.sln /t:Build /p:Configuration=Debug | |
| dotnet build | |
| msbuild /t:Restore;Build /p:Configuration=Release | |
| ``` | |
| 1. Run `dotnet build` from a standard repo checkout | |
| 1. Execute a NuGet restore followed by build (common CI/CD pattern): | |
| ``` | |
| nuget restore MySolution.sln | |
| msbuild MySolution.sln /t:Build | |
| ``` | |
| 1. Record all telemetry | |
| **Expected Telemetry:** | |
| - Parent process: `devenv.exe`, `dotnet.exe`, or Developer Command Prompt `cmd.exe` with VS environment | |
| - Project files in source directories | |
| - Standard targets: Build, Clean, Rebuild, Restore, Publish | |
| - Child processes: `csc.exe`, `vbc.exe`, etc. | |
| **Detection Signal Should Fire:** NO | |
| ----- | |
| ## 6. Results Tracking Template | |
| |Test ID|Executed (Y/N)|Timestamp|Alert Fired (Y/N)|Alert ID / Rule Name|Latency (seconds)|Notes| | |
| |-------|--------------|---------|-----------------|--------------------|-----------------|-----| | |
| |MSB-01 | | | | | | | | |
| |MSB-02 | | | | | | | | |
| |MSB-03 | | | | | | | | |
| |MSB-04 | | | | | | | | |
| |MSB-05 | | | | | | | | |
| |MSB-06 | | | | | | | | |
| |MSB-07 | | | | | | | | |
| |MSB-08 | | | | | | | | |
| |MSB-09 | | | | | | | | |
| |MSB-10 | | | | | | | | |
| |MSB-11 | | | | | | | | |
| |MSB-12 | | | | | | | | |
| ----- | |
| ## 7. Detection Signal Recommendations | |
| Based on these tests, the PCSIRT detection signal should ideally cover the following indicators, ranked by confidence: | |
| **High Confidence (alert):** | |
| - MSBuild spawning suspicious child processes (cmd, PowerShell, whoami, net, certutil, etc.) | |
| - MSBuild parent is `wscript.exe`, `cscript.exe`, `mshta.exe`, `winword.exe`, or `excel.exe` | |
| - MSBuild executing files from Temp, Downloads, AppData, ProgramData, or Public directories | |
| - Command line contains `@` (response file) with project files in non-development paths | |
| **Medium Confidence (alert with enrichment):** | |
| - MSBuild executing `.xml` or `.proj` files | |
| - Command line includes `/noconsolelogger` | |
| - MSBuild invoked from plain `cmd.exe` or `powershell.exe` without VS environment context | |
| - `.csproj` containing `CodeTaskFactory` or `RoslynCodeTaskFactory` in file content | |
| **Low Confidence (enrich / correlate):** | |
| - `/verbosity:quiet` or `/v:q` outside CI/CD context | |
| - MSBuild invoked by a user account that has never previously run MSBuild | |
| - Project file created within the last 60 seconds before MSBuild execution (staging indicator) | |
| ----- | |
| ## 8. Cleanup Procedures | |
| After all tests are complete: | |
| ``` | |
| del C:\Temp\benign_calc.csproj | |
| del C:\Temp\benign_whoami.xml | |
| del C:\Temp\test.rsp | |
| del C:\Temp\payload.proj | |
| del C:\Temp\child_proc_test.csproj | |
| del C:\Temp\msbuild_test_output.txt | |
| del C:\Temp\msbuild_child_test.txt | |
| del C:\Users\<testuser>\Downloads\build.csproj | |
| del C:\Users\<testuser>\AppData\Local\Temp\build.csproj | |
| del C:\Users\Public\build.csproj | |
| del C:\ProgramData\build.csproj | |
| del C:\Temp\launch_msbuild.vbs | |
| schtasks /delete /tn "MSBuildTest" /f 2>nul | |
| ``` | |
| Confirm all test artifacts are removed and no scheduled tasks persist. | |
| ----- | |
| ## 9. Sign-Off | |
| |Role |Name|Date|Signature| | |
| |--------------|----|----|---------| | |
| |Red Team Lead | | | | | |
| |PCSIRT Lead | | | | | |
| |SOC Manager | | | | | |
| |Change Manager| | | | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment