diff --git a/c/meterpreter/source/common/common_core.h b/c/meterpreter/source/common/common_core.h index b378e056d..85c5c4a5d 100644 --- a/c/meterpreter/source/common/common_core.h +++ b/c/meterpreter/source/common/common_core.h @@ -85,6 +85,13 @@ typedef enum */ #define LOAD_LIBRARY_FLAG_LOCAL (1 << 2) + /*! + * @brief Indicates that the library in question supports runtime encryption. + * @detail Libraries can be encrypted runtime, depending on how they interact with the system + * if this flag is present, it means this library support the runtime encryption. + */ +#define LOAD_LIBRARY_EXTENSION_ENCRYPTABLE (1 << 3) + /*! @brief An indication of whether the challen is synchronous or asynchronous. */ #define CHANNEL_FLAG_SYNCHRONOUS (1 << 0) /*! @brief An indication of whether the content written to the channel should be compressed. */ diff --git a/c/meterpreter/source/metsrv/extension_encryption.c b/c/meterpreter/source/metsrv/extension_encryption.c new file mode 100644 index 000000000..15065a7a8 --- /dev/null +++ b/c/meterpreter/source/metsrv/extension_encryption.c @@ -0,0 +1,148 @@ +#include "extension_encryption.h" + +extension_encryption_ctx* extension_statuses[MAX_EXTENSIONS] = { 0 }; + +BOOL extension_encryption_add(extension_encryption_ctx* ExtensionCtx) { + BOOL ret = FALSE; + + if (ExtensionCtx == NULL || !ExtensionCtx->encryptable) { + dprintf("[extension_encryption][extension_encryption_add] Either ExtensionCtx is NULL or Extension is not encryptable."); + return ret; + } + + for (int i = 0; i < MAX_EXTENSIONS; i++) { + if (extension_statuses[i] == NULL) { + extension_statuses[i] = ExtensionCtx; + ret = TRUE; + break; + } + } + if (!ret) { + dprintf("[extension_encryption][extension_encryption_add] Couldn't locate an empty member in extension_statuses array."); + } + return ret; +} + +BOOL extension_encryption_remove(extension_encryption_ctx* ExtensionCtx) { + BOOL ret = FALSE; + + if (ExtensionCtx == NULL) { + dprintf("[extension_encryption][extension_encryption_remove] ExtensionCtx is NULL."); + return ret; + } + + for (int i = 0; i < MAX_EXTENSIONS; i++) { + if (extension_statuses[i] == ExtensionCtx) { + extension_statuses[i] = NULL; + ret = TRUE; + break; + } + } + if (!ret) { + dprintf("[extension_encryption][extension_encryption_remove] Couldn't locate ExtensionCtx in extension_statuses array."); + } + return ret; +} + +BOOL extension_encryption_encrypt(extension_encryption_ctx* ExtensionCtx) { + RC4_CTX RC4 = { 0 }; + size_t KeyLength = 0; + BOOL ret = FALSE; + unsigned char buff[4096] = { 0 }; + DWORD diff = 4096; + size_t ByteCounter = 0; + + if (ExtensionCtx == NULL || !ExtensionCtx->encryptable || ExtensionCtx->encrypted || !ExtensionCtx->size || ExtensionCtx->key == NULL || ExtensionCtx->loc == NULL) { + dprintf("[extension_encryption][extension_encryption_encrypt] Invalid ExtensionCtx."); + return ret; + } + + KeyLength = strlen(ExtensionCtx->key); + + if (!KeyLength || !InitRc4(&RC4, ExtensionCtx->key, KeyLength)) { + dprintf("[extension_encryption][extension_encryption_encrypt] Either KeyLength is 0 or InitRc4 failed."); + return ret; + } + + for (DWORD i = 0; i != ExtensionCtx->size; i += diff) { + if ((ExtensionCtx->size - i) < 4096) { + diff = ExtensionCtx->size - i; + } + ret = ReadProcessMemory(GetCurrentProcess(), (unsigned char*)ExtensionCtx->loc + i, buff, diff, &ByteCounter); + if (!ret || ByteCounter != diff) { + dprintf("[extension_encryption][extension_encryption_encrypt] ReadProcessMemory failed with error 0x%x", GetLasatError()); + break; + } + if (!RC4Cipher(&RC4, buff, diff)) { + dprintf("[extension_encryption][extension_encryption_encrypt] RC4Cipher failed."); + ret = FALSE; + break; + } + ret = WriteProcessMemory(GetCurrentProcess(), (unsigned char*)ExtensionCtx->loc, buff, diff, &ByteCounter); + if (!ret || ByteCounter != diff) { + dprintf("[extension_encryption][extension_encryption_encrypt] WriteProcessMemory failed with error 0x%x", GetLastError()); + break; + } + } + if (ret) { + ExtensionCtx->encrypted = !ExtensionCtx->encrypted; + } + return ret; +} + +BOOL extension_encryption_decrypt(extension_encryption_ctx* ExtensionCtx) { + RC4_CTX RC4 = { 0 }; + size_t KeyLength = 0; + BOOL ret = FALSE; + unsigned char buff[4096] = { 0 }; + DWORD diff = 4096; + size_t ByteCounter = 0; + + if (ExtensionCtx == NULL || !ExtensionCtx->encryptable || !ExtensionCtx->encrypted || !ExtensionCtx->size || ExtensionCtx->key == NULL || ExtensionCtx->loc == NULL) { + dprintf("[extension_encryption][extension_encryption_decrypt] Invalid ExtensionCtx."); + return ret; + } + + KeyLength = strlen(ExtensionCtx->key); + + if (!KeyLength || !InitRc4(&RC4, ExtensionCtx->key, KeyLength)) { + dprintf("[extension_encryption][extension_encryption_decrypt] Either KeyLength is 0 or InitRc4 failed."); + return ret; + } + + for (DWORD i = 0; i != ExtensionCtx->size; i += diff) { + if ((ExtensionCtx->size - i) < 4096) { + diff = ExtensionCtx->size - i; + } + ret = ReadProcessMemory(GetCurrentProcess(), (unsigned char*)ExtensionCtx->loc + i, buff, diff, &ByteCounter); + if (!ret || ByteCounter != diff) { + dprintf("[extension_encryption][extension_encryption_decrypt] ReadProcessMemory failed with error 0x%x", GetLasatError()); + break; + } + if (!RC4Cipher(&RC4, buff, diff)) { + dprintf("[extension_encryption][extension_encryption_decrypt] RC4Cipher failed."); + ret = FALSE; + break; + } + ret = WriteProcessMemory(GetCurrentProcess(), (unsigned char*)ExtensionCtx->loc, buff, diff, &ByteCounter); + if (!ret || ByteCounter != diff) { + dprintf("[extension_encryption][extension_encryption_decrypt] WriteProcessMemory failed with error 0x%x", GetLastError()); + break; + } + } + if (ret) { + ExtensionCtx->encrypted = !ExtensionCtx->encrypted; + } + return ret; +} + +void extension_encryption_encrypt_unused() { + for (int i = 0; i < MAX_EXTENSIONS; i++) { + if (extension_statuses[i] == NULL || !extension_statuses[i]->encryptable || extension_statuses[i]->encrypted || (GetTickCount() - extension_statuses[i]->LastUsedTime) < 600000) { + continue; + } + if (!extension_encryption_encrypt(extension_statuses[i])) { + dprintf("[extension_encryption][extension_encryption_encrypt_unused] extension_statuses[%d] couldn't be encrypted.", i); + } + } +} \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/extension_encryption.h b/c/meterpreter/source/metsrv/extension_encryption.h new file mode 100644 index 000000000..14870a8ce --- /dev/null +++ b/c/meterpreter/source/metsrv/extension_encryption.h @@ -0,0 +1,19 @@ +#include "rc4.h" +#include "common.h" + +#define MAX_EXTENSIONS 32 // ?? + +typedef struct { + BOOL encryptable; + BOOL encrypted; + LPCSTR key; + LPVOID loc; + DWORD size; + DWORD LastUsedTime; +} extension_encryption_ctx; + +BOOL extension_encryption_add(extension_encryption_ctx* ExtensionCtx); +BOOL extension_encryption_remove(extension_encryption_ctx* ExtensionCtx); +BOOL extension_encryption_encrypt(extension_encryption_ctx* ExtensionCtx); +BOOL extension_encryption_decrypt(extension_encryption_ctx* ExtensionCtx); +void extension_encryption_encrypt_unused(); \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/rc4.c b/c/meterpreter/source/metsrv/rc4.c new file mode 100644 index 000000000..c6b19294f --- /dev/null +++ b/c/meterpreter/source/metsrv/rc4.c @@ -0,0 +1,48 @@ +#include "rc4.h" + +BOOL InitRc4(RC4_CTX* Context, unsigned char* Key, size_t len) { + unsigned char T = 0; + unsigned int j = 0; + + if (Context == NULL || Key == NULL || len == 0) { + return FALSE; + } + + memset(Context, 0x00, sizeof(RC4_CTX)); + + for (unsigned int i = 0; i < 256; i++) { + Context->s[i] = i; + } + + for (unsigned int i = 0; i < 256; i++) { + j = (j + Context->s[i] + Key[i % len]) % 256; + T = Context->s[i]; + Context->s[i] = Context->s[j]; + Context->s[j] = T; + } + + Context->i = 0; + Context->j = 0; + + return TRUE; +} + +BOOL RC4Cipher(RC4_CTX* Context, unsigned char* buf, size_t len) { + unsigned char T = 0; + unsigned int i = Context->i; + unsigned int j = Context->j; + + for (unsigned int k = 0; k < len;k++) { + i = (i+1) % 256; + j = (j + Context->s[i]) % 256; + T = Context->s[i]; + Context->s[i] = Context->s[j]; + Context->s[j] = T; + buf[k] ^= Context->s[(Context->s[i] + Context->s[j]) % 256]; + } + + Context->i = i; + Context->j = j; + + return TRUE; +} \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/rc4.h b/c/meterpreter/source/metsrv/rc4.h new file mode 100644 index 000000000..f13913b2d --- /dev/null +++ b/c/meterpreter/source/metsrv/rc4.h @@ -0,0 +1,10 @@ +#include + +typedef struct { + unsigned int i, j; + unsigned char s[256]; +} RC4_CTX; + +BOOL InitRc4(RC4_CTX* Context, unsigned char* Key, size_t len); +BOOL RC4Cipher(RC4_CTX* Context, unsigned char* buf, size_t len); + diff --git a/c/meterpreter/source/metsrv/remote_dispatch.c b/c/meterpreter/source/metsrv/remote_dispatch.c index 1969494aa..30d8b2f72 100644 --- a/c/meterpreter/source/metsrv/remote_dispatch.c +++ b/c/meterpreter/source/metsrv/remote_dispatch.c @@ -423,6 +423,9 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet) if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && library) { res = load_extension(library, bLibLoadedReflectivly, remote, response, first); + if (flags & LOAD_LIBRARY_EXTENSION_ENCRYPTABLE) { + dprintf("[DEBUG] This extension can be encrypted!"); + } } } while (0); diff --git a/c/meterpreter/workspace/metsrv/metsrv.vcxproj b/c/meterpreter/workspace/metsrv/metsrv.vcxproj index 106363b92..98c5a920c 100644 --- a/c/meterpreter/workspace/metsrv/metsrv.vcxproj +++ b/c/meterpreter/workspace/metsrv/metsrv.vcxproj @@ -570,6 +570,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" + + @@ -601,6 +603,8 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" + + @@ -618,4 +622,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - \ No newline at end of file + diff --git a/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters b/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters index 4f02ec4a1..e3a7876c4 100644 --- a/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters +++ b/c/meterpreter/workspace/metsrv/metsrv.vcxproj.filters @@ -27,6 +27,9 @@ + + + @@ -57,9 +60,12 @@ + + + - \ No newline at end of file +