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