code clean
This commit is contained in:
@@ -153,35 +153,8 @@ BOOL parseChecking(PAnalizador respuestaAnalizador) {
|
|||||||
|
|
||||||
DBG_PRINTF("[Tareas] Tenemos nuevo UUID ! --> %s\n", nuevoUuid);
|
DBG_PRINTF("[Tareas] Tenemos nuevo UUID ! --> %s\n", nuevoUuid);
|
||||||
|
|
||||||
// === Leer clave pública del servidor y derivar AES si cifrado está habilitado ===
|
// === Nota: Cifrado AESPSK ya inicializado en cazallaMain() ===
|
||||||
if (cazallaConfig->encryptionEnabled) {
|
// La clave AES se inyecta en tiempo de compilación, no se deriva en runtime
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
liberarAnalizador(respuestaAnalizador);
|
liberarAnalizador(respuestaAnalizador);
|
||||||
|
|||||||
@@ -57,13 +57,9 @@
|
|||||||
#define SHA256_HASH_SIZE 32
|
#define SHA256_HASH_SIZE 32
|
||||||
|
|
||||||
// Globals (simple single-agent context)
|
// 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 unsigned char g_aesKey[AES_KEY_SIZE];
|
||||||
static int g_aesKeySet = 0;
|
static int g_aesKeySet = 0;
|
||||||
static int g_encryptionEnabled = 0; // Track if encryption is enabled
|
static int g_encryptionEnabled = 0; // Track if encryption is enabled
|
||||||
static unsigned char g_pubRaw[512];
|
|
||||||
static DWORD g_pubRawLen = 0;
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
static void secure_zero(void *p, SIZE_T n) {
|
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) {
|
void crypto_cleanup(void) {
|
||||||
secure_zero(g_aesKey, sizeof(g_aesKey));
|
secure_zero(g_aesKey, sizeof(g_aesKey));
|
||||||
g_aesKeySet = 0;
|
g_aesKeySet = 0;
|
||||||
if (g_currentKey) {
|
g_encryptionEnabled = 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize AESPSK key from base64 string (Mythic format)
|
// Initialize AESPSK key from base64 string (Mythic format)
|
||||||
|
|||||||
@@ -85,14 +85,6 @@ SIZE_T b64tamanoDecodificado(const char* in) {
|
|||||||
return ret;
|
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) {
|
static int b64_inverse(char c) {
|
||||||
if (c >= 'A' && c <= 'Z') return c - 'A';
|
if (c >= 'A' && c <= 'Z') return c - 'A';
|
||||||
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
||||||
|
|||||||
@@ -102,21 +102,13 @@ def responseTasking(tasks):
|
|||||||
def responseCheckin(uuid, server_pubkey=""):
|
def responseCheckin(uuid, server_pubkey=""):
|
||||||
"""
|
"""
|
||||||
Construye la respuesta de checkin.
|
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 = bytearray()
|
||||||
data.append(commands["checkin"]["hex_code"]) # 0xF1
|
data.append(commands["checkin"]["hex_code"]) # 0xF1
|
||||||
data += uuid.encode() # UUID del agente
|
data += uuid.encode() # UUID del agente
|
||||||
|
# Longitud 0 para clave pública (ya no se usa ECDH)
|
||||||
# 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:
|
|
||||||
data += (0).to_bytes(4, "big")
|
data += (0).to_bytes(4, "big")
|
||||||
print("[DEBUG] Sin server_pubkey en checkin")
|
|
||||||
|
|
||||||
return bytes(data)
|
return bytes(data)
|
||||||
|
|
||||||
|
|||||||
@@ -52,14 +52,16 @@ def checkIn(data):
|
|||||||
# Retrieve External IP
|
# Retrieve External IP
|
||||||
externalIP, data = getBytesWithSize(data)
|
externalIP, data = getBytesWithSize(data)
|
||||||
|
|
||||||
# === Retrieve ECC Public Key if present ===
|
# Nota: ECC Public Key ya no se usa (cifrado AESPSK se inyecta en build time)
|
||||||
pub_key = None
|
# Leemos y descartamos la longitud (4 bytes) que siempre será 0
|
||||||
try:
|
try:
|
||||||
pub_key, data = getBytesWithSize(data)
|
key_len = int.from_bytes(data[:4], "big")
|
||||||
pub_key = pub_key.decode() if pub_key else None
|
data = data[4:]
|
||||||
print(f"[DEBUG] Clave pública ECC recibida: {pub_key[:60]}...") # truncada
|
if key_len > 0:
|
||||||
except Exception as e:
|
# Descarta los datos de la clave si existen (código legacy)
|
||||||
print(f"[DEBUG] No se recibió clave pública ECC: {e}")
|
data = data[key_len:]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
dataJson = {
|
dataJson = {
|
||||||
"action": "checkin",
|
"action": "checkin",
|
||||||
@@ -75,9 +77,6 @@ def checkIn(data):
|
|||||||
"externalIP": externalIP.decode('cp850'),
|
"externalIP": externalIP.decode('cp850'),
|
||||||
}
|
}
|
||||||
|
|
||||||
if pub_key:
|
|
||||||
dataJson["pub_key"] = pub_key
|
|
||||||
|
|
||||||
return dataJson
|
return dataJson
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -131,8 +131,7 @@ class cazalla_translator(TranslationContainer):
|
|||||||
|
|
||||||
if inputMsg.Message["action"] == "checkin":
|
if inputMsg.Message["action"] == "checkin":
|
||||||
print("Response CHECKIN")
|
print("Response CHECKIN")
|
||||||
server_pubkey = inputMsg.Message.get("server_key", "")
|
response.Message = responseCheckin(inputMsg.Message["id"])
|
||||||
response.Message = responseCheckin(inputMsg.Message["id"], server_pubkey)
|
|
||||||
|
|
||||||
elif inputMsg.Message["action"] == "get_tasking":
|
elif inputMsg.Message["action"] == "get_tasking":
|
||||||
print("Response TASKING")
|
print("Response TASKING")
|
||||||
|
|||||||
Reference in New Issue
Block a user