Coverage Report

Created: 2025-11-16 07:09

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