diff --git a/src/actions/transformations/transformation.cc b/src/actions/transformations/transformation.cc index 1efd7061..fc0829f3 100644 --- a/src/actions/transformations/transformation.cc +++ b/src/actions/transformations/transformation.cc @@ -108,7 +108,7 @@ Transformation* Transformation::instantiate(std::string a) { IF_MATCH(trim) { return new Trim(a); } IF_MATCH(urlDecode) { return new UrlDecode(a); } IF_MATCH(urlDecodeUni) { return new UrlDecodeUni(a); } - IF_MATCH(url_encode) { return new UrlEncode(a); } + IF_MATCH(urlEncode) { return new UrlEncode(a); } IF_MATCH(utf8_to_unicode) { return new Utf8Unicode(a); } return new Transformation(a); diff --git a/src/actions/transformations/url_encode.cc b/src/actions/transformations/url_encode.cc index d6041892..8c900eac 100644 --- a/src/actions/transformations/url_encode.cc +++ b/src/actions/transformations/url_encode.cc @@ -24,30 +24,79 @@ #include "modsecurity/assay.h" #include "actions/transformations/transformation.h" - +#include "src/utils.h" namespace ModSecurity { namespace actions { namespace transformations { + UrlEncode::UrlEncode(std::string action) : Transformation(action) { this->action_kind = 1; } + +std::string UrlEncode::url_enc(const char *input, + unsigned int input_len, int *changed) { + char *rval, *d; + unsigned int i, len; + int count = 0; + + *changed = 0; + + len = input_len * 3 + 1; + d = rval = (char *)malloc(len); + if (rval == NULL) { + return NULL; + } + + /* ENH Only encode the characters that really need to be encoded. */ + + for (i = 0; i < input_len; i++) { + unsigned char c = input[i]; + + if (c == ' ') { + *d++ = '+'; + *changed = 1; + count++; + } else { + if ( (c == 42) || ((c >= 48) && (c <= 57)) + || ((c >= 65) && (c <= 90)) + || ((c >= 97)&&(c <= 122))) { + *d++ = c; + count++; + } else { + *d++ = '%'; + count++; + c2x(c, (unsigned char *)d); + d += 2; + count++; + count++; + *changed = 1; + } + } + } + + *d = '\0'; + + std::string ret(""); + ret.append(rval, count); + free(rval); + return ret; +} + + std::string UrlEncode::evaluate(std::string value, Assay *assay) { - /** - * @todo Implement the transformation UrlEncode - */ - if (assay) { -#ifndef NO_LOGS - assay->debug(4, "Transformation UrlEncode is not implemented yet."); -#endif - } - return value; + int changed; + + std::string ret = url_enc(value.c_str(), value.size(), &changed); + + return ret; } + } // namespace transformations } // namespace actions } // namespace ModSecurity diff --git a/src/actions/transformations/url_encode.h b/src/actions/transformations/url_encode.h index 1028de08..eee911b1 100644 --- a/src/actions/transformations/url_encode.h +++ b/src/actions/transformations/url_encode.h @@ -33,6 +33,9 @@ class UrlEncode : public Transformation { explicit UrlEncode(std::string action); std::string evaluate(std::string exp, Assay *assay) override; + + std::string url_enc(const char *input, + unsigned int input_len, int *changed); }; } // namespace transformations diff --git a/src/utils.cc b/src/utils.cc index ae2a53d8..8a42c6a3 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -842,6 +842,17 @@ unsigned char x2c(unsigned char *what) { } +unsigned char *c2x(unsigned what, unsigned char *where) { + static const char c2x_table[] = "0123456789abcdef"; + + what = what & 0xff; + *where++ = c2x_table[what >> 4]; + *where++ = c2x_table[what & 0x0f]; + + return where; +} + + std::string string_to_hex(const std::string& input) { static const char* const lut = "0123456789ABCDEF"; size_t len = input.length(); diff --git a/src/utils.h b/src/utils.h index c5b21a14..3534b353 100644 --- a/src/utils.h +++ b/src/utils.h @@ -43,6 +43,7 @@ namespace ModSecurity { double cpu_seconds(void); int js_decode_nonstrict_inplace(unsigned char *input, int64_t input_len); unsigned char x2c(unsigned char *what); + unsigned char *c2x(unsigned what, unsigned char *where); int css_decode_inplace(unsigned char *input, int64_t input_len); unsigned char xsingle2c(unsigned char *what); int html_entities_decode_inplace(unsigned char *input, int input_len);