Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-http-cookie.c
Line
Count
Source
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 "decode.h"
36
#include "detect.h"
37
38
#include "detect-parse.h"
39
#include "detect-engine.h"
40
#include "detect-engine-buffer.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
static int g_http2_thread_id = 0;
71
72
static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx,
73
        const DetectEngineTransforms *transforms,
74
        Flow *_f, const uint8_t _flow_flags,
75
        void *txv, const int list_id);
76
static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx,
77
        const DetectEngineTransforms *transforms,
78
        Flow *_f, const uint8_t _flow_flags,
79
        void *txv, const int list_id);
80
static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx,
81
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
82
        const int list_id);
83
static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx,
84
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
85
        const int list_id);
86
/**
87
 * \brief Registration function for keyword: http_cookie
88
 */
89
void DetectHttpCookieRegister(void)
90
12
{
91
    /* http_cookie content modifier */
92
12
    sigmatch_table[DETECT_HTTP_COOKIE_CM].name = "http_cookie";
93
12
    sigmatch_table[DETECT_HTTP_COOKIE_CM].desc =
94
12
            "content modifier to match only on the HTTP cookie-buffer";
95
12
    sigmatch_table[DETECT_HTTP_COOKIE_CM].url = "/rules/http-keywords.html#http-cookie";
96
12
    sigmatch_table[DETECT_HTTP_COOKIE_CM].Setup = DetectHttpCookieSetup;
97
#ifdef UNITTESTS
98
    sigmatch_table[DETECT_HTTP_COOKIE_CM].RegisterTests = DetectHttpCookieRegisterTests;
99
#endif
100
12
    sigmatch_table[DETECT_HTTP_COOKIE_CM].flags |= SIGMATCH_NOOPT;
101
12
    sigmatch_table[DETECT_HTTP_COOKIE_CM].flags |= SIGMATCH_INFO_CONTENT_MODIFIER;
102
12
    sigmatch_table[DETECT_HTTP_COOKIE_CM].alternative = DETECT_HTTP_COOKIE;
103
104
    /* http.cookie sticky buffer */
105
12
    sigmatch_table[DETECT_HTTP_COOKIE].name = "http.cookie";
106
12
    sigmatch_table[DETECT_HTTP_COOKIE].desc = "sticky buffer to match on the HTTP Cookie/Set-Cookie buffers";
107
12
    sigmatch_table[DETECT_HTTP_COOKIE].url = "/rules/http-keywords.html#http-cookie";
108
12
    sigmatch_table[DETECT_HTTP_COOKIE].Setup = DetectHttpCookieSetupSticky;
109
12
    sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_NOOPT;
110
12
    sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_INFO_STICKY_BUFFER;
111
112
12
    DetectAppLayerInspectEngineRegister("http_cookie", ALPROTO_HTTP1, SIG_FLAG_TOSERVER,
113
12
            HTP_REQUEST_PROGRESS_HEADERS, DetectEngineInspectBufferGeneric, GetRequestData);
114
12
    DetectAppLayerInspectEngineRegister("http_cookie", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT,
115
12
            HTP_REQUEST_PROGRESS_HEADERS, DetectEngineInspectBufferGeneric, GetResponseData);
116
117
12
    DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
118
12
            GetRequestData, ALPROTO_HTTP1, HTP_REQUEST_PROGRESS_HEADERS);
119
12
    DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
120
12
            GetResponseData, ALPROTO_HTTP1, HTP_REQUEST_PROGRESS_HEADERS);
121
122
12
    DetectAppLayerInspectEngineRegister("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
123
12
            HTTP2StateOpen, DetectEngineInspectBufferGeneric, GetRequestData2);
124
12
    DetectAppLayerInspectEngineRegister("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT,
125
12
            HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetResponseData2);
126
127
12
    DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
128
12
            GetRequestData2, ALPROTO_HTTP2, HTTP2StateOpen);
129
12
    DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
130
12
            GetResponseData2, ALPROTO_HTTP2, HTTP2StateDataServer);
131
132
12
    DetectBufferTypeSetDescriptionByName("http_cookie",
133
12
            "http cookie header");
134
135
12
    g_http2_thread_id = DetectRegisterThreadCtxGlobalFuncs(
136
12
            "http_cookie", SCHttp2ThreadBufDataInit, NULL, SCHttp2ThreadBufDataFree);
137
138
12
    g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie");
139
12
}
140
141
/**
142
 * \brief this function setups the http_cookie modifier keyword used in the rule
143
 *
144
 * \param de_ctx   Pointer to the Detection Engine Context
145
 * \param s        Pointer to the Signature to which the current keyword belongs
146
 * \param str      Should hold an empty string always
147
 *
148
 * \retval  0 On success
149
 * \retval -1 On failure
150
 */
