1 /*
2 * ModSecurity, http://www.modsecurity.org/
3 * Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4 *
5 * You may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * If any of the files related to licensing are missing or if you have any
11 * other questions related to licensing please contact Trustwave Holdings, Inc.
12 * directly using the email address security@modsecurity.org.
13 *
14 */
15
16 #include "src/operators/validate_url_encoding.h"
17
18 #include <string>
19
20 #include "src/operators/operator.h"
21
22 namespace modsecurity {
23 namespace operators {
24
25
validate_url_encoding(const char * input,uint64_t input_length,size_t * offset)26 int ValidateUrlEncoding::validate_url_encoding(const char *input,
27 uint64_t input_length, size_t *offset) {
28 int i;
29 *offset = 0;
30
31 if ((input == NULL) || (input_length == 0)) {
32 return -1;
33 }
34
35 i = 0;
36 while (i < input_length) {
37 if (input[i] == '%') {
38 if (i + 2 >= input_length) {
39 *offset = i;
40 /* Not enough bytes. */
41 return -3;
42 } else {
43 /* Here we only decode a %xx combination if it is valid,
44 * leaving it as is otherwise.
45 */
46 char c1 = input[i + 1];
47 char c2 = input[i + 2];
48
49 if ( (((c1 >= '0') && (c1 <= '9'))
50 || ((c1 >= 'a') && (c1 <= 'f'))
51 || ((c1 >= 'A') && (c1 <= 'F')))
52 && (((c2 >= '0') && (c2 <= '9'))
53 || ((c2 >= 'a') && (c2 <= 'f'))
54 || ((c2 >= 'A') && (c2 <= 'F'))) ) {
55 i += 3;
56 } else {
57 /* Non-hexadecimal characters used in encoding. */
58 *offset = i;
59 return -2;
60 }
61 }
62 } else {
63 i++;
64 }
65 }
66
67 return 1;
68 }
69
70
evaluate(Transaction * transaction,RuleWithActions * rule,const std::string & input,std::shared_ptr<RuleMessage> ruleMessage)71 bool ValidateUrlEncoding::evaluate(Transaction *transaction, RuleWithActions *rule,
72 const std::string &input, std::shared_ptr<RuleMessage> ruleMessage) {
73 size_t offset = 0;
74 bool res = false;
75
76 if (input.empty() == true) {
77 return res;
78 }
79
80 int rc = validate_url_encoding(input.c_str(), input.size(), &offset);
81 switch (rc) {
82 case 1 :
83 /* Encoding is valid */
84 if (transaction) {
85 ms_dbg_a(transaction, 7, "Valid URL Encoding at '" +input + "'");
86 }
87 res = false;
88 break;
89 case -2 :
90 if (transaction) {
91 ms_dbg_a(transaction, 7, "Invalid URL Encoding: Non-hexadecimal "
92 "digits used at '" + input + "'");
93 logOffset(ruleMessage, offset, input.size());
94 }
95 res = true; /* Invalid match. */
96 break;
97 case -3 :
98 if (transaction) {
99 ms_dbg_a(transaction, 7, "Invalid URL Encoding: Not enough " \
100 "characters at the end of input at '" + input + "'");
101 logOffset(ruleMessage, offset, input.size());
102 }
103 res = true; /* Invalid match. */
104 break;
105 case -1 :
106 default :
107 if (transaction) {
108 ms_dbg_a(transaction, 7, "Invalid URL Encoding: Internal " \
109 "Error (rc = " + std::to_string(rc) + ") at '" +
110 input + "'");
111 logOffset(ruleMessage, offset, input.size());
112 }
113 res = true;
114 break;
115 }
116
117 return res;
118 }
119
120
121 } // namespace operators
122 } // namespace modsecurity
123