/src/suricata7/src/detect-http-method.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2007-2019 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 | | * \ingroup httplayer |
20 | | * |
21 | | * @{ |
22 | | */ |
23 | | |
24 | | |
25 | | /** |
26 | | * \file |
27 | | * |
28 | | * \author Brian Rectanus <brectanu@gmail.com> |
29 | | * |
30 | | * Implements the http_method keyword |
31 | | */ |
32 | | |
33 | | #include "suricata-common.h" |
34 | | #include "threads.h" |
35 | | #include "decode.h" |
36 | | #include "detect.h" |
37 | | |
38 | | #include "detect-parse.h" |
39 | | #include "detect-engine.h" |
40 | | #include "detect-engine-mpm.h" |
41 | | #include "detect-engine-prefilter.h" |
42 | | #include "detect-content.h" |
43 | | #include "detect-pcre.h" |
44 | | |
45 | | #include "flow.h" |
46 | | #include "flow-var.h" |
47 | | #include "flow-util.h" |
48 | | |
49 | | #include "util-debug.h" |
50 | | #include "util-unittest.h" |
51 | | #include "util-unittest-helper.h" |
52 | | #include "util-spm.h" |
53 | | |
54 | | #include "app-layer.h" |
55 | | #include "app-layer-parser.h" |
56 | | |
57 | | #include "app-layer-htp.h" |
58 | | #include "detect-http-method.h" |
59 | | #include "stream-tcp.h" |
60 | | |
61 | | static int g_http_method_buffer_id = 0; |
62 | | static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, const char *); |
63 | | static int DetectHttpMethodSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); |
64 | | #ifdef UNITTESTS |
65 | | void DetectHttpMethodRegisterTests(void); |
66 | | #endif |
67 | | void DetectHttpMethodFree(void *); |
68 | | static bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror); |
69 | | static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, |
70 | | const DetectEngineTransforms *transforms, Flow *_f, |
71 | | const uint8_t _flow_flags, void *txv, const int list_id); |
72 | | static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, |
73 | | const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, |
74 | | const int list_id); |
75 | | |
76 | | /** |
77 | | * \brief Registration function for keyword: http_method |
78 | | */ |
79 | | void DetectHttpMethodRegister(void) |
80 | 73 | { |
81 | | /* http_method content modifier */ |
82 | 73 | sigmatch_table[DETECT_AL_HTTP_METHOD].name = "http_method"; |
83 | 73 | sigmatch_table[DETECT_AL_HTTP_METHOD].desc = "content modifier to match only on the HTTP method-buffer"; |
84 | 73 | sigmatch_table[DETECT_AL_HTTP_METHOD].url = "/rules/http-keywords.html#http-method"; |
85 | 73 | sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; |
86 | 73 | sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; |
87 | | #ifdef UNITTESTS |
88 | | sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; |
89 | | #endif |
90 | 73 | sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; |
91 | 73 | sigmatch_table[DETECT_AL_HTTP_METHOD].alternative = DETECT_HTTP_METHOD; |
92 | | |
93 | | /* http.method sticky buffer */ |
94 | 73 | sigmatch_table[DETECT_HTTP_METHOD].name = "http.method"; |
95 | 73 | sigmatch_table[DETECT_HTTP_METHOD].desc = "sticky buffer to match specifically and only on the HTTP method buffer"; |
96 | 73 | sigmatch_table[DETECT_HTTP_METHOD].url = "/rules/http-keywords.html#http-method"; |
97 | 73 | sigmatch_table[DETECT_HTTP_METHOD].Setup = DetectHttpMethodSetupSticky; |
98 | 73 | sigmatch_table[DETECT_HTTP_METHOD].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; |
99 | | |
100 | 73 | DetectAppLayerInspectEngineRegister2("http_method", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, |
101 | 73 | HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); |
102 | | |
103 | 73 | DetectAppLayerMpmRegister2("http_method", SIG_FLAG_TOSERVER, 4, PrefilterGenericMpmRegister, |
104 | 73 | GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); |
105 | | |
106 | 73 | DetectAppLayerInspectEngineRegister2("http_method", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, |
107 | 73 | HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); |
108 | | |
109 | 73 | DetectAppLayerMpmRegister2("http_method", SIG_FLAG_TOSERVER, 4, PrefilterGenericMpmRegister, |
110 | 73 | GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); |
111 | | |
112 | 73 | DetectBufferTypeSetDescriptionByName("http_method", |
113 | 73 | "http request method"); |
114 | | |
115 | 73 | DetectBufferTypeRegisterValidateCallback("http_method", |
116 | 73 | DetectHttpMethodValidateCallback); |
117 | | |
118 | 73 | g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); |
119 | | |
120 | 73 | SCLogDebug("registering http_method rule option"); |
121 | 73 | } |
122 | | |
123 | | /** |
124 | | * \brief This function is used to add the parsed "http_method" option |
125 | | * into the current signature. |
126 | | * |
127 | | * \param de_ctx Pointer to the Detection Engine Context. |
128 | | * \param s Pointer to the Current Signature. |
129 | | * \param str Pointer to the user provided option string. |
130 | | * |
131 | | * \retval 0 on Success. |
132 | | * \retval -1 on Failure. |
133 | | */ |
134 | | static int DetectHttpMethodSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) |
135 | 2.04k | { |
136 | 2.04k | return DetectEngineContentModifierBufferSetup( |
137 | 2.04k | de_ctx, s, str, DETECT_AL_HTTP_METHOD, g_http_method_buffer_id, ALPROTO_HTTP1); |
138 | 2.04k | } |
139 | | |
140 | | /** |
141 | | * \brief this function setup the http.method keyword used in the rule |
142 | | * |
143 | | * \param de_ctx Pointer to the Detection Engine Context |
144 | | * \param s Pointer to the Signature to which the current keyword belongs |
145 | | * \param str Should hold an empty string always |
146 | | * |
147 | | * \retval 0 On success |
148 | | */ |
149 | | static int DetectHttpMethodSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) |
150 | 22.3k | { |
151 | 22.3k | if (DetectBufferSetActiveList(de_ctx, s, g_http_method_buffer_id) < 0) |
152 | 14 | return -1; |
153 | | |
154 | 22.2k | if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) |
155 | 99 | return -1; |
156 | | |
157 | 22.1k | return 0; |
158 | 22.2k | } |
159 | | |
160 | | /** |
161 | | * \retval 1 valid |
162 | | * \retval 0 invalid |
163 | | */ |
164 | | static bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror) |
165 | 101k | { |
166 | 205k | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
167 | 104k | if (s->init_data->buffers[x].id != (uint32_t)g_http_method_buffer_id) |
168 | 3.44k | continue; |
169 | 101k | const SigMatch *sm = s->init_data->buffers[x].head; |
170 | 207k | for (; sm != NULL; sm = sm->next) { |
171 | 106k | if (sm->type != DETECT_CONTENT) |
172 | 87.5k | continue; |
173 | 19.4k | const DetectContentData *cd = (const DetectContentData *)sm->ctx; |
174 | 19.4k | if (cd->content && cd->content_len) { |
175 | 19.4k | if (cd->content[cd->content_len - 1] == 0x20) { |
176 | 482 | *sigerror = "http_method pattern with trailing space"; |
177 | 482 | SCLogError("%s", *sigerror); |
178 | 482 | return false; |
179 | 18.9k | } else if (cd->content[0] == 0x20) { |
180 | 102 | *sigerror = "http_method pattern with leading space"; |
181 | 102 | SCLogError("%s", *sigerror); |
182 | 102 | return false; |
183 | 18.8k | } else if (cd->content[cd->content_len - 1] == 0x09) { |
184 | 30 | *sigerror = "http_method pattern with trailing tab"; |
185 | 30 | SCLogError("%s", *sigerror); |
186 | 30 | return false; |
187 | 18.8k | } else if (cd->content[0] == 0x09) { |
188 | 210 | *sigerror = "http_method pattern with leading tab"; |
189 | 210 | SCLogError("%s", *sigerror); |
190 | 210 | return false; |
191 | 210 | } |
192 | 19.4k | } |
193 | 19.4k | } |
194 | 101k | } |
195 | 100k | return true; |
196 | 101k | } |
197 | | |
198 | | static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, |
199 | | const DetectEngineTransforms *transforms, Flow *_f, |
200 | | const uint8_t _flow_flags, void *txv, const int list_id) |
201 | 835 | { |
202 | 835 | InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); |
203 | 835 | if (buffer->inspect == NULL) { |
204 | 506 | htp_tx_t *tx = (htp_tx_t *)txv; |
205 | | |
206 | 506 | if (tx->request_method == NULL) |
207 | 117 | return NULL; |
208 | | |
209 | 389 | const uint32_t data_len = bstr_len(tx->request_method); |
210 | 389 | const uint8_t *data = bstr_ptr(tx->request_method); |
211 | | |
212 | 389 | InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); |
213 | 389 | InspectionBufferApplyTransforms(buffer, transforms); |
214 | 389 | } |
215 | | |
216 | 718 | return buffer; |
217 | 835 | } |
218 | | |
219 | | static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, |
220 | | const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, |
221 | | const int list_id) |
222 | 899 | { |
223 | 899 | InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); |
224 | 899 | if (buffer->inspect == NULL) { |
225 | 852 | uint32_t b_len = 0; |
226 | 852 | const uint8_t *b = NULL; |
227 | | |
228 | 852 | if (rs_http2_tx_get_method(txv, &b, &b_len) != 1) |
229 | 552 | return NULL; |
230 | 300 | if (b == NULL || b_len == 0) |
231 | 0 | return NULL; |
232 | | |
233 | 300 | InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); |
234 | 300 | InspectionBufferApplyTransforms(buffer, transforms); |
235 | 300 | } |
236 | | |
237 | 347 | return buffer; |
238 | 899 | } |
239 | | |
240 | | #ifdef UNITTESTS |
241 | | #include "tests/detect-http-method.c" |
242 | | #endif |
243 | | |
244 | | /** |
245 | | * @} |
246 | | */ |