151
152
static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
153
449
{
154
449
    return DetectEngineContentModifierBufferSetup(
155
449
            de_ctx, s, str, DETECT_HTTP_COOKIE_CM, g_http_cookie_buffer_id, ALPROTO_HTTP1);
156
449
}
157
158
/**
159
 * \brief this function setup the http.cookie keyword used in the rule
160
 *
161
 * \param de_ctx   Pointer to the Detection Engine Context
162
 * \param s        Pointer to the Signature to which the current keyword belongs
163
 * \param str      Should hold an empty string always
164
 *
165
 * \retval 0       On success
166
 */
167
static int DetectHttpCookieSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
168
4.72k
{
169
4.72k
    if (SCDetectBufferSetActiveList(de_ctx, s, g_http_cookie_buffer_id) < 0)
170
8
        return -1;
171
172
4.72k
    if (SCDetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
173
92
        return -1;
174
175
4.62k
    return 0;
176
4.72k
}
177
178
static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx,
179
        const DetectEngineTransforms *transforms, Flow *_f,
180
        const uint8_t _flow_flags, void *txv, const int list_id)
181
2.13k
{
182
2.13k
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
183
2.13k
    if (buffer->inspect == NULL) {
184
2.13k
        htp_tx_t *tx = (htp_tx_t *)txv;
185
186
2.13k
        if (htp_tx_request_headers(tx) == NULL)
187
0
            return NULL;
188
189
2.13k
        const htp_header_t *h = htp_tx_request_header(tx, "Cookie");
190
2.13k
        if (h == NULL || htp_header_value(h) == NULL) {
191
1.85k
            SCLogDebug("HTTP cookie header not present in this request");
192
1.85k
            return NULL;
193
1.85k
        }
194
195
278
        const uint32_t data_len = (uint32_t)htp_header_value_len(h);
196
278
        const uint8_t *data = htp_header_value_ptr(h);
197
198
278
        InspectionBufferSetupAndApplyTransforms(
199
278
                det_ctx, list_id, buffer, data, data_len, transforms);
200
278
    }
201
202
282
    return buffer;
203
2.13k
}
204
205
static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx,
206
        const DetectEngineTransforms *transforms, Flow *_f,
207
        const uint8_t _flow_flags, void *txv, const int list_id)
208
904
{
209
904
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
210
904
    if (buffer->inspect == NULL) {
211
904
        htp_tx_t *tx = (htp_tx_t *)txv;
212
213
904
        if (htp_tx_response_headers(tx) == NULL)
214
0
            return NULL;
215
216
904
        const htp_header_t *h = htp_tx_response_header(tx, "Set-Cookie");
217
904
        if (h == NULL || htp_header_value(h) == NULL) {
218
904
            SCLogDebug("HTTP cookie header not present in this request");
219
904
            return NULL;
220
904
        }
221
222
0
        const uint32_t data_len = (uint32_t)htp_header_value_len(h);
223
0
        const uint8_t *data = htp_header_value_ptr(h);
224
225
0
        InspectionBufferSetupAndApplyTransforms(
226
0
                det_ctx, list_id, buffer, data, data_len, transforms);
227
0
    }
228
229
0
    return buffer;
230
904
}
231
232
static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx,
233
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
234
        const int list_id)
235
113
{
236
113
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
237
113
    if (buffer->inspect == NULL) {
238
92
        uint32_t b_len = 0;
239
92
        const uint8_t *b = NULL;
240
241
92
        void *thread_buf = DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_http2_thread_id);
242
92
        if (thread_buf == NULL)
243
0
            return NULL;
244
92
        if (SCHttp2TxGetCookie(txv, STREAM_TOSERVER, &b, &b_len, thread_buf) != 1)
245
71
            return NULL;
246
21
        if (b == NULL || b_len == 0)
247
0
            return NULL;
248
249
21
        InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms);
250
21
    }
251
252
42
    return buffer;
253
113
}
254
255
static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx,
256
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
257
        const int list_id)
258
28
{
259
28
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
260
28
    if (buffer->inspect == NULL) {
261
28
        uint32_t b_len = 0;
262
28
        const uint8_t *b = NULL;
263
264
28
        void *thread_buf = DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_http2_thread_id);
265
28
        if (thread_buf == NULL)
266
0
            return NULL;
267
28
        if (SCHttp2TxGetCookie(txv, STREAM_TOCLIENT, &b, &b_len, thread_buf) != 1)
268
28
            return NULL;
269
0
        if (b == NULL || b_len == 0)
270
0
            return NULL;
271
272
0
        InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms);
273
0
    }
274
275
0
    return buffer;
276
28
}
277
278
/******************************** UNITESTS **********************************/
279
280
#ifdef UNITTESTS
281
#include "tests/detect-http-cookie.c"
282
#endif /* UNITTESTS */
283
284
/**
285
 * @}
286
 */