/src/suricata7/src/detect-transform-urldecode.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2020 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Philippe Antoine <p.antoine@catenacyber.fr> |
22 | | * |
23 | | * Implements the url_decode transform keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | |
28 | | #include "detect.h" |
29 | | #include "detect-engine.h" |
30 | | #include "detect-engine-prefilter.h" |
31 | | #include "detect-engine-build.h" |
32 | | #include "detect-parse.h" |
33 | | #include "detect-transform-urldecode.h" |
34 | | |
35 | | #include "util-unittest.h" |
36 | | #include "util-print.h" |
37 | | |
38 | | static int DetectTransformUrlDecodeSetup (DetectEngineCtx *, Signature *, const char *); |
39 | | #ifdef UNITTESTS |
40 | | static void DetectTransformUrlDecodeRegisterTests(void); |
41 | | #endif |
42 | | |
43 | | static void TransformUrlDecode(InspectionBuffer *buffer, void *options); |
44 | | |
45 | | void DetectTransformUrlDecodeRegister(void) |
46 | 34 | { |
47 | 34 | sigmatch_table[DETECT_TRANSFORM_URL_DECODE].name = "url_decode"; |
48 | 34 | sigmatch_table[DETECT_TRANSFORM_URL_DECODE].desc = |
49 | 34 | "modify buffer to decode urlencoded data before inspection"; |
50 | 34 | sigmatch_table[DETECT_TRANSFORM_URL_DECODE].url = "/rules/transforms.html#url-decode"; |
51 | 34 | sigmatch_table[DETECT_TRANSFORM_URL_DECODE].Transform = |
52 | 34 | TransformUrlDecode; |
53 | 34 | sigmatch_table[DETECT_TRANSFORM_URL_DECODE].Setup = |
54 | 34 | DetectTransformUrlDecodeSetup; |
55 | | #ifdef UNITTESTS |
56 | | sigmatch_table[DETECT_TRANSFORM_URL_DECODE].RegisterTests = |
57 | | DetectTransformUrlDecodeRegisterTests; |
58 | | #endif |
59 | | |
60 | 34 | sigmatch_table[DETECT_TRANSFORM_URL_DECODE].flags |= SIGMATCH_NOOPT; |
61 | 34 | } |
62 | | |
63 | | /** |
64 | | * \internal |
65 | | * \brief Apply the transform keyword to the last pattern match |
66 | | * \param det_ctx detection engine ctx |
67 | | * \param s signature |
68 | | * \param nullstr should be null |
69 | | * \retval 0 ok |
70 | | * \retval -1 failure |
71 | | */ |
72 | | static int DetectTransformUrlDecodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) |
73 | 695 | { |
74 | 695 | SCEnter(); |
75 | 695 | int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_URL_DECODE, NULL); |
76 | 695 | SCReturnInt(r); |
77 | 695 | } |
78 | | |
79 | | // util function so as to ease reuse sometimes |
80 | | static bool BufferUrlDecode(const uint8_t *input, const uint32_t input_len, uint8_t *output, uint32_t *output_size) |
81 | 47 | { |
82 | 47 | bool changed = false; |
83 | 47 | uint8_t *oi = output; |
84 | | //PrintRawDataFp(stdout, input, input_len); |
85 | 22.8k | for (uint32_t i = 0; i < input_len; i++) { |
86 | 22.7k | if (input[i] == '%') { |
87 | 7 | if (i + 2 < input_len) { |
88 | 7 | if ((isxdigit(input[i+1])) && (isxdigit(input[i+2]))) { |
89 | | // Decode %HH encoding. |
90 | 0 | *oi = (uint8_t)((input[i + 1] >= 'A' ? ((input[i + 1] & 0xdf) - 'A') + 10 |
91 | 0 | : (input[i + 1] - '0')) |
92 | 0 | << 4); |
93 | 0 | *oi |= (input[i+2] >= 'A' ? ((input[i+2] & 0xdf) - 'A') + 10 : (input[i+2] - '0')); |
94 | 0 | oi++; |
95 | | // one more increment before looping |
96 | 0 | i += 2; |
97 | 0 | changed = true; |
98 | 7 | } else { |
99 | | // leaves incorrect percent |
100 | | // does not handle unicode %u encoding |
101 | 7 | *oi++ = input[i]; |
102 | 7 | } |
103 | 7 | } else { |
104 | | // leaves trailing incomplete percent |
105 | 0 | *oi++ = input[i]; |
106 | 0 | } |
107 | 22.7k | } else if (input[i] == '+') { |
108 | 21 | *oi++ = ' '; |
109 | 21 | changed = true; |
110 | 22.7k | } else { |
111 | 22.7k | *oi++ = input[i]; |
112 | 22.7k | } |
113 | 22.7k | } |
114 | 47 | *output_size = oi - output; |
115 | 47 | return changed; |
116 | 47 | } |
117 | | |
118 | | static void TransformUrlDecode(InspectionBuffer *buffer, void *options) |
119 | 47 | { |
120 | 47 | uint32_t output_size; |
121 | 47 | bool changed; |
122 | | |
123 | 47 | const uint8_t *input = buffer->inspect; |
124 | 47 | const uint32_t input_len = buffer->inspect_len; |
125 | 47 | if (input_len == 0) { |
126 | 0 | return; |
127 | 0 | } |
128 | | // we can only shrink |
129 | 47 | uint8_t *output = InspectionBufferCheckAndExpand(buffer, input_len); |
130 | 47 | if (output == NULL) { |
131 | 0 | return; |
132 | 0 | } |
133 | | |
134 | 47 | changed = BufferUrlDecode(input, input_len, output, &output_size); |
135 | | |
136 | 47 | if (changed) { |
137 | 3 | InspectionBufferTruncate(buffer, output_size); |
138 | 3 | } |
139 | 47 | } |
140 | | |
141 | | #ifdef UNITTESTS |
142 | | static int DetectTransformUrlDecodeTest01(void) |
143 | | { |
144 | | const uint8_t *input = (const uint8_t *)"Suricata%20is+%27%61wesome%21%27%25%30%30%ZZ%4"; |
145 | | uint32_t input_len = strlen((char *)input); |
146 | | |
147 | | InspectionBuffer buffer; |
148 | | InspectionBufferInit(&buffer, 8); |
149 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
150 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
151 | | TransformUrlDecode(&buffer, NULL); |
152 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
153 | | FAIL_IF (buffer.inspect_len != strlen("Suricata is 'awesome!'%00%ZZ%4")); |
154 | | FAIL_IF (memcmp(buffer.inspect, "Suricata is 'awesome!'%00%ZZ%4", buffer.inspect_len) != 0); |
155 | | InspectionBufferFree(&buffer); |
156 | | PASS; |
157 | | } |
158 | | |
159 | | static int DetectTransformUrlDecodeTest02(void) |
160 | | { |
161 | | const char rule[] = "alert http any any -> any any (http.request_body; url_decode; content:\"mail=test@oisf.net\"; sid:1;)"; |
162 | | ThreadVars th_v; |
163 | | DetectEngineThreadCtx *det_ctx = NULL; |
164 | | memset(&th_v, 0, sizeof(th_v)); |
165 | | |
166 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
167 | | FAIL_IF_NULL(de_ctx); |
168 | | Signature *s = DetectEngineAppendSig(de_ctx, rule); |
169 | | FAIL_IF_NULL(s); |
170 | | SigGroupBuild(de_ctx); |
171 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
172 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
173 | | DetectEngineCtxFree(de_ctx); |
174 | | PASS; |
175 | | } |
176 | | |
177 | | static void DetectTransformUrlDecodeRegisterTests(void) |
178 | | { |
179 | | UtRegisterTest("DetectTransformUrlDecodeTest01", |
180 | | DetectTransformUrlDecodeTest01); |
181 | | UtRegisterTest("DetectTransformUrlDecodeTest02", |
182 | | DetectTransformUrlDecodeTest02); |
183 | | } |
184 | | #endif |