From 34ae571fa01300864527203e44c9e7d7921f5fd1 Mon Sep 17 00:00:00 2001 From: Ramon Novoa Date: Thu, 25 May 2023 20:56:21 +0200 Subject: [PATCH] Encode log data to base64 to prevent it from breaking XML data files. --- pandora_agents/unix/plugins/grep_log | 44 ++++++++++++++-- pandora_agents/unix/plugins/grep_log_module | 42 ++++++++++++++-- .../win32/modules/pandora_module.cc | 14 ++---- pandora_agents/win32/pandora_strutils.cc | 50 +++++++++++++++++++ pandora_agents/win32/pandora_strutils.h | 1 + 5 files changed, 134 insertions(+), 17 deletions(-) diff --git a/pandora_agents/unix/plugins/grep_log b/pandora_agents/unix/plugins/grep_log index 2143464b48..1ecba6266a 100755 --- a/pandora_agents/unix/plugins/grep_log +++ b/pandora_agents/unix/plugins/grep_log @@ -22,6 +22,11 @@ use strict; use File::Basename; use Scalar::Util qw(looks_like_number); +BEGIN { + eval { + require MIME::Base64; + }; +} # Output format (module or log_module). my $Output = 'module'; @@ -65,6 +70,37 @@ if ( (defined ($ENV{GREP_LOG_TMP})) && (-d $ENV{GREP_LOG_TMP}) ) { $Idx_dir=$ENV{GREP_LOG_TMP}; } +# Define encode_base64 if it is not available via MIME::Base64. +my $encode_sub = defined(&MIME::Base64::encode_base64) ? \&MIME::Base64::encode_base64 : sub { + my ($str, $endl) = @_; + + my @ALPHABET = ('A'..'Z', 'a'..'z', 0..9, '+', '/'); + my $str_len = length($str); + my $str_base64 = ''; + + for (my $i = 0; $i < $str_len; $i += 3) { + my $chunk = substr($str, $i, 3); + my $chunk_len = length($chunk); + + my $num = 0; + $num |= ord(substr($chunk, 0, 1)) << 16 if ($chunk_len >= 1); + $num |= ord(substr($chunk, 1, 1)) << 8 if ($chunk_len >= 2); + $num |= ord(substr($chunk, 2, 1)) if ($chunk_len == 3); + + my $enc_1 = ($num & 0xfc0000) >> 18; + my $enc_2 = ($num & 0x03f000) >> 12; + my $enc_3 = ($num & 0x000fc0) >> 6; + my $enc_4 = ($num & 0x00003f); + + $str_base64 .= $ALPHABET[$enc_1]; + $str_base64 .= $ALPHABET[$enc_2]; + $str_base64 .= $chunk_len >= 2 ? $ALPHABET[$enc_3] : '='; + $str_base64 .= $chunk_len == 3 ? $ALPHABET[$enc_4] : '='; + } + + return $str_base64; +}; + ######################################################################################## # Erase blank spaces before and after the string ######################################################################################## @@ -335,11 +371,13 @@ sub print_log ($) { my $output = "\n"; $output .= "\n"; $output .= "{$line}}) { + $tmp .= $content; + } } + $output .= &$encode_sub($tmp, ''); $output .= "]]>"; $output .= "\n"; diff --git a/pandora_agents/unix/plugins/grep_log_module b/pandora_agents/unix/plugins/grep_log_module index 6fc1cff239..d15a6f7c08 100755 --- a/pandora_agents/unix/plugins/grep_log_module +++ b/pandora_agents/unix/plugins/grep_log_module @@ -22,6 +22,11 @@ use strict; use File::Basename; +BEGIN { + eval { + require MIME::Base64; + }; +} # Output format (module or log_module). my $Output = 'log_module'; @@ -53,6 +58,37 @@ my $Idx_size = 0; # Regular expression to be matched my $Reg_exp = ''; +# Define encode_base64 if it is not available via MIME::Base64. +my $encode_sub = defined(&MIME::Base64::encode_base64) ? \&MIME::Base64::encode_base64 : sub { + my ($str, $endl) = @_; + + my @ALPHABET = ('A'..'Z', 'a'..'z', 0..9, '+', '/'); + my $str_len = length($str); + my $str_base64 = ''; + + for (my $i = 0; $i < $str_len; $i += 3) { + my $chunk = substr($str, $i, 3); + my $chunk_len = length($chunk); + + my $num = 0; + $num |= ord(substr($chunk, 0, 1)) << 16 if ($chunk_len >= 1); + $num |= ord(substr($chunk, 1, 1)) << 8 if ($chunk_len >= 2); + $num |= ord(substr($chunk, 2, 1)) if ($chunk_len == 3); + + my $enc_1 = ($num & 0xfc0000) >> 18; + my $enc_2 = ($num & 0x03f000) >> 12; + my $enc_3 = ($num & 0x000fc0) >> 6; + my $enc_4 = ($num & 0x00003f); + + $str_base64 .= $ALPHABET[$enc_1]; + $str_base64 .= $ALPHABET[$enc_2]; + $str_base64 .= $chunk_len >= 2 ? $ALPHABET[$enc_3] : '='; + $str_base64 .= $chunk_len == 3 ? $ALPHABET[$enc_4] : '='; + } + + return $str_base64; +}; + ############################################################################### # SUB error_msg # Print an error message and exit. @@ -213,11 +249,9 @@ sub print_log (@) { if ($Output eq 'log_module') { my $output = "\n"; $output .= "\n"; + $output .= "base64\n"; $output .= ""; $output .= "\n"; diff --git a/pandora_agents/win32/modules/pandora_module.cc b/pandora_agents/win32/modules/pandora_module.cc index d5bd1fc21d..4a6382acf6 100644 --- a/pandora_agents/win32/modules/pandora_module.cc +++ b/pandora_agents/win32/modules/pandora_module.cc @@ -520,7 +520,7 @@ Pandora_Module::getXml () { if (this->module_type == TYPE_LOG) { module_xml = "\n\tmodule_name; - module_xml += "]]>\n\t\n\tbase64\n\tdata_list && this->data_list->size () > 1) { list::iterator iter; @@ -532,25 +532,19 @@ Pandora_Module::getXml () { data = *iter; try { - data_clean = strreplace (this->getDataOutput (data), - "%", "%%" ); - data_clean = strreplace (data_clean, "]]>", "]]>getDataOutput(data); } catch (Module_Exception e) { continue; } - - module_xml += data_clean; } } else { data = data_list->front (); try { - data_clean = strreplace (this->getDataOutput (data), "%", "%%" ); - data_clean = strreplace (data_clean, "]]>", "]]>getDataOutput (data); } catch (Module_Exception e) { } } + module_xml += base64Encode(data_clean); module_xml += "]]>"; /* Clean up */ diff --git a/pandora_agents/win32/pandora_strutils.cc b/pandora_agents/win32/pandora_strutils.cc index ea3bbf51f0..83f1019d08 100644 --- a/pandora_agents/win32/pandora_strutils.cc +++ b/pandora_agents/win32/pandora_strutils.cc @@ -24,6 +24,8 @@ #include #include #include // for strchr +#include +#include using namespace Pandora; @@ -56,6 +58,54 @@ Pandora_Strutils::trim (const string str) { return result; } +/** + * Encode the given string to base64. + * Based on: https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64 + * + * @param str String to be encoded. + * + * @return The base64 encoded string. + */ +string +Pandora_Strutils::base64Encode(string str) { + string base64_str; + std::uint32_t temp; + const static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::vector buffer(begin(str), end(str)); + base64_str.reserve(((buffer.size() / 3) + (buffer.size() % 3 > 0)) * 4); + + std::vector::iterator cursor = buffer.begin(); + for(size_t idx = 0; idx < buffer.size() / 3; idx++) { + temp = (*cursor++) << 16; + temp += (*cursor++) << 8; + temp += (*cursor++); + base64_str.append(1, alphabet[(temp & 0x00FC0000) >> 18]); + base64_str.append(1, alphabet[(temp & 0x0003F000) >> 12]); + base64_str.append(1, alphabet[(temp & 0x00000FC0) >> 6]); + base64_str.append(1, alphabet[(temp & 0x0000003F)]); + } + + switch(buffer.size() % 3){ + case 1: + temp = (*cursor++) << 16; + base64_str.append(1, alphabet[(temp & 0x00FC0000) >> 18]); + base64_str.append(1, alphabet[(temp & 0x0003F000) >> 12]); + base64_str.append(2, '='); + break; + case 2: + temp = (*cursor++) << 16; + temp += (*cursor++) << 8; + base64_str.append(1, alphabet[(temp & 0x00FC0000) >> 18]); + base64_str.append(1, alphabet[(temp & 0x0003F000) >> 12]); + base64_str.append(1, alphabet[(temp & 0x00000FC0) >> 6]); + base64_str.append(1, '='); + break; + } + + return base64_str; +} + /** * Convert an unicode string to a ANSI string. * diff --git a/pandora_agents/win32/pandora_strutils.h b/pandora_agents/win32/pandora_strutils.h index c105c9c3a9..fb7562d64d 100644 --- a/pandora_agents/win32/pandora_strutils.h +++ b/pandora_agents/win32/pandora_strutils.h @@ -44,6 +44,7 @@ namespace Pandora_Strutils { string trim (const string str); + string base64Encode(string str); string strUnicodeToAnsi (LPCWSTR s); wstring strAnsiToUnicode (LPCSTR s); string inttostr (const int i);