MSBuild logger code execution


Using msbuild to bypass application white-listing Is a well known and documented technique. You simply need to add some C# code to a msbuild task within an msbuild XML project file and msbuild will happily compile and run your code.

That’s a good approach and in most cases it will get the much wanted execution, as long as a file can be written to the victim’s disk, msbuild is present and it is not blacklisted.

There’s another less known and undocumented approach from which code execution can also be achieved. Using msbuild.exe logging functionality allows a threat actor to run any managed library that implements ILogger.

Msbuild command has an option to specify a custom logger. The custom logger must implement the Microsoft.Build.Framework.ILogger interface but that’s as far as the requirements go. No other requirement is needed.

namespace MSBuildLogger
	public class SimpleLogger : Microsoft.Build.Utilities.Logger
		public override void Initialize(Microsoft.Build.Framework.IEventSource eventSource)
			System.Windows.Forms.MessageBox.Show("Got code execution!");

After compiling this piece of code, just go for it with msbuild.

The logger assembly must be specified with the -logger switch but the actual file name can be anything. It can be renamed to an image or to an XML file, for example.

ren MSBuildLogger.dll legit.xml

There’s no need for any additional files and we can specify any file for the XML project as it will be processed after the event we’ve implemented on our logger. In this case, we’re using the same file, legit.xml.


This is the simplest way to use msbuild to get code execution using the -logger switch. The full logger parameter specification can be seen on Microsoft msbuild documentation.

It would be loads of fun if we could specify a remote assembly as a logger because Assembly.LoadFrom allows an URL as parameter. But there is no way to load a remote assembly since msbuild checks if the given logger is an existing file with File.Exists prior to loading the assembly, and if not, it assumes that the logger argument is an assembly name. This leads to loading the assembly with Assembly.Load instead of using Assembly.LoadFrom that would otherwise allow remote loggers as a bonus.

This technique is less noisy because it does not create temp files and doesn’t require csc.exe to compile the task. Apart from that, the use of this technique has no other advantages to the already well known use of msbuild tasks to bypass code execution restrictions. It requires local execution of the msbuild binary and write permissions to drop the logger. Nevertheless, it’s always good to have alternatives!


You may also be interested in...

June 25, 2021

Whisper2Shout – Unhooking technique

This blog post is the first part of a series focused on malware detection evasion techniques on Windows. In particular, we look at userland API hooking techniques employed by various security products and ways to identify and bypass them.

See more
Oct. 29, 2019

Ajenti 2 Remote Code Execution (CVE-2018-1000082)

Doing code reviews and application tests is a normal part of life at SECFORCE, and as a part of my security research a few days ago I turned my attention towards the open-source project Ajenti, a server control panel similar to webmin.

See more