Skip to content

Commit 12055fc

Browse files
committed
Finalised support for RSA-encrypted AES key negotiation
Still needs to be wired into HTTP/S.
1 parent 8ffb877 commit 12055fc

File tree

3 files changed

+124
-24
lines changed

3 files changed

+124
-24
lines changed

c/meterpreter/source/common/common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#define _METERPRETER_SOURCE_COMMON_COMMON_H
77

88
/*! @brief Set to 0 for "normal", and 1 to "verbose", comment out to disable completely. */
9-
#define DEBUGTRACE 1
9+
//#define DEBUGTRACE 0
1010

1111
#include <stdlib.h>
1212
#include <stdio.h>

c/meterpreter/source/common/core.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,9 @@ typedef enum
170170
TLV_TYPE_CIPHER_PARAMETERS = TLV_VALUE(TLV_META_TYPE_GROUP, 501), ///! Represents parameters for a cipher.
171171

172172
// Packet encryption
173-
TLV_TYPE_AES_KEY = TLV_VALUE(TLV_META_TYPE_RAW, 550), ///! Represents the AES key
173+
TLV_TYPE_AES_KEY = TLV_VALUE(TLV_META_TYPE_RAW, 550), ///! Represents an AES key
174+
TLV_TYPE_ENC_AES_KEY = TLV_VALUE(TLV_META_TYPE_RAW, 551), ///! Represents an encrypted AES key
175+
TLV_TYPE_RSA_PUB_KEY = TLV_VALUE(TLV_META_TYPE_STRING, 552), ///! Represents PEM-formatted RSA public key
174176

175177
TLV_TYPE_EXTENSIONS = TLV_VALUE(TLV_META_TYPE_COMPLEX, 20000), ///! Represents an extension value.
176178
TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000), ///! Represents a user value.

c/meterpreter/source/common/packet_encryption.c

Lines changed: 120 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ typedef struct _CryptProviderParams
1111
const DWORD flags;
1212
} CryptProviderParams;
1313

14+
typedef struct _RsaKey
15+
{
16+
BLOBHEADER header;
17+
DWORD length;
18+
BYTE key[1];
19+
} RsaKey;
20+
21+
1422
const CryptProviderParams AesProviders[] =
1523
{
1624
{MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0},
@@ -310,25 +318,25 @@ DWORD free_encryption_context(Remote* remote)
310318
DWORD result = ERROR_SUCCESS;
311319

312320
dprintf("[ENC] Freeing encryption context %p", remote->enc_ctx);
313-
if (remote->enc_ctx != NULL);
321+
if (remote->enc_ctx != NULL);
322+
{
323+
dprintf("[ENC] Encryption context not null, so ditching AES key");
324+
if (remote->enc_ctx->aes_key != 0)
314325
{
315-
dprintf("[ENC] Encryption context not null, so ditching AES key");
316-
if (remote->enc_ctx->aes_key != 0)
317-
{
318-
CryptDestroyKey(remote->enc_ctx->aes_key);
319-
}
320-
321-
dprintf("[ENC] Encryption context not null, so ditching provider");
322-
if (remote->enc_ctx->provider != 0)
323-
{
324-
CryptReleaseContext(remote->enc_ctx->provider, 0);
325-
}
326+
CryptDestroyKey(remote->enc_ctx->aes_key);
327+
}
326328

327-
dprintf("[ENC] Encryption context not null, so freeing the context");
328-
free(remote->enc_ctx);
329-
remote->enc_ctx = NULL;
329+
dprintf("[ENC] Encryption context not null, so ditching provider");
330+
if (remote->enc_ctx->provider != 0)
331+
{
332+
CryptReleaseContext(remote->enc_ctx->provider, 0);
330333
}
331-
return result;
334+
335+
dprintf("[ENC] Encryption context not null, so freeing the context");
336+
free(remote->enc_ctx);
337+
remote->enc_ctx = NULL;
338+
}
339+
return result;
332340
}
333341

334342
DWORD request_negotiate_aes_key(Remote* remote, Packet* packet)
@@ -396,14 +404,104 @@ DWORD request_negotiate_aes_key(Remote* remote, Packet* packet)
396404
break;
397405
}
398406

399-
ctx->valid = TRUE;
400-
} while (0);
407+
// now we need to encrypt this key data using the public key given
408+
CHAR* pubKeyPem = packet_get_tlv_value_string(packet, TLV_TYPE_RSA_PUB_KEY);
401409

