Coverage Report

Created: 2026-06-07 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-http-uri.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 Gerardo Iglesias  <iglesiasg@gmail.com>
29
 * \author Victor Julien <victor@inliniac.net>
30
 */
31
32
#include "suricata-common.h"
33
#include "threads.h"
34
#include "decode.h"
35
#include "detect.h"
36
37
#include "detect-parse.h"
38
#include "detect-engine.h"
39
#include "detect-engine-mpm.h"
40
#include "detect-engine-prefilter.h"
41
#include "detect-content.h"
42
#include "detect-pcre.h"
43
#include "detect-urilen.h"
44
45
#include "flow.h"
46
#include "flow-var.h"
47
48
#include "util-debug.h"
49
#include "util-unittest.h"
50
#include "util-spm.h"
51
#include "util-print.h"
52
53
#include "app-layer.h"
54
55
#include "app-layer-htp.h"
56
#include "detect-http-uri.h"
57
#include "stream-tcp.h"
58
59
#ifdef UNITTESTS
60
static void DetectHttpUriRegisterTests(void);
61
#endif
62
static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx,
63
                                       Signature *s);
64
static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror);
65
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
66
        const DetectEngineTransforms *transforms,
67
        Flow *_f, const uint8_t _flow_flags,
68
        void *txv, const int list_id);
69
static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx,
70
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
71
        const int list_id);
72
static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
73
static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, const char *);
74
static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx,
75
                                          Signature *s);
76
static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **);
77
static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx,
78
        const DetectEngineTransforms *transforms,
79
        Flow *_f, const uint8_t _flow_flags,
80
        void *txv, const int list_id);
81
static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
82
83
static int g_http_raw_uri_buffer_id = 0;
84
static int g_http_uri_buffer_id = 0;
85
86
/**
87
 * \brief Registration function for keywords: http_uri and http.uri
88
 */
89
void DetectHttpUriRegister (void)
90
75
{
91
    /* http_uri content modifier */
92
75
    sigmatch_table[DETECT_AL_HTTP_URI].name = "http_uri";
93
75
    sigmatch_table[DETECT_AL_HTTP_URI].desc = "content modifier to match specifically and only on the HTTP uri-buffer";
94
75
    sigmatch_table[DETECT_AL_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw";
95
75
    sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup;
96
#ifdef UNITTESTS
97
    sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests;
98
#endif
99
75
    sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER;
100
75
    sigmatch_table[DETECT_AL_HTTP_URI].alternative = DETECT_HTTP_URI;
101
102
    /* http.uri sticky buffer */
103
75
    sigmatch_table[DETECT_HTTP_URI].name = "http.uri";
104
75
    sigmatch_table[DETECT_HTTP_URI].alias = "http.uri.normalized";
105
75
    sigmatch_table[DETECT_HTTP_URI].desc = "sticky buffer to match specifically and only on the normalized HTTP URI buffer";
106
75
    sigmatch_table[DETECT_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw";
107
75
    sigmatch_table[DETECT_HTTP_URI].Setup = DetectHttpUriSetupSticky;
108
75
    sigmatch_table[DETECT_HTTP_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER;
109
110
75
    DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER,
111
75
            HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData);
112
113
75
    DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
114
75
            GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE);
115
116
75
    DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
117
75
            HTTP2StateOpen, DetectEngineInspectBufferGeneric, GetData2);
118
119
75
    DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
120
75
            GetData2, ALPROTO_HTTP2, HTTP2StateOpen);
121
122
75
    DetectBufferTypeSetDescriptionByName("http_uri",
123
75
            "http request uri");
124
125
75
    DetectBufferTypeRegisterSetupCallback("http_uri",
126
75
            DetectHttpUriSetupCallback);
127
128
75
    DetectBufferTypeRegisterValidateCallback("http_uri",
129
75
            DetectHttpUriValidateCallback);
130
131
75
    g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri");
132
133
    /* http_raw_uri content modifier */
134
75
    sigmatch_table[DETECT_AL_HTTP_RAW_URI].name = "http_raw_uri";
