Adds support to urlDecodeUni transformation

This commit is contained in:
Felipe Zimmerle 2015-08-05 22:54:48 -03:00
parent 6dad6af4a9
commit 522f195aa0
7 changed files with 171 additions and 14 deletions

View File

@ -191,9 +191,10 @@ class Assay {
clock_t start;
int highest_severity;
Rules *m_rules;
private:
std::ofstream myfile;
Rules *m_rules;
ModSecurity *m_ms;
const char *m_clientIpAddress;

View File

@ -13,6 +13,9 @@
*
*/
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
#include <ctime>
#include <iostream>
@ -47,10 +50,20 @@ class Driver;
class Rules : public RulesProperties {
public:
Rules()
: RulesProperties(NULL) { }
: RulesProperties(NULL),
unicode_codepage(0) {
unicode_map_table = reinterpret_cast<int *>(
malloc(sizeof(int)*65536));
memset(unicode_map_table, -1, (sizeof(int)*65536));
}
explicit Rules(DebugLog *customLog)
: RulesProperties(customLog) { }
: unicode_codepage(0),
RulesProperties(customLog) {
unicode_map_table = reinterpret_cast<int *>(
malloc(sizeof(int)*65536));
memset(unicode_map_table, -1, (sizeof(int)*65536));
}
~Rules();
@ -76,6 +89,9 @@ class Rules : public RulesProperties {
DebugLog *debugLog;
int *unicode_map_table;
int64_t unicode_codepage;
private:
int m_referenceCount;
};

View File

@ -105,7 +105,7 @@ Transformation* Transformation::instantiate(std::string a) {
IF_MATCH(trim_left) { return new TrimLeft(a); }
IF_MATCH(trim_right) { return new TrimRight(a); }
IF_MATCH(url_decode) { return new UrlDecode(a); }
IF_MATCH(url_decode_uni) { return new UrlDecodeUni(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

@ -15,6 +15,8 @@
#include "actions/transformations/url_decode_uni.h"
#include <string.h>
#include <iostream>
#include <string>
#include <algorithm>
@ -24,26 +26,28 @@
#include "modsecurity/assay.h"
#include "actions/transformations/transformation.h"
#include "src/utils.h"
namespace ModSecurity {
namespace actions {
namespace transformations {
UrlDecodeUni::UrlDecodeUni(std::string action)
: Transformation(action) {
this->action_kind = 1;
}
std::string UrlDecodeUni::evaluate(std::string value,
Assay *assay) {
/**
* @todo Implement the transformation UrlDecodeUni
*/
assay->debug(4, "Transformation UrlDecodeUni is not implemented yet.");
return value;
int changed = 0;
char *tmp = strdup(value.c_str());
int res = urldecode_uni_nonstrict_inplace_ex(assay, (unsigned char *)tmp,
value.size(), &changed);
std::string ret("");
ret.assign(tmp);
free(tmp);
return ret;
}
} // namespace transformations
} // namespace actions
} // namespace ModSecurity

View File

@ -30,7 +30,9 @@ namespace transformations {
class UrlDecodeUni : public Transformation {
public:
explicit UrlDecodeUni(std::string action);
explicit UrlDecodeUni(std::string action)
: Transformation(action) { }
std::string evaluate(std::string exp,
Assay *assay) override;
};

View File

@ -824,5 +824,137 @@ std::string string_to_hex(const std::string& input) {
}
/**
*
* IMP1 Assumes NUL-terminated
*/
int urldecode_uni_nonstrict_inplace_ex(Assay *assay, unsigned char *input,
int64_t input_len, int *changed) {
unsigned char *d = input;
int64_t i, count, fact, j, xv;
int Code, hmap = -1;
*changed = 0;
if (input == NULL) return -1;
i = count = 0;
while (i < input_len) {
if (input[i] == '%') {
if ((i + 1 < input_len) &&
((input[i + 1] == 'u') || (input[i + 1] == 'U'))) {
/* Character is a percent sign. */
/* IIS-specific %u encoding. */
if (i + 5 < input_len) {
/* We have at least 4 data bytes. */
if ((VALID_HEX(input[i + 2])) &&
(VALID_HEX(input[i + 3])) &&
(VALID_HEX(input[i + 4])) &&
(VALID_HEX(input[i + 5]))) {
Code = 0;
fact = 1;
if (assay
&& assay->m_rules->unicode_map_table != NULL
&& assay->m_rules->unicode_codepage > 0) {
for (j = 5; j >= 2; j--) {
if (isxdigit((input[i+j]))) {
if (input[i+j] >= 97) {
xv = (input[i+j] - 97) + 10;
} else if (input[i+j] >= 65) {
xv = (input[i+j] - 65) + 10;
} else {
xv = (input[i+j]) - 48;
}
Code += (xv * fact);
fact *= 16;
}
}
if (Code >= 0 && Code <= 65535) {
hmap = assay->m_rules->unicode_map_table[Code];
}
}
if (hmap != -1) {
*d = hmap;
} else {
/* We first make use of the lower byte here,
* ignoring the higher byte. */
*d = x2c(&input[i + 4]);
/* Full width ASCII (ff01 - ff5e)
* needs 0x20 added */
if ((*d > 0x00) && (*d < 0x5f)
&& ((input[i + 2] == 'f')
|| (input[i + 2] == 'F'))
&& ((input[i + 3] == 'f')
|| (input[i + 3] == 'F'))) {
(*d) += 0x20;
}
}
d++;
count++;
i += 6;
*changed = 1;
} else {
/* Invalid data, skip %u. */
*d++ = input[i++];
*d++ = input[i++];
count += 2;
}
} else {
/* Not enough bytes (4 data bytes), skip %u. */
*d++ = input[i++];
*d++ = input[i++];
count += 2;
}
} else {
/* Standard URL encoding. */
/* Are there enough bytes available? */
if (i + 2 < input_len) {
/* Yes. */
/* Decode a %xx combo only if it is valid.
*/
char c1 = input[i + 1];
char c2 = input[i + 2];
if (VALID_HEX(c1) && VALID_HEX(c2)) {
*d++ = x2c(&input[i + 1]);
count++;
i += 3;
*changed = 1;
} else {
/* Not a valid encoding, skip this % */
*d++ = input[i++];
count++;
}
} else {
/* Not enough bytes available, skip this % */
*d++ = input[i++];
count++;
}
}
} else {
/* Character is not a percent sign. */
if (input[i] == '+') {
*d++ = ' ';
*changed = 1;
} else {
*d++ = input[i];
}
count++;
i++;
}
}
*d = '\0';
return count;
}
} // namespace ModSecurity

View File

@ -41,6 +41,8 @@ namespace ModSecurity {
int normalize_path_inplace(unsigned char *input, int input_len,
int win, int *changed);
std::string string_to_hex(const std::string& input);
int urldecode_uni_nonstrict_inplace_ex(Assay *assay, unsigned char *input,
int64_t input_len, int *changed);
} // namespace ModSecurity
#define SRC_UTILS_H_