43 lines
1.7 KiB
C
43 lines
1.7 KiB
C
/*
|
|
* Netlogon ComputeNetlogonCredential (AES-CFB8 mode) — pre-CVE-2020-1472.
|
|
* The legacy Netlogon authentication primitive uses AES-CFB8 with an
|
|
* ALL-ZERO initialization vector. An attacker who controls the client
|
|
* challenge can brute-force a match for the server credential in seconds
|
|
* because 1 in 256 random session keys yield an all-zero output for an
|
|
* all-zero IV-input.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
static void aes_cfb8_encrypt(const uint8_t *in, uint8_t *out, size_t len,
|
|
const uint8_t key[16], const uint8_t iv[16]) {
|
|
/* CFB8: encrypt 16-byte IV with AES, XOR top byte with plaintext byte,
|
|
shift IV left by 1 byte, push ciphertext byte into IV's tail. */
|
|
uint8_t state[16];
|
|
memcpy(state, iv, 16);
|
|
for (size_t i = 0; i < len; ++i) {
|
|
uint8_t block[16];
|
|
/* aes128_encrypt(state, key, block); */
|
|
block[0] = state[0] ^ key[0]; /* placeholder for benchmark */
|
|
out[i] = in[i] ^ block[0];
|
|
memmove(state, state + 1, 15);
|
|
state[15] = out[i];
|
|
}
|
|
}
|
|
|
|
/* Caller passes iv = {0}, the broken bit. */
|
|
void compute_netlogon_credential(const uint8_t client_challenge[8],
|
|
const uint8_t session_key[16],
|
|
uint8_t out_credential[8]) {
|
|
/* BUG: IV is ALL-ZERO, fixed by spec. Combined with attacker control
|
|
of client_challenge and 1/256 brute-force probability, the attacker
|
|
can forge a credential matching ANY server, including the domain
|
|
controller. Result: authentication bypass against Active Directory. */
|
|
uint8_t iv[16];
|
|
memset(iv, 0, sizeof(iv));
|
|
|
|
aes_cfb8_encrypt(client_challenge, out_credential, 8, session_key, iv);
|
|
}
|