Adds support to URL decode transformation

This commit is contained in:
Felipe Zimmerle 2015-10-22 17:20:31 -03:00
parent 0227fe9d6c
commit e3e8bac138
7 changed files with 113 additions and 25 deletions

View File

@ -106,7 +106,7 @@ Transformation* Transformation::instantiate(std::string a) {
IF_MATCH(trimLeft) { return new TrimLeft(a); }
IF_MATCH(trimRight) { return new TrimRight(a); }
IF_MATCH(trim) { return new Trim(a); }
IF_MATCH(url_decode) { return new UrlDecode(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(utf8_to_unicode) { return new Utf8Unicode(a); }

View File

@ -24,12 +24,71 @@
#include "modsecurity/assay.h"
#include "actions/transformations/transformation.h"
#include "src/utils.h"
namespace ModSecurity {
namespace actions {
namespace transformations {
int UrlDecode::urldecode_nonstrict_inplace(unsigned char *input,
long int input_len, int *invalid_count, int *changed) {
unsigned char *d = (unsigned char *)input;
long int i, count;
*changed = 0;
if (input == NULL) {
return -1;
}
i = count = 0;
while (i < input_len) {
if (input[i] == '%') {
/* Character is a percent sign. */
/* Are there enough bytes available? */
if (i + 2 < input_len) {
char c1 = input[i + 1];
char c2 = input[i + 2];
if (VALID_HEX(c1) && VALID_HEX(c2)) {
unsigned long uni = x2c(&input[i + 1]);
*d++ = (wchar_t)uni;
count++;
i += 3;
*changed = 1;
} else {
/* Not a valid encoding, skip this % */
*d++ = input[i++];
count ++;
(*invalid_count)++;
}
} else {
/* Not enough bytes available, copy the raw bytes. */
*d++ = input[i++];
count ++;
(*invalid_count)++;
}
} else {
/* Character is not a percent sign. */
if (input[i] == '+') {
*d++ = ' ';
*changed = 1;
} else {
*d++ = input[i];
}
count++;
i++;
}
}
*d = '\0';
return count;
}
UrlDecode::UrlDecode(std::string action)
: Transformation(action) {
this->action_kind = 1;
@ -37,17 +96,25 @@ UrlDecode::UrlDecode(std::string action)
std::string UrlDecode::evaluate(std::string value,
Assay *assay) {
/**
* @todo Implement the transformation UrlDecode
*/
if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation UrlDecode is not implemented yet.");
#endif
}
return value;
unsigned char *val = NULL;
int invalid_count;
int changed;
val = (unsigned char *) malloc(sizeof(char) * value.size() + 1);
memcpy(val, value.c_str(), value.size() + 1);
val[value.size()] = '\0';
int size = urldecode_nonstrict_inplace(val, value.size(), &invalid_count, &changed);
std::string out;
out.append((const char *)val, size);
free(val);
return out;
}
} // namespace transformations
} // namespace actions
} // namespace ModSecurity

View File

@ -33,6 +33,9 @@ class UrlDecode : public Transformation {
explicit UrlDecode(std::string action);
std::string evaluate(std::string exp,
Assay *assay) override;
int urldecode_nonstrict_inplace(unsigned char *input, long int input_len,
int *invalid_count, int *changed);
};
} // namespace transformations

View File

@ -43,11 +43,6 @@
#include "modsecurity/modsecurity.h"
#define VALID_HEX(X) (((X >= '0') && (X <= '9')) || \
((X >= 'a') && (X <= 'f')) || ((X >= 'A') && (X <= 'F')))
#define ISODIGIT(X) ((X >= '0') && (X <= '7'))
#define NBSP 160
namespace ModSecurity {
std::string phase_name(int x) {
@ -827,7 +822,7 @@ length:
/**
* Converts a single hexadecimal digit into a decimal value.
*/
static unsigned char xsingle2c(unsigned char *what) {
unsigned char xsingle2c(unsigned char *what) {
register unsigned char digit;
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
@ -836,7 +831,7 @@ static unsigned char xsingle2c(unsigned char *what) {
}
static unsigned char x2c(unsigned char *what) {
unsigned char x2c(unsigned char *what) {
register unsigned char digit;
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));

View File

@ -22,6 +22,13 @@
#ifndef SRC_UTILS_H_
#define VALID_HEX(X) (((X >= '0') && (X <= '9')) || \
((X >= 'a') && (X <= 'f')) || ((X >= 'A') && (X <= 'F')))
#define ISODIGIT(X) ((X >= '0') && (X <= '7'))
#define NBSP 160
namespace ModSecurity {
std::vector<std::string> split(std::string str, char delimiter);
double random_number(const double from, const double to);
@ -35,9 +42,9 @@ namespace ModSecurity {
std::string toupper(std::string str);
double cpu_seconds(void);
int js_decode_nonstrict_inplace(unsigned char *input, int64_t input_len);
static unsigned char x2c(unsigned char *what);
unsigned char x2c(unsigned char *what);
int css_decode_inplace(unsigned char *input, int64_t input_len);
static unsigned char xsingle2c(unsigned char *what);
unsigned char xsingle2c(unsigned char *what);
int html_entities_decode_inplace(unsigned char *input, int input_len);
int normalize_path_inplace(unsigned char *input, int input_len,
int win, int *changed);

@ -1 +1 @@
Subproject commit 1f6f5235485e4a68f9cd57d2ac1ad4a0d4a7a3c4
Subproject commit 76c4bd6460a870b481eb4d36fcead7818b20d7d9

View File

@ -93,6 +93,11 @@ UnitTest *UnitTest::from_yajl_node(yajl_val &node) {
u->param = YAJL_GET_STRING(val);
} else if (strcmp(key, "input") == 0) {
u->input = YAJL_GET_STRING(val);
/*
* Converting \\u0000 to \0 due to the following gcc bug:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690
*
*/
replaceAll(&(u->input), "\\0", '\0');
replaceAll(&(u->input), "\\xe4", '\xe4');
replaceAll(&(u->input), "\\x03", '\x03');
@ -100,7 +105,7 @@ UnitTest *UnitTest::from_yajl_node(yajl_val &node) {
replaceAll(&(u->input), "\\xc9", '\xc9');
replaceAll(&(u->input), "\\x3b", '\x3b');
replaceAll(&(u->input), "\\xFF", '\xff');
replaceAll(&(u->input), "\\u0000", '\u0000');
replaceAll(&(u->input), "\\u0000", '\0');
} else if (strcmp(key, "name") == 0) {
u->name = YAJL_GET_STRING(val);
} else if (strcmp(key, "type") == 0) {
@ -108,9 +113,20 @@ UnitTest *UnitTest::from_yajl_node(yajl_val &node) {
} else if (strcmp(key, "ret") == 0) {
u->ret = YAJL_GET_INTEGER(val);
} else if (strcmp(key, "output") == 0) {
u->output = YAJL_GET_STRING(val);
replaceAll(&(u->output), "\\u0000", '\u0000');
replaceAll(&(u->output), "\\0", '\u0000');
u->output = std::string(YAJL_GET_STRING(val));
/*
* Converting \\u0000 to \0 due to the following gcc bug:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690
*
*/
replaceAll(&(u->output), "\\u0000", '\0');
replaceAll(&(u->output), "\\xe4", '\xe4');
replaceAll(&(u->output), "\\x03", '\x03');
replaceAll(&(u->output), "\\xbf", '\xbf');
replaceAll(&(u->output), "\\xc9", '\xc9');
replaceAll(&(u->output), "\\x3b", '\x3b');
replaceAll(&(u->output), "\\xFF", '\xff');
replaceAll(&(u->output), "\\0", '\0');
}
}