410+
if (pubKeyPem != NULL)
411+
{
412+
DWORD binaryRequiredSize = 0;
413+
CryptStringToBinaryA(pubKeyPem, 0, CRYPT_STRING_BASE64HEADER, NULL, &binaryRequiredSize, NULL, NULL);
414+
dprintf("[ENC] Required size for the binary key is: %u (%x)", binaryRequiredSize, binaryRequiredSize);
415+
BYTE* pubKeyBin = (BYTE*)malloc(binaryRequiredSize);
416+
if (!CryptStringToBinaryA(pubKeyPem, 0, CRYPT_STRING_BASE64HEADER, pubKeyBin, &binaryRequiredSize, NULL, NULL))
417+
{
418+
result = GetLastError();
419+
dprintf("[ENC] Failed to convert the given base64 encoded key into bytes: %u (%x)", result, result);
420+
break;
421+
}
402422

403-
if (remote->enc_ctx->valid)
404-
{
405-
packet_add_tlv_raw(response, TLV_TYPE_AES_KEY, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length);
406-
}
423+
DWORD keyRequiredSize = 0;
424+
CERT_PUBLIC_KEY_INFO* pubKeyInfo = NULL;
425+
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pubKeyBin, binaryRequiredSize, CRYPT_ENCODE_ALLOC_FLAG, 0, &pubKeyInfo, &keyRequiredSize))
426+
{
427+
result = GetLastError();
428+
dprintf("[ENC] Failed to decode: %u (%x)", result, result);
429+
break;
430+
}
431+
432+
dprintf("[ENC] Key algo: %s", pubKeyInfo->Algorithm.pszObjId);
433+
434+
HCRYPTPROV rsaProv = 0;
435+
if (!CryptAcquireContext(&rsaProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
436+
{
437+
dprintf("[ENC] Failed to create the RSA provider with CRYPT_VERIFYCONTEXT");
438+
if (!CryptAcquireContext(&rsaProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
439+
{
440+
result = GetLastError();
441+
dprintf("[ENC] Failed to create the RSA provider with CRYPT_NEWKEYSET: %u (%x)", result, result);
442+
break;
443+
}
444+
else
445+
{
446+
dprintf("[ENC] Created the RSA provider with CRYPT_NEWKEYSET");
447+
}
448+
}
449+
else
450+
{
451+
dprintf("[ENC] Created the RSA provider with CRYPT_VERIFYCONTEXT");
452+
}
453+
454+
HCRYPTKEY pubCryptKey = 0;
455+
if (!CryptImportPublicKeyInfo(rsaProv, X509_ASN_ENCODING, pubKeyInfo, &pubCryptKey))
456+
{
457+
result = GetLastError();
458+
dprintf("[ENC] Failed to import the key: %u (%x)", result, result);
459+
break;
460+
}
461+
462+
DWORD requiredEncSize = remote->enc_ctx->key_data.length;
463+
CryptEncrypt(pubCryptKey, 0, TRUE, 0, NULL, &requiredEncSize, requiredEncSize);
464+
dprintf("[ENC] Encrypted data length: %u (%x)", requiredEncSize, requiredEncSize);
465+
466+
LPBYTE cipherText = (LPBYTE)calloc(1, requiredEncSize);
467+
DWORD aesKeySize = remote->enc_ctx->key_data.length;
468+
memcpy_s(cipherText, requiredEncSize, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length);
469+
470+
if (!CryptEncrypt(pubCryptKey, 0, TRUE, 0, cipherText, &aesKeySize, requiredEncSize))
471+
{
472+
result = GetLastError();
473+
dprintf("[ENC] Failed to encrypt: %u (%x)", result, result);
474+
475+
// encryption failed, so pass on the raw AES key instead
476+
packet_add_tlv_raw(response, TLV_TYPE_AES_KEY, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length);
477+
}
478+
else
479+
{
480+
dprintf("[ENC] Encryption witih RSA succeded, byteswapping because MS is stupid and does stuff in little endian.");
481+
// Given that we are encrypting such a small amount of data, we're going to assume that the size
482+
// of the key matches the size of the block of data we've decrypted.
483+
for (DWORD i = 0; i < requiredEncSize / 2; ++i)
484+
{
485+
BYTE b = cipherText[i];
486+
cipherText[i] = cipherText[requiredEncSize - i - 1];
487+
cipherText[requiredEncSize - i - 1] = b;
488+
}
489+
// encryption succeeded, pass this key back to the call in encrypted form
490+
packet_add_tlv_raw(response, TLV_TYPE_ENC_AES_KEY, cipherText, requiredEncSize);
491+
}
492+
free(cipherText);
493+
LocalFree(pubKeyInfo);
494+
CryptDestroyKey(pubCryptKey);
495+
CryptReleaseContext(rsaProv, 0);
496+
}
497+
else
498+
{
499+
// no public key was given, so send it back in the raw
500+
packet_add_tlv_raw(response, TLV_TYPE_AES_KEY, remote->enc_ctx->key_data.key, remote->enc_ctx->key_data.length);
501+
}
502+
503+
ctx->valid = TRUE;
504+
} while (0);
407505

408506
packet_transmit_response(result, remote, response);
409507

0 commit comments

Comments
 (0)