1 /* Copyright (C) 2007-2018 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 Gurvinder Singh <gurvindersinghdahiya@gmail.com>
29 *
30 * Implements the http_cookie keyword
31 */
32
33 #include "suricata-common.h"
34 #include "threads.h"
35 #include "debug.h"
36 #include "decode.h"
37 #include "detect.h"
38
39 #include "detect-parse.h"
40 #include "detect-engine.h"
41 #include "detect-engine-mpm.h"
42 #include "detect-engine-prefilter.h"
43 #include "detect-content.h"
44 #include "detect-pcre.h"
45
46 #include "flow.h"
47 #include "flow-var.h"
48 #include "flow-util.h"
49
50 #include "util-debug.h"
51 #include "util-error.h"
52 #include "util-unittest.h"
53 #include "util-unittest-helper.h"
54 #include "util-spm.h"
55 #include "util-print.h"
56
57 #include "app-layer.h"
58 #include "app-layer-parser.h"
59
60 #include "app-layer-htp.h"
61 #include "detect-http-cookie.h"
62 #include "stream-tcp.h"
63
64 static int DetectHttpCookieSetup (DetectEngineCtx *, Signature *, const char *);
65 static int DetectHttpCookieSetupSticky (DetectEngineCtx *, Signature *, const char *);
66 #ifdef UNITTESTS
67 static void DetectHttpCookieRegisterTests(void);
68 #endif
69 static int g_http_cookie_buffer_id = 0;
70
71 static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx,
72 const DetectEngineTransforms *transforms,
73 Flow *_f, const uint8_t _flow_flags,
74 void *txv, const int list_id);
75 static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx,
76 const DetectEngineTransforms *transforms,
77 Flow *_f, const uint8_t _flow_flags,
78 void *txv, const int list_id);
79 static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx,
80 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
81 const int list_id);
82 static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx,
83 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
84 const int list_id);
85 /**
86 * \brief Registration function for keyword: http_cookie
87 */
DetectHttpCookieRegister(void)88 void DetectHttpCookieRegister(void)
89 {
90 /* http_cookie content modifier */
91 sigmatch_table[DETECT_AL_HTTP_COOKIE].name = "http_cookie";
92 sigmatch_table[DETECT_AL_HTTP_COOKIE].desc = "content modifier to match only on the HTTP cookie-buffer";
93 sigmatch_table[DETECT_AL_HTTP_COOKIE].url = "/rules/http-keywords.html#http-cookie";
94 sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup;
95 #ifdef UNITTESTS
96 sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests;
97 #endif
98 sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_NOOPT;
99 sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_INFO_CONTENT_MODIFIER;
100 sigmatch_table[DETECT_AL_HTTP_COOKIE].alternative = DETECT_HTTP_COOKIE;
101
102 /* http.cookie sticky buffer */
103 sigmatch_table[DETECT_HTTP_COOKIE].name = "http.cookie";
104 sigmatch_table[DETECT_HTTP_COOKIE].desc = "sticky buffer to match on the HTTP Cookie/Set-Cookie buffers";
105 sigmatch_table[DETECT_HTTP_COOKIE].url = "/rules/http-keywords.html#http-cookie";
106 sigmatch_table[DETECT_HTTP_COOKIE].Setup = DetectHttpCookieSetupSticky;
107 sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_NOOPT;
108 sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_INFO_STICKY_BUFFER;
109
110 DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP,
111 SIG_FLAG_TOSERVER, HTP_REQUEST_HEADERS,
112 DetectEngineInspectBufferGeneric, GetRequestData);
113 DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP,
114 SIG_FLAG_TOCLIENT, HTP_REQUEST_HEADERS,
115 DetectEngineInspectBufferGeneric, GetResponseData);
116
117 DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOSERVER, 2,
118 PrefilterGenericMpmRegister, GetRequestData, ALPROTO_HTTP,
119 HTP_REQUEST_HEADERS);
120 DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOCLIENT, 2,
121 PrefilterGenericMpmRegister, GetResponseData, ALPROTO_HTTP,
122 HTP_REQUEST_HEADERS);
123
124 DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
125 HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRequestData2);
126 DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT,
127 HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetResponseData2);
128
129 DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
130 GetRequestData2, ALPROTO_HTTP2, HTTP2StateDataClient);
131 DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
132 GetResponseData2, ALPROTO_HTTP2, HTTP2StateDataServer);
133
134 DetectBufferTypeSetDescriptionByName("http_cookie",
135 "http cookie header");
136
137 g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie");
138 }
139
140 /**
141 * \brief this function setups the http_cookie modifier 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 * \retval -1 On failure
149 */
150
DetectHttpCookieSetup(DetectEngineCtx * de_ctx,Signature * s,const char * str)151 static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
152 {
153 return DetectEngineContentModifierBufferSetup(de_ctx, s, str,
154 DETECT_AL_HTTP_COOKIE,
155 g_http_cookie_buffer_id,
156 ALPROTO_HTTP);
157 }
158
159 /**
160 * \brief this function setup the http.user_agent keyword used in the rule
161 *
162 * \param de_ctx Pointer to the Detection Engine Context
163 * \param s Pointer to the Signature to which the current keyword belongs
164 * \param str Should hold an empty string always
165 *
166 * \retval 0 On success
167 */
DetectHttpCookieSetupSticky(DetectEngineCtx * de_ctx,Signature * s,const char * str)168 static int DetectHttpCookieSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
169 {
170 if (DetectBufferSetActiveList(s, g_http_cookie_buffer_id) < 0)
171 return -1;
172
173 if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
174 return -1;
175
176 return 0;
177 }
178
GetRequestData(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)179 static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx,
180 const DetectEngineTransforms *transforms, Flow *_f,
181 const uint8_t _flow_flags, void *txv, const int list_id)
182 {
183 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
184 if (buffer->inspect == NULL) {
185 htp_tx_t *tx = (htp_tx_t *)txv;
186
187 if (tx->request_headers == NULL)
188 return NULL;
189
190 htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers,
191 "Cookie");
192 if (h == NULL || h->value == NULL) {
193 SCLogDebug("HTTP cookie header not present in this request");
194 return NULL;
195 }
196
197 const uint32_t data_len = bstr_len(h->value);
198 const uint8_t *data = bstr_ptr(h->value);
199
200 InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
201 InspectionBufferApplyTransforms(buffer, transforms);
202 }
203
204 return buffer;
205 }
206
GetResponseData(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)207 static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx,
208 const DetectEngineTransforms *transforms, Flow *_f,
209 const uint8_t _flow_flags, void *txv, const int list_id)
210 {
211 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
212 if (buffer->inspect == NULL) {
213 htp_tx_t *tx = (htp_tx_t *)txv;
214
215 if (tx->response_headers == NULL)
216 return NULL;
217
218 htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers,
219 "Set-Cookie");
220 if (h == NULL || h->value == NULL) {
221 SCLogDebug("HTTP cookie header not present in this request");
222 return NULL;
223 }
224
225 const uint32_t data_len = bstr_len(h->value);
226 const uint8_t *data = bstr_ptr(h->value);
227
228 InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
229 InspectionBufferApplyTransforms(buffer, transforms);
230 }
231
232 return buffer;
233 }
234
GetRequestData2(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)235 static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx,
236 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
237 const int list_id)
238 {
239 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
240 if (buffer->inspect == NULL) {
241 uint32_t b_len = 0;
242 const uint8_t *b = NULL;
243
244 if (rs_http2_tx_get_cookie(txv, STREAM_TOSERVER, &b, &b_len) != 1)
245 return NULL;
246 if (b == NULL || b_len == 0)
247 return NULL;
248
249 InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
250 InspectionBufferApplyTransforms(buffer, transforms);
251 }
252
253 return buffer;
254 }
255
GetResponseData2(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)256 static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx,
257 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
258 const int list_id)
259 {
260 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
261 if (buffer->inspect == NULL) {
262 uint32_t b_len = 0;
263 const uint8_t *b = NULL;
264
265 if (rs_http2_tx_get_cookie(txv, STREAM_TOCLIENT, &b, &b_len) != 1)
266 return NULL;
267 if (b == NULL || b_len == 0)
268 return NULL;
269
270 InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
271 InspectionBufferApplyTransforms(buffer, transforms);
272 }
273
274 return buffer;
275 }
276
277 /******************************** UNITESTS **********************************/
278
279 #ifdef UNITTESTS
280 #include "tests/detect-http-cookie.c"
281 #endif /* UNITTESTS */
282
283 /**
284 * @}
285 */
286