135
75
    sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on the raw HTTP uri";
136
75
    sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = "/rules/http-keywords.html#http_uri-and-http_raw-uri";
137
75
    sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup;
138
75
    sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER;
139
75
    sigmatch_table[DETECT_AL_HTTP_RAW_URI].alternative = DETECT_HTTP_URI_RAW;
140
141
    /* http.uri.raw sticky buffer */
142
75
    sigmatch_table[DETECT_HTTP_URI_RAW].name = "http.uri.raw";
143
75
    sigmatch_table[DETECT_HTTP_URI_RAW].desc = "sticky buffer to match specifically and only on the raw HTTP URI buffer";
144
75
    sigmatch_table[DETECT_HTTP_URI_RAW].url = "/rules/http-keywords.html#http-uri-and-http-raw-uri";
145
75
    sigmatch_table[DETECT_HTTP_URI_RAW].Setup = DetectHttpRawUriSetupSticky;
146
75
    sigmatch_table[DETECT_HTTP_URI_RAW].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER;
147
148
75
    DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER,
149
75
            HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetRawData);
150
151
75
    DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
152
75
            GetRawData, ALPROTO_HTTP1, HTP_REQUEST_LINE);
153
154
    // no difference between raw and decoded uri for HTTP2
155
75
    DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
156
75
            HTTP2StateOpen, DetectEngineInspectBufferGeneric, GetData2);
157
158
75
    DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
159
75
            GetData2, ALPROTO_HTTP2, HTTP2StateOpen);
160
161
75
    DetectBufferTypeSetDescriptionByName("http_raw_uri",
162
75
            "raw http uri");
163
164
75
    DetectBufferTypeRegisterSetupCallback("http_raw_uri",
165
75
            DetectHttpRawUriSetupCallback);
166
167
75
    DetectBufferTypeRegisterValidateCallback("http_raw_uri",
168
75
            DetectHttpRawUriValidateCallback);
169
170
75
    g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri");
171
75
}
172
173
/**
174
 * \brief this function setups the http_uri modifier keyword used in the rule
175
 *
176
 * \param de_ctx   Pointer to the Detection Engine Context
177
 * \param s        Pointer to the Signature to which the current keyword belongs
178
 * \param str      Should hold an empty string always
179
 *
180
 * \retval  0 On success
181
 * \retval -1 On failure
182
 */
183
184
int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
185
36.3k
{
186
36.3k
    return DetectEngineContentModifierBufferSetup(
187
36.3k
            de_ctx, s, str, DETECT_AL_HTTP_URI, g_http_uri_buffer_id, ALPROTO_HTTP1);
188
36.3k
}
189
190
static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror)
191
45.7k
{
192
45.7k
    return DetectUrilenValidateContent(s, g_http_uri_buffer_id, sigerror);
193
45.7k
}
194
195
static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx,
196
                                       Signature *s)
197
82.1k
{
198
82.1k
    SCLogDebug("callback invoked by %u", s->id);
199
82.1k
    DetectUrilenApplyToContent(s, g_http_uri_buffer_id);
200
82.1k
}
201
202
/**
203
 * \brief this function setup the http.uri keyword used in the rule
204
 *
205
 * \param de_ctx   Pointer to the Detection Engine Context
206
 * \param s        Pointer to the Signature to which the current keyword belongs
207
 * \param str      Should hold an empty string always
208
 *
209
 * \retval 0       On success
210
 */
211
static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
212
63.5k
{
213
63.5k
    if (DetectBufferSetActiveList(de_ctx, s, g_http_uri_buffer_id) < 0)
214
603
        return -1;
215
62.9k
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
216
4.66k
        return -1;
217
58.2k
    return 0;
218
62.9k
}
219
220
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
221
        const DetectEngineTransforms *transforms, Flow *_f,
222
        const uint8_t _flow_flags, void *txv, const int list_id)
