From 7f13e4b962a56800b5f07031127592ee06e43aec Mon Sep 17 00:00:00 2001 From: Francesco Soncina Date: Wed, 30 Oct 2019 14:40:37 +0100 Subject: [PATCH 1/7] Add global isBase64Output --- modules/kull_m_output.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/kull_m_output.h b/modules/kull_m_output.h index c6f46ba8..633596d2 100644 --- a/modules/kull_m_output.h +++ b/modules/kull_m_output.h @@ -7,7 +7,9 @@ #include "globals.h" #include #include +#include +BOOL isBase64Output; FILE * logfile; #if !defined(MIMIKATZ_W2000_SUPPORT) wchar_t * outputBuffer; @@ -20,4 +22,4 @@ void kprintf_inputline(PCWCHAR format, ...); BOOL kull_m_output_file(PCWCHAR file); void kull_m_output_init(); -void kull_m_output_clean(); \ No newline at end of file +void kull_m_output_clean(); From d3f370e3bd8009f4a46a20d741491062f9014fa6 Mon Sep 17 00:00:00 2001 From: Francesco Soncina Date: Wed, 30 Oct 2019 14:42:43 +0100 Subject: [PATCH 2/7] Include kull_m_output.h --- mimikatz/modules/kuhl_m_standard.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mimikatz/modules/kuhl_m_standard.h b/mimikatz/modules/kuhl_m_standard.h index f9c2094a..a4b580d4 100644 --- a/mimikatz/modules/kuhl_m_standard.h +++ b/mimikatz/modules/kuhl_m_standard.h @@ -10,6 +10,7 @@ #include "../../modules/kull_m_process.h" #include "../../modules/kull_m_net.h" #include "../../modules/kull_m_cabinet.h" +#include "../../modules/kull_m_output.h" const KUHL_M kuhl_m_standard; @@ -25,4 +26,4 @@ NTSTATUS kuhl_m_standard_version(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_standard_cd(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_standard_localtime(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_standard_hostname(int argc, wchar_t * argv[]); -NTSTATUS kuhl_m_standard_test(int argc, wchar_t * argv[]); \ No newline at end of file +NTSTATUS kuhl_m_standard_test(int argc, wchar_t * argv[]); From f234e18279fb58df79e4620bd7ee6e8bd7d0be0f Mon Sep 17 00:00:00 2001 From: Francesco Soncina Date: Wed, 30 Oct 2019 14:43:32 +0100 Subject: [PATCH 3/7] Parse /base64 option of log command --- mimikatz/modules/kuhl_m_standard.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mimikatz/modules/kuhl_m_standard.c b/mimikatz/modules/kuhl_m_standard.c index 7c4b7819..53ee55b7 100644 --- a/mimikatz/modules/kuhl_m_standard.c +++ b/mimikatz/modules/kuhl_m_standard.c @@ -72,6 +72,7 @@ NTSTATUS kuhl_m_standard_sleep(int argc, wchar_t * argv[]) NTSTATUS kuhl_m_standard_log(int argc, wchar_t * argv[]) { PCWCHAR filename = (kull_m_string_args_byName(argc, argv, L"stop", NULL, NULL) ? NULL : (argc ? argv[0] : MIMIKATZ_DEFAULT_LOG)); + kull_m_string_args_bool_byName(argc, argv, L"base64", &isBase64Output); kprintf(L"Using \'%s\' for logfile : %s\n", filename, kull_m_output_file(filename) ? L"OK" : L"KO"); return STATUS_SUCCESS; } @@ -267,4 +268,4 @@ NTSTATUS kuhl_m_standard_hostname(int argc, wchar_t * argv[]) } kprintf(L"\n"); return STATUS_SUCCESS; -} \ No newline at end of file +} From 12b650607bb4b594d38dec6ec219744c01ab2104 Mon Sep 17 00:00:00 2001 From: Francesco Soncina Date: Wed, 30 Oct 2019 14:49:45 +0100 Subject: [PATCH 4/7] Add support for base64 output format --- modules/kull_m_output.c | 109 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 7 deletions(-) diff --git a/modules/kull_m_output.c b/modules/kull_m_output.c index 6532f4f5..afec4e73 100644 --- a/modules/kull_m_output.c +++ b/modules/kull_m_output.c @@ -58,8 +58,54 @@ void kprintf(PCWCHAR format, ...) #endif if(logfile) { - vfwprintf(logfile, format, args); - fflush(logfile); + if(isBase64Output) + { + // get current size + size_t current_length = ftell(logfile); + // get new content size + size_t appended_length = _vscwprintf(format, args); + // set position to 0 + fseek(logfile, 0, SEEK_SET); + // alloc current_content buffer + LPWSTR current_content = LocalAlloc(LPTR, current_length + 1); + // read current content + size_t n_read = fread_s(current_content, current_length, sizeof(wchar_t), current_length / sizeof(wchar_t), logfile); + current_content[current_length] = '\x00'; + // base64decode + size_t decoded_length = 0; + CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, NULL, &decoded_length, NULL, NULL); + wchar_t* decoded_content = LocalAlloc(LPTR, decoded_length * sizeof(wchar_t)); + CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, (BYTE *) decoded_content, &decoded_length, NULL, NULL); + // concat data + wchar_t* concatenated_content = LocalAlloc(LPTR, decoded_length * sizeof(wchar_t) + appended_length * sizeof(wchar_t) + 1); + memcpy(concatenated_content, decoded_content, decoded_length); + vswprintf(concatenated_content + wcslen(concatenated_content), appended_length + 1, format, args); + // base64encode + size_t encoded_length = 0; + CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, NULL, &encoded_length); + LPWSTR encoded_content = LocalAlloc(LPTR, encoded_length * sizeof(wchar_t)); + CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, encoded_content, &encoded_length); + // write to file + fseek(logfile, 0, SEEK_SET); + for(size_t i = 0; i < encoded_length; i++) + { + if(encoded_content[i] != '\x0d' && encoded_content[i] != '\x0a' && encoded_content[i] != '\x00') + fwrite(encoded_content + i, sizeof(wchar_t), 1, logfile); + } + + fflush(logfile); + // free temporary buffers + LocalFree(current_content); + LocalFree(decoded_content); + LocalFree(concatenated_content); + LocalFree(encoded_content); + // TODO: check for errors + } + else + { + vfwprintf(logfile, format, args); + fflush(logfile); + } } va_end(args); } @@ -68,10 +114,56 @@ void kprintf_inputline(PCWCHAR format, ...) { va_list args; va_start(args, format); - if(logfile) + if (logfile) { - vfwprintf(logfile, format, args); - fflush(logfile); + if(isBase64Output) + { + // get current size + size_t current_length = ftell(logfile); + // get new content size + size_t appended_length = _vscwprintf(format, args); + // set position to 0 + fseek(logfile, 0, SEEK_SET); + // alloc current_content buffer + LPWSTR current_content = LocalAlloc(LPTR, current_length + 1); + // read current content + size_t n_read = fread_s(current_content, current_length, sizeof(wchar_t), current_length / sizeof(wchar_t), logfile); + current_content[current_length] = '\x00'; + // base64decode + size_t decoded_length = 0; + CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, NULL, &decoded_length, NULL, NULL); + wchar_t* decoded_content = LocalAlloc(LPTR, decoded_length * sizeof(wchar_t)); + CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, (BYTE *) decoded_content, &decoded_length, NULL, NULL); + // concat data + wchar_t* concatenated_content = LocalAlloc(LPTR, decoded_length * sizeof(wchar_t) + appended_length * sizeof(wchar_t) + 1); + memcpy(concatenated_content, decoded_content, decoded_length); + vswprintf(concatenated_content + wcslen(concatenated_content), appended_length + 1, format, args); + // base64encode + size_t encoded_length = 0; + CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, NULL, &encoded_length); + LPWSTR encoded_content = LocalAlloc(LPTR, encoded_length * sizeof(wchar_t)); + CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, encoded_content, &encoded_length); + // write to file + fseek(logfile, 0, SEEK_SET); + for(size_t i = 0; i < encoded_length; i++) + { + if(encoded_content[i] != '\x0d' && encoded_content[i] != '\x0a' && encoded_content[i] != '\x00') + fwrite(encoded_content + i, sizeof(wchar_t), 1, logfile); + } + + fflush(logfile); + // free temporary buffers + LocalFree(current_content); + LocalFree(decoded_content); + LocalFree(concatenated_content); + LocalFree(encoded_content); + // TODO: check for errors + } + else + { + vfwprintf(logfile, format, args); + fflush(logfile); + } } va_end(args); } @@ -82,10 +174,13 @@ BOOL kull_m_output_file(PCWCHAR file) FILE * newlog = NULL; if(file) + { #pragma warning(push) #pragma warning(disable:4996) - newlog = _wfopen(file, L"a"); // XP does not like _wfopen_s + newlog = _wfopen(file, L"w+"); // XP does not like _wfopen_s + fseek(newlog, 0, SEEK_END); #pragma warning(pop) + } if(newlog || !file) { if(logfile) @@ -118,4 +213,4 @@ void kull_m_output_clean() #endif SetConsoleOutputCP(previousConsoleOutput); #endif -} \ No newline at end of file +} From 1ed49f2bbf367bba8ef621a66208a0576c604ccd Mon Sep 17 00:00:00 2001 From: Francesco Soncina Date: Wed, 30 Oct 2019 14:51:30 +0100 Subject: [PATCH 5/7] Fix indentation --- modules/kull_m_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kull_m_output.c b/modules/kull_m_output.c index afec4e73..bd2e6120 100644 --- a/modules/kull_m_output.c +++ b/modules/kull_m_output.c @@ -114,7 +114,7 @@ void kprintf_inputline(PCWCHAR format, ...) { va_list args; va_start(args, format); - if (logfile) + if(logfile) { if(isBase64Output) { From ca5c2044bdd949e9f6fe29e7b9b23dc4ea702c51 Mon Sep 17 00:00:00 2001 From: Francesco Soncina Date: Thu, 31 Oct 2019 11:57:44 +0100 Subject: [PATCH 6/7] Fix x64 build --- modules/kull_m_output.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/kull_m_output.c b/modules/kull_m_output.c index bd2e6120..5af573df 100644 --- a/modules/kull_m_output.c +++ b/modules/kull_m_output.c @@ -61,9 +61,9 @@ void kprintf(PCWCHAR format, ...) if(isBase64Output) { // get current size - size_t current_length = ftell(logfile); + DWORD current_length = ftell(logfile); // get new content size - size_t appended_length = _vscwprintf(format, args); + DWORD appended_length = _vscwprintf(format, args); // set position to 0 fseek(logfile, 0, SEEK_SET); // alloc current_content buffer @@ -72,7 +72,7 @@ void kprintf(PCWCHAR format, ...) size_t n_read = fread_s(current_content, current_length, sizeof(wchar_t), current_length / sizeof(wchar_t), logfile); current_content[current_length] = '\x00'; // base64decode - size_t decoded_length = 0; + DWORD decoded_length = 0; CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, NULL, &decoded_length, NULL, NULL); wchar_t* decoded_content = LocalAlloc(LPTR, decoded_length * sizeof(wchar_t)); CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, (BYTE *) decoded_content, &decoded_length, NULL, NULL); @@ -81,13 +81,13 @@ void kprintf(PCWCHAR format, ...) memcpy(concatenated_content, decoded_content, decoded_length); vswprintf(concatenated_content + wcslen(concatenated_content), appended_length + 1, format, args); // base64encode - size_t encoded_length = 0; + DWORD encoded_length = 0; CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, NULL, &encoded_length); LPWSTR encoded_content = LocalAlloc(LPTR, encoded_length * sizeof(wchar_t)); CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, encoded_content, &encoded_length); // write to file fseek(logfile, 0, SEEK_SET); - for(size_t i = 0; i < encoded_length; i++) + for(DWORD i = 0; i < encoded_length; i++) { if(encoded_content[i] != '\x0d' && encoded_content[i] != '\x0a' && encoded_content[i] != '\x00') fwrite(encoded_content + i, sizeof(wchar_t), 1, logfile); @@ -119,9 +119,9 @@ void kprintf_inputline(PCWCHAR format, ...) if(isBase64Output) { // get current size - size_t current_length = ftell(logfile); + DWORD current_length = ftell(logfile); // get new content size - size_t appended_length = _vscwprintf(format, args); + DWORD appended_length = _vscwprintf(format, args); // set position to 0 fseek(logfile, 0, SEEK_SET); // alloc current_content buffer @@ -130,7 +130,7 @@ void kprintf_inputline(PCWCHAR format, ...) size_t n_read = fread_s(current_content, current_length, sizeof(wchar_t), current_length / sizeof(wchar_t), logfile); current_content[current_length] = '\x00'; // base64decode - size_t decoded_length = 0; + DWORD decoded_length = 0; CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, NULL, &decoded_length, NULL, NULL); wchar_t* decoded_content = LocalAlloc(LPTR, decoded_length * sizeof(wchar_t)); CryptStringToBinary(current_content, current_length, CRYPT_STRING_BASE64, (BYTE *) decoded_content, &decoded_length, NULL, NULL); @@ -139,13 +139,13 @@ void kprintf_inputline(PCWCHAR format, ...) memcpy(concatenated_content, decoded_content, decoded_length); vswprintf(concatenated_content + wcslen(concatenated_content), appended_length + 1, format, args); // base64encode - size_t encoded_length = 0; + DWORD encoded_length = 0; CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, NULL, &encoded_length); LPWSTR encoded_content = LocalAlloc(LPTR, encoded_length * sizeof(wchar_t)); CryptBinaryToString((const BYTE *) concatenated_content, decoded_length + appended_length * sizeof(wchar_t), CRYPT_STRING_BASE64, encoded_content, &encoded_length); // write to file fseek(logfile, 0, SEEK_SET); - for(size_t i = 0; i < encoded_length; i++) + for(DWORD i = 0; i < encoded_length; i++) { if(encoded_content[i] != '\x0d' && encoded_content[i] != '\x0a' && encoded_content[i] != '\x00') fwrite(encoded_content + i, sizeof(wchar_t), 1, logfile); From e7ea5c0b6f715f5c6b53ec54fc76b245c77b749e Mon Sep 17 00:00:00 2001 From: Francesco Soncina Date: Thu, 31 Oct 2019 12:02:00 +0100 Subject: [PATCH 7/7] Add encoding info to log message ``` mimikatz # log mimi /base64:on Using 'mimi' for logfile : OK [UTF16LE+BASE64] ``` --- mimikatz/modules/kuhl_m_standard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mimikatz/modules/kuhl_m_standard.c b/mimikatz/modules/kuhl_m_standard.c index 53ee55b7..6da2722e 100644 --- a/mimikatz/modules/kuhl_m_standard.c +++ b/mimikatz/modules/kuhl_m_standard.c @@ -73,7 +73,7 @@ NTSTATUS kuhl_m_standard_log(int argc, wchar_t * argv[]) { PCWCHAR filename = (kull_m_string_args_byName(argc, argv, L"stop", NULL, NULL) ? NULL : (argc ? argv[0] : MIMIKATZ_DEFAULT_LOG)); kull_m_string_args_bool_byName(argc, argv, L"base64", &isBase64Output); - kprintf(L"Using \'%s\' for logfile : %s\n", filename, kull_m_output_file(filename) ? L"OK" : L"KO"); + kprintf(L"Using \'%s\' for logfile : %s %s\n", filename, kull_m_output_file(filename) ? L"OK" : L"KO", isBase64Output ? L"[UTF16LE+BASE64]" : L""); return STATUS_SUCCESS; }