From bf4a9d76333fdfb6c2a69c07c48cd893194797ca Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Tue, 24 May 2016 15:42:32 -0300 Subject: [PATCH] Adds support to base64DecodeExt transformation More info on #964 --- .../transformations/base64_decode_ext.cc | 19 +-- .../transformations/base64_decode_ext.h | 3 +- src/actions/transformations/transformation.cc | 2 +- src/utils/base64.cc | 146 +++++++++++++++++- src/utils/base64.h | 8 + 5 files changed, 156 insertions(+), 22 deletions(-) diff --git a/src/actions/transformations/base64_decode_ext.cc b/src/actions/transformations/base64_decode_ext.cc index d19b40b3..f823b297 100644 --- a/src/actions/transformations/base64_decode_ext.cc +++ b/src/actions/transformations/base64_decode_ext.cc @@ -24,31 +24,22 @@ #include "modsecurity/transaction.h" #include "actions/transformations/transformation.h" +#include "utils/base64.h" namespace modsecurity { namespace actions { namespace transformations { -Base64DecodeExt::Base64DecodeExt(std::string action) - : Transformation(action) { - this->action_kind = 1; -} std::string Base64DecodeExt::evaluate(std::string value, Transaction *transaction) { - /** - * @todo Implement the transformation Base64DecodeExt - */ - if (transaction) { -#ifndef NO_LOGS - transaction->debug(4, "Transformation Base64DecodeExt is" \ - " not implemented yet."); -#endif - } - return value; + std::string ret = Utils::Base64::decode_forgiven(value); + + return ret; } + } // namespace transformations } // namespace actions } // namespace modsecurity diff --git a/src/actions/transformations/base64_decode_ext.h b/src/actions/transformations/base64_decode_ext.h index dd572d99..8f673334 100644 --- a/src/actions/transformations/base64_decode_ext.h +++ b/src/actions/transformations/base64_decode_ext.h @@ -30,7 +30,8 @@ namespace transformations { class Base64DecodeExt : public Transformation { public: - explicit Base64DecodeExt(std::string action); + explicit Base64DecodeExt(std::string action) : Transformation(action) { } + std::string evaluate(std::string exp, Transaction *transaction) override; }; diff --git a/src/actions/transformations/transformation.cc b/src/actions/transformations/transformation.cc index 8e6d3649..06839397 100644 --- a/src/actions/transformations/transformation.cc +++ b/src/actions/transformations/transformation.cc @@ -74,7 +74,7 @@ std::string Transformation::evaluate(std::string value, Transformation* Transformation::instantiate(std::string a) { - IF_MATCH(base64_decode_ext) { return new Base64DecodeExt(a); } + IF_MATCH(base64DecodeExt) { return new Base64DecodeExt(a); } IF_MATCH(base64Decode) { return new Base64Decode(a); } IF_MATCH(base64Encode) { return new Base64Encode(a); } IF_MATCH(cmd_line) { return new CmdLine(a); } diff --git a/src/utils/base64.cc b/src/utils/base64.cc index 8271c7b0..b5f66db6 100644 --- a/src/utils/base64.cc +++ b/src/utils/base64.cc @@ -31,7 +31,7 @@ std::string Base64::encode(std::string& data) { std::string ret; mbedtls_base64_encode(NULL, 0, &encoded_len, - reinterpret_cast(data.c_str()), data.length()); + reinterpret_cast(data.c_str()), data.size()); d = reinterpret_cast(malloc(sizeof(char) * encoded_len)); if (d == NULL) { @@ -41,9 +41,9 @@ std::string Base64::encode(std::string& data) { memset(d, '\0', encoded_len); mbedtls_base64_encode(d, encoded_len, &encoded_len, - (unsigned char*) data.c_str(), data.length()); + (unsigned char*) data.c_str(), data.size()); - ret.assign(reinterpret_cast(d)); + ret.assign(reinterpret_cast(d), encoded_len); free(d); @@ -51,13 +51,23 @@ std::string Base64::encode(std::string& data) { } +std::string Base64::decode(std::string& data, bool forgiven) { + if (forgiven) { + return decode_forgiven(data); + } + + return decode(data); +} + + std::string Base64::decode(std::string& data) { size_t decoded_len = 0; unsigned char *d = NULL; std::string ret; + size_t len = strlen(data.c_str()); mbedtls_base64_decode(NULL, 0, &decoded_len, - reinterpret_cast(data.c_str()), data.length()); + reinterpret_cast(data.c_str()), len); d = reinterpret_cast(malloc(sizeof(char) * decoded_len)); if (d == NULL) { @@ -67,14 +77,138 @@ std::string Base64::decode(std::string& data) { memset(d, '\0', decoded_len); mbedtls_base64_decode(d, decoded_len, &decoded_len, - reinterpret_cast(data.c_str()), data.length()); + reinterpret_cast(data.c_str()), len); - ret.assign(reinterpret_cast(d)); + ret.assign(reinterpret_cast(d), decoded_len); free(d); return ret; } +std::string Base64::decode_forgiven(std::string& data) { + size_t decoded_len = 0; + unsigned char *d = NULL; + std::string ret; + + decode_forgiven_engine(NULL, 0, &decoded_len, + reinterpret_cast(data.c_str()), data.size()); + + d = reinterpret_cast(malloc(sizeof(char) * decoded_len)); + if (d == NULL) { + return data; + } + + memset(d, '\0', decoded_len); + + decode_forgiven_engine(d, decoded_len, &decoded_len, + reinterpret_cast(data.c_str()), data.size()); + + ret.assign(reinterpret_cast(d), decoded_len); + free(d); + + return ret; +} + + +void Base64::decode_forgiven_engine(unsigned char *plain_text, + size_t plain_text_size, size_t *aiming_size, + const unsigned char *encoded, size_t input_len) { + int i = 0, j = 0, k = 0; + int ch = 0; + static const char b64_pad = '='; + static short b64_reverse_t[256] = { + -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -2, -1, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2, + -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2, + -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 + }; + + + while (/*ch = *encoded++ != '\0' && */input_len-- > 0) { + ch = *encoded++; + if (ch == b64_pad) { + if (*encoded != '=' && (i % 4) == 1) { + *aiming_size = 0; + return; + } + continue; + } + + ch = b64_reverse_t[ch]; + if (ch < 0 || ch == -1) { + continue; + } else if (ch == -2) { + *aiming_size = 0; + return; + } + switch(i % 4) { + case 0: + if (plain_text_size != 0) { + plain_text[j] = ch << 2; + } + break; + case 1: + if (plain_text_size == 0) { + j++; + } else { + plain_text[j++] |= ch >> 4; + plain_text[j] = (ch & 0x0f) << 4; + } + break; + case 2: + if (plain_text_size == 0) { + j++; + } else { + plain_text[j++] |= ch >>2; + plain_text[j] = (ch & 0x03) << 6; + } + break; + case 3: + if (plain_text_size == 0) { + j++; + } else { + plain_text[j++] |= ch; + } + break; + } + i++; + } + + k = j; + if (ch == b64_pad) { + switch(i % 4) { + case 1: + *aiming_size = 0; + return; + case 2: + k++; + case 3: + if (plain_text_size != 0) { + plain_text[k] = 0; + } + } + } + + if (plain_text_size != 0) { + plain_text[j] = '\0'; + } + + *aiming_size = j; +} + + } // namespace Utils } // namespace modsecurity diff --git a/src/utils/base64.h b/src/utils/base64.h index 4cb96414..265785b5 100644 --- a/src/utils/base64.h +++ b/src/utils/base64.h @@ -8,7 +8,15 @@ class Base64 { Base64() { } static std::string encode(std::string& data); + + static std::string decode(std::string& data, bool forgiven); static std::string decode(std::string& data); + static std::string decode_forgiven(std::string& data); + + static void decode_forgiven_engine(unsigned char *output, + size_t output_size, size_t *aiming_size, const unsigned char *input, + size_t input_size); + };