223
2.13k
{
224
2.13k
    SCEnter();
225
226
2.13k
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
227
2.13k
    if (!buffer->initialized) {
228
1.95k
        htp_tx_t *tx = (htp_tx_t *)txv;
229
1.95k
        HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
230
231
1.95k
        if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) {
232
849
            SCLogDebug("no tx_id or uri");
233
849
            return NULL;
234
849
        }
235
236
1.10k
        const uint32_t data_len = bstr_len(tx_ud->request_uri_normalized);
237
1.10k
        const uint8_t *data = bstr_ptr(tx_ud->request_uri_normalized);
238
239
1.10k
        InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
240
1.10k
        InspectionBufferApplyTransforms(buffer, transforms);
241
1.10k
    }
242
243
1.28k
    return buffer;
244
2.13k
}
245
246
static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx,
247
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
248
        const int list_id)
249
2.63k
{
250
2.63k
    SCEnter();
251
252
2.63k
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
253
2.63k
    if (!buffer->initialized) {
254
2.38k
        uint32_t b_len = 0;
255
2.38k
        const uint8_t *b = NULL;
256
257
2.38k
        if (rs_http2_tx_get_uri(txv, &b, &b_len) != 1)
258
1.56k
            return NULL;
259
821
        if (b == NULL || b_len == 0)
260
1
            return NULL;
261
262
820
        InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
263
820
        InspectionBufferApplyTransforms(buffer, transforms);
264
820
    }
265
266
1.07k
    return buffer;
267
2.63k
}
268
269
/**
270
 * \brief Sets up the http_raw_uri modifier keyword.
271
 *
272
 * \param de_ctx Pointer to the Detection Engine Context.
273
 * \param s      Pointer to the Signature to which the current keyword belongs.
274
 * \param arg    Should hold an empty string always.
275
 *
276
 * \retval  0 On success.
277
 * \retval -1 On failure.
278
 */
279
static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
280
651
{
281
651
    return DetectEngineContentModifierBufferSetup(
282
651
            de_ctx, s, arg, DETECT_AL_HTTP_RAW_URI, g_http_raw_uri_buffer_id, ALPROTO_HTTP1);
283
651
}
284
285
static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **sigerror)
286
441
{
287
441
    return DetectUrilenValidateContent(s, g_http_raw_uri_buffer_id, sigerror);
288
441
}
289
290
static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx,
291
                                          Signature *s)
292
2.16k
{
293
2.16k
    SCLogDebug("callback invoked by %u", s->id);
294
2.16k
    DetectUrilenApplyToContent(s, g_http_raw_uri_buffer_id);
295
2.16k
}
296
297
/**
298
 * \brief this function setup the http.uri.raw keyword used in the rule
299
 *
300
 * \param de_ctx   Pointer to the Detection Engine Context
301
 * \param s        Pointer to the Signature to which the current keyword belongs
302
 * \param str      Should hold an empty string always
303
 *
304
 * \retval 0       On success
305
 */
306
static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
307
2.28k
{
308
2.28k
    if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_uri_buffer_id) < 0)
309
3
        return -1;
310
2.28k
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
311
4
        return -1;
312
2.27k
    return 0;
313
2.28k
}
314
315
static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx,
316
        const DetectEngineTransforms *transforms, Flow *_f,
317
        const uint8_t _flow_flags, void *txv, const int list_id)
318
12.7k
{
319
12.7k
    SCEnter();
320
321
12.7k
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
322
12.7k
    if (!buffer->initialized) {
323
10.0k
        htp_tx_t *tx = (htp_tx_t *)txv;
324
10.0k
        if (unlikely(tx->request_uri == NULL)) {
325
1.94k
            return NULL;
326
1.94k
        }
327
8.08k
        const uint32_t data_len = bstr_len(tx->request_uri);
328
8.08k
        const uint8_t *data = bstr_ptr(tx->request_uri);
329
330
8.08k
        InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
331
8.08k
        InspectionBufferApplyTransforms(buffer, transforms);
332
8.08k
    }
333
334
10.8k
    return buffer;
335
12.7k
}
336
337
#ifdef UNITTESTS /* UNITTESTS */
338
#include "tests/detect-http-uri.c"
339
#endif /* UNITTESTS */
340
341
/**
342
 * @}
343
 */