Recently a customer wanted me to evaluate the cost and fix all XSS holes in their website. Their security specialist found some holes using an obscure software only security specialists have and gave me his report and a list of webpage where it occurs.
After some digging I found there was one main hole - the same and on every page of their website. The hole was coming from the code of an UI component, a four years old version of the Telerik UI library for ASP.NET where XSS was not in the light.
My first report was to replace this component everywhere. As it would cost too much to the company, I was aimed to propose another solution : decompile the faulty assembly, find and fix the bug, and recompile it. It seemed easy. Helas ! This commercial library is obfuscated by Xenocode (a commercial obfuscator) which removes a lot of code unused by the CLR but necessary to the recompilation. So it was not an option.
THE SOLUTION
Then I came with an idea from my childhood where I was playing with raw asm and modified a tetris software because the blocs were not rotating in the correct direction …
Why not replace the faulting method pointer with the pointer of a fixed method dynamically in memory ? A lot of things run against this idea.One of them is that the code memory area is protected since Windows XP. And code injection does not work on 64 bit platforms at all.
Then I googled and found the graal… A post by Ziad Elmalki called “CLR Injection: Runtime Method Replacer”.
With a few lines of code I make it work with the web project.
I created a class “Demo.Fix” with a method InjectFix to be called in global.axax’s Application_Start event.
The first thing this method does is to check wether the assembly containing the code to fix is already loaded. If it is not it handles the AppDomain’s AssemblyLoad event.
using System;
using System.Reflection;
using System.Web;
using System.Linq;
using NativeAssemblerInjection;
namespace Demo
{
public class Fix
{
/// <summary>
/// Dynamically replace the failing method with our
/// </summary>
/// <remarks>
/// First search if the assembly containing the class and method to replace is already
/// loaded. If it is not already loaded, handle the AssemblyLoad event on the
/// application domain.
/// </remarks>
public static void InjectFix()
{
var assembly = (from a in AppDomain.CurrentDomain.GetAssemblies()
where a.FullName.Contains("FaultingAssemblyName")
select a).FirstOrDefault();
if (assembly != null)
DoReplace(assembly);
else
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
}
/// <summary>
/// Wait for the assembly containing the class and method to replace to be loaded.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
static void CurrentDomain_AssemblyLoad(object sender, System.AssemblyLoadEventArgs args)
{
if (args.LoadedAssembly.FullName.Contains("FaultingAssemblyName"))
{
DoReplace(args.LoadedAssembly);
AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomain_AssemblyLoad;
}
}
/// <summary>
/// Dynamically replace the failing method in <paramref name="assembly"/> by our
/// own method.
/// </summary>
/// <param name="assembly">assembly containing the failing method</param>
private static void DoReplace(Assembly assembly)
{
MethodBase oldMethod = assembly.GetType("FullNamespace.WebControls.x7fbe3d3b15648174")
.GetMethod("xe07c485b9dc80480", BindingFlags.NonPublic | BindingFlags.Instance);
MethodBase newMethod = typeof(Fix).GetMethod("ReplacementMethod",
BindingFlags.NonPublic | BindingFlags.Instance);
MethodUtil.ReplaceMethod(newMethod, oldMethod);
}
/// <summary>
/// Replacement method which corrects the behaviour of the original method
/// </summary>
/// <remarks>
/// The signature must be the exact same as the original method. When called, the context
/// (this) is the one from the original object, not the one from this class.
/// </remarks>
private string ReplacementMethod()
{
...
}
}
}
And it works both in 32 and 64 bits … amazing.
References
CLR Injection: Runtime Method Replacer