Artifacts created
This commit is contained in:
@@ -261,6 +261,9 @@ VOID CopiarFichero(PAnalizador argumentos) {
|
||||
|
||||
addString(respuestaTarea, tareaUuid, FALSE);
|
||||
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||
|
||||
// Add File Write artifact for the destination file
|
||||
addArtifact(respuestaTarea, "File Write", nuevoFichero);
|
||||
|
||||
mandarPaquete(respuestaTarea);
|
||||
liberarPaquete(salida);
|
||||
@@ -318,6 +321,9 @@ VOID CrearRuta(PAnalizador argumentos){
|
||||
|
||||
addString(respuestaTarea, tareaUuid, FALSE);
|
||||
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||
|
||||
// Add File Write artifact for the created directory
|
||||
addArtifact(respuestaTarea, "File Write", directorio);
|
||||
|
||||
mandarPaquete(respuestaTarea);
|
||||
liberarPaquete(salida);
|
||||
@@ -425,6 +431,9 @@ VOID EliminarRuta(PAnalizador argumentos){
|
||||
|
||||
addString(respuestaTarea, tareaUuid, FALSE);
|
||||
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||
|
||||
// Add File Write artifact for the deleted file/directory
|
||||
addArtifact(respuestaTarea, "File Write", ruta);
|
||||
|
||||
mandarPaquete(respuestaTarea);
|
||||
liberarPaquete(salida);
|
||||
|
||||
@@ -29,7 +29,11 @@ BOOL ejecutarConsola(PAnalizador argumentos) {
|
||||
addString(salida, ruta, FALSE);
|
||||
}
|
||||
|
||||
// Add output to response
|
||||
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||
|
||||
// Add Process Create artifact using the helper function
|
||||
addArtifact(respuestaTarea, "Process Create", comando);
|
||||
|
||||
_pclose(fp);
|
||||
Analizador* respuestaAnalizador = mandarPaquete(respuestaTarea);
|
||||
|
||||
@@ -639,4 +639,25 @@ VOID paqueteCompletado(PCHAR taskUuid, PPaquete datosOpcionales) {
|
||||
// Cleanup
|
||||
liberarPaquete(respuesta);
|
||||
if (resp) liberarAnalizador(resp);
|
||||
}
|
||||
|
||||
// Helper function to add artifacts to response packages
|
||||
// Format: [0xFF marker][artifact_type_len:4][artifact_type][artifact_value_len:4][artifact_value]
|
||||
VOID addArtifact(PPaquete paquete, PCHAR artifact_type, PCHAR artifact_value) {
|
||||
if (!paquete || !artifact_type || !artifact_value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Artifact marker
|
||||
addByte(paquete, 0xFF);
|
||||
|
||||
// Artifact type length and value
|
||||
SIZE_T type_len = strlen(artifact_type);
|
||||
addInt32(paquete, (UINT32)type_len);
|
||||
addString(paquete, artifact_type, FALSE);
|
||||
|
||||
// Artifact value length and value
|
||||
SIZE_T value_len = strlen(artifact_value);
|
||||
addInt32(paquete, (UINT32)value_len);
|
||||
addString(paquete, artifact_value, FALSE);
|
||||
}
|
||||
@@ -31,4 +31,8 @@ BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia);
|
||||
/* Formatted append helper */
|
||||
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...);
|
||||
|
||||
/* Artifact helper: adds artifact marker and data to response package */
|
||||
/* Format: [0xFF marker][artifact_type_len:4][artifact_type][artifact_value_len:4][artifact_value] */
|
||||
VOID addArtifact(PPaquete paquete, PCHAR artifact_type, PCHAR artifact_value);
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
from mythic_container.MythicCommandBase import *
|
||||
from mythic_container.MythicRPC import *
|
||||
import json
|
||||
|
||||
|
||||
class ShellArguments(TaskArguments):
|
||||
@@ -40,5 +41,27 @@ class ShellCommand(CommandBase):
|
||||
return task
|
||||
|
||||
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
||||
"""
|
||||
Process response from agent and add artifacts for Process Create.
|
||||
|
||||
According to Mythic documentation:
|
||||
https://docs.mythic-c2.net/customizing/hooking-features/artifacts
|
||||
|
||||
Artifacts should be added to the response JSON with an 'artifacts' array.
|
||||
However, the current Mythic API doesn't allow commands to directly modify
|
||||
the translator's JSON response. Instead, we could:
|
||||
|
||||
1. Use MythicRPC to create artifacts after the response (current limitation)
|
||||
2. Modify the agent to send command context in responses
|
||||
3. Have the translator detect shell commands automatically
|
||||
|
||||
For now, artifacts are prepared in the translator but need command context.
|
||||
"""
|
||||
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
||||
|
||||
# TODO: Add artifacts via MythicRPC or modify translator to detect shell commands
|
||||
# command = task.args.get_arg("command")
|
||||
# if command:
|
||||
# # Could use MythicRPC CreateArtifact here if available
|
||||
|
||||
return resp
|
||||
@@ -1,6 +1,7 @@
|
||||
from translator.utils import *
|
||||
import ipaddress
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
def checkIn(data):
|
||||
@@ -86,6 +87,27 @@ def getTasking(data):
|
||||
return dataJson
|
||||
|
||||
|
||||
def create_artifact(base_artifact, artifact_value, needs_cleanup=False, resolved=False):
|
||||
"""
|
||||
Helper function to create an artifact entry according to Mythic documentation.
|
||||
|
||||
Args:
|
||||
base_artifact: Type of artifact (e.g., "Process Create", "File Write")
|
||||
artifact_value: The actual artifact (e.g., "cmd.exe /c whoami", "/path/to/file")
|
||||
needs_cleanup: Whether this artifact needs cleanup later
|
||||
resolved: Whether this artifact has been cleaned up
|
||||
|
||||
Returns:
|
||||
Dictionary representing an artifact entry
|
||||
"""
|
||||
return {
|
||||
"base_artifact": base_artifact,
|
||||
"artifact": artifact_value,
|
||||
"needs_cleanup": needs_cleanup,
|
||||
"resolved": resolved
|
||||
}
|
||||
|
||||
|
||||
def parse_process_list(output_text):
|
||||
"""
|
||||
Parsea el texto tab-separated de procesos al formato JSON del Process Browser.
|
||||
@@ -155,6 +177,57 @@ def postResponse(data):
|
||||
output, data = getBytesWithSize(data)
|
||||
|
||||
print(f"Tamaño después de extraer UUID: {len(data)} bytes")
|
||||
|
||||
# Parse artifacts: format [0xFF][type_len:4][type][value_len:4][value]
|
||||
artifacts_data = []
|
||||
remaining_data = data
|
||||
|
||||
while len(remaining_data) >= 5: # At least: marker (1) + type_len (4)
|
||||
if remaining_data[0] == 0xFF:
|
||||
# Artifact marker found
|
||||
offset = 1
|
||||
|
||||
# Extract artifact type
|
||||
if len(remaining_data) < offset + 4:
|
||||
break
|
||||
type_len = int.from_bytes(remaining_data[offset:offset+4], 'big')
|
||||
offset += 4
|
||||
|
||||
if type_len == 0 or len(remaining_data) < offset + type_len:
|
||||
break
|
||||
|
||||
try:
|
||||
artifact_type = remaining_data[offset:offset+type_len].decode('cp850')
|
||||
offset += type_len
|
||||
except:
|
||||
break
|
||||
|
||||
# Extract artifact value
|
||||
if len(remaining_data) < offset + 4:
|
||||
break
|
||||
value_len = int.from_bytes(remaining_data[offset:offset+4], 'big')
|
||||
offset += 4
|
||||
|
||||
if value_len == 0 or len(remaining_data) < offset + value_len:
|
||||
break
|
||||
|
||||
try:
|
||||
artifact_value = remaining_data[offset:offset+value_len].decode('cp850')
|
||||
offset += value_len
|
||||
|
||||
artifacts_data.append({
|
||||
"type": artifact_type,
|
||||
"value": artifact_value
|
||||
})
|
||||
print(f"[ARTIFACTS] Detectado artifact: {artifact_type} = {artifact_value[:50]}")
|
||||
|
||||
# Continue parsing for multiple artifacts
|
||||
remaining_data = remaining_data[offset:]
|
||||
except:
|
||||
break
|
||||
else:
|
||||
# No more artifacts
|
||||
break
|
||||
|
||||
try:
|
||||
decoded_output = output.decode('cp850')
|
||||
@@ -207,6 +280,23 @@ def postResponse(data):
|
||||
if is_process_list and len(processes) > 0:
|
||||
jsonTask["processes"] = processes
|
||||
print(f"[PROCESS_BROWSER] Respuesta convertida al formato Process Browser con {len(processes)} procesos")
|
||||
|
||||
# Support for artifacts: create artifacts from parsed data
|
||||
artifacts = []
|
||||
|
||||
# Process all detected artifacts
|
||||
for artifact_info in artifacts_data:
|
||||
artifacts.append(create_artifact(
|
||||
artifact_info["type"],
|
||||
artifact_info["value"],
|
||||
needs_cleanup=False, # Can be made configurable per artifact type
|
||||
resolved=False
|
||||
))
|
||||
|
||||
# Add artifacts array if we have any
|
||||
if len(artifacts) > 0:
|
||||
jsonTask["artifacts"] = artifacts
|
||||
print(f"[ARTIFACTS] Total de artifacts agregados: {len(artifacts)}")
|
||||
|
||||
resTaks.append(jsonTask)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user