~ubuntu-branches/ubuntu/utopic/suricata/utopic

« back to all changes in this revision

Viewing changes to src/detect-http-stat-msg.c

  • Committer: Package Import Robot
  • Author(s): Pierre Chifflier
  • Date: 2012-07-22 22:27:36 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20120722222736-s2bcw3ruzenagjam
Tags: 1.3-1
* Imported Upstream version 1.3
* Add build-dependency on libnss3-dev and libnspr4-dev
* Bump Standards Version to 3.9.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 * \file
27
27
 *
28
28
 * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
 
29
 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
29
30
 *
30
31
 * Implements the http_stat_msg keyword
31
32
 */
39
40
#include "detect-parse.h"
40
41
#include "detect-engine.h"
41
42
#include "detect-content.h"
 
43
#include "detect-pcre.h"
 
44
#include "detect-engine-mpm.h"
42
45
 
43
46
#include "flow.h"
44
47
#include "flow-var.h"
72
75
void DetectHttpStatMsgRegister (void) {
73
76
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].name = "http_stat_msg";
74
77
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Match = NULL;
75
 
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = DetectHttpStatMsgMatch;
 
78
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = NULL;
76
79
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].alproto = ALPROTO_HTTP;
77
80
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup;
78
 
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Free  = DetectHttpStatMsgFree;
 
81
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Free  = NULL;
79
82
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests;
80
83
 
81
84
    sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD;
82
85
}
83
86
 
84
87
/**
85
 
 * \brief match the specified content in the signature with the received http
86
 
 *        status message header in the http response.
87
 
 *
88
 
 * \param t         pointer to thread vars
89
 
 * \param det_ctx   pointer to the pattern matcher thread
90
 
 * \param f         pointer to the current flow
91
 
 * \param flags     flags to indicate the direction of the received packet
92
 
 * \param state     pointer the app layer state, which will cast into HtpState
93
 
 * \param s         pointer to the current signature
94
 
 * \param sm        pointer to the sigmatch
95
 
 *
96
 
 * \retval 0 no match
97
 
 * \retval 1 match
98
 
 */
99
 
int DetectHttpStatMsgMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx,
100
 
                           Flow *f, uint8_t flags, void *state, Signature *s,
101
 
                           SigMatch *sm)
102
 
{
103
 
    SCEnter();
104
 
 
105
 
    int ret = 0;
106
 
    int idx;
107
 
 
108
 
    SCMutexLock(&f->m);
109
 
    SCLogDebug("got lock %p", &f->m);
110
 
 
111
 
    DetectContentData *co = (DetectContentData *)sm->ctx;
112
 
 
113
 
    HtpState *htp_state = (HtpState *)state;
114
 
    if (htp_state == NULL) {
115
 
        SCLogDebug("no HTTP layer state has been received, so no match");
116
 
        goto end;
117
 
    }
118
 
 
119
 
    if (!(htp_state->flags & HTP_FLAG_STATE_OPEN)) {
120
 
        SCLogDebug("HTP state not yet properly setup, so no match");
121
 
        goto end;
122
 
    }
123
 
 
124
 
    SCLogDebug("htp_state %p, flow %p", htp_state, f);
125
 
    SCLogDebug("htp_state->connp %p", htp_state->connp);
126
 
    SCLogDebug("htp_state->connp->conn %p", htp_state->connp->conn);
127
 
 
128
 
    if (htp_state->connp == NULL || htp_state->connp->conn == NULL) {
129
 
        SCLogDebug("HTTP connection structure is NULL");
130
 
        goto end;
131
 
    }
132
 
 
133
 
    htp_tx_t *tx = NULL;
134
 
 
135
 
    idx = AppLayerTransactionGetInspectId(f);
136
 
    if (idx == -1) {
137
 
        goto end;
138
 
    }
139
 
 
140
 
    int size = (int)list_size(htp_state->connp->conn->transactions);
141
 
    for (; idx < size; idx++)
142
 
    {
143
 
        tx = list_get(htp_state->connp->conn->transactions, idx);
144
 
        if (tx == NULL)
145
 
            continue;
146
 
 
147
 
        if (tx->response_message == NULL)
148
 
            continue;
149
 
 
150
 
        SCLogDebug("we have a response message");
151
 
 
152
 
        /* call the case insensitive version if nocase has been specified in the sig */
153
 
        if (co->flags & DETECT_CONTENT_NOCASE) {
154
 
            if (SpmNocaseSearch((uint8_t *) bstr_ptr(tx->response_message),
155
 
                    bstr_len(tx->response_message), co->content, co->content_len) != NULL)
156
 
            {
157
 
                SCLogDebug("match has been found in received request and given http_"
158
 
                           "stat_msg rule");
159
 
                ret = 1;
160
 
            }
161
 
        } else {
162
 
            if (SpmSearch((uint8_t *) bstr_ptr(tx->response_message),
163
 
                    bstr_len(tx->response_message), co->content, co->content_len) != NULL)
164
 
            {
165
 
                SCLogDebug("match has been found in received request and given http_"
166
 
                           "stat_msg rule");
167
 
                ret = 1;
168
 
            }
169
 
        }
170
 
    }
171
 
 
172
 
    SCMutexUnlock(&f->m);
173
 
    SCReturnInt(ret ^ ((co->flags & DETECT_CONTENT_NEGATED) ? 1 : 0));
174
 
 
175
 
end:
176
 
    SCMutexUnlock(&f->m);
177
 
    SCLogDebug("released lock %p", &f->m);
178
 
    SCReturnInt(ret);
179
 
}
180
 
 
181
 
/**
182
 
 * \brief this function clears the memory of http_stat_msg modifier keyword
183
 
 *
184
 
 * \param ptr   Pointer to the Detection Stat Message data
185
 
 */
186
 
void DetectHttpStatMsgFree(void *ptr)
187
 
{
188
 
    DetectContentData *hsmd = (DetectContentData *)ptr;
189
 
    if (hsmd == NULL)
190
 
        return;
191
 
    if (hsmd->content != NULL)
192
 
        SCFree(hsmd->content);
193
 
    SCFree(hsmd);
194
 
}
195
 
 
196
 
/**
197
88
 * \brief this function setups the http_stat_msg modifier keyword used in the rule
198
89
 *
199
90
 * \param de_ctx   Pointer to the Detection Engine Context
204
95
 * \retval -1 On failure
205
96
 */
206
97
 
207
 
static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *str)
 
98
static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *arg)
208
99
{
209
 
    DetectContentData *hd = NULL;
 
100
    DetectContentData *cd = NULL;
210
101
    SigMatch *sm = NULL;
211
102
 
212
 
    /** new sig match to replace previous content */
213
 
    SigMatch *nm = NULL;
214
 
 
215
 
    if (str != NULL && strcmp(str, "") != 0) {
216
 
        SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_msg shouldn't be supplied"
217
 
                " with an argument");
218
 
        return -1;
219
 
    }
220
 
 
221
 
    SigMatch *pm = DetectContentGetLastPattern(s->sm_lists_tail[DETECT_SM_LIST_PMATCH]);
222
 
    if (pm == NULL) {
223
 
        SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http_stat_msg found inside "
224
 
                "the rule, without a content context.  Please use a "
225
 
                "content keyword before using http_stat_msg");
226
 
        return -1;
227
 
    }
228
 
 
229
 
    /* http_stat_msg should not be used with the fast_pattern rule */
230
 
    if (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) {
231
 
        SCLogWarning(SC_WARN_COMPATIBILITY, "http_stat_msg rule can not "
232
 
                "be used with the fast_pattern rule keyword. "
233
 
                "Unsetting fast_pattern on this modifier. Signature ==> %s",
234
 
                s->sig_str);
235
 
        ((DetectContentData *)pm->ctx)->flags &= ~DETECT_CONTENT_FAST_PATTERN;
236
 
 
237
 
        /* http_stat_msg should not be used with the rawbytes rule */
238
 
    } else if (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_RAWBYTES) {
 
103
    if (arg != NULL && strcmp(arg, "") != 0) {
 
104
        SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_msg supplied with args");
 
105
        return -1;
 
106
    }
 
107
 
 
108
    sm =  SigMatchGetLastSMFromLists(s, 2,
 
109
                                     DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]);
 
110
    /* if still we are unable to find any content previous keywords, it is an
 
111
     * invalid rule */
 
112
    if (sm == NULL) {
 
113
        SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_stat_msg\" keyword "
 
114
                   "found inside the rule without a content context.  "
 
115
                   "Please use a \"content\" keyword before using the "
 
116
                   "\"http_stat_msg\" keyword");
 
117
        return -1;
 
118
    }
 
119
 
 
120
    cd = (DetectContentData *)sm->ctx;
 
121
 
 
122
    /* http_stat_msg should not be used with the rawbytes rule */
 
123
    if (cd->flags & DETECT_CONTENT_RAWBYTES) {
239
124
        SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg rule can not "
240
 
                "be used with the rawbytes rule keyword");
 
125
                   "be used with the rawbytes rule keyword");
241
126
        return -1;
242
127
    }
243
128
 
244
 
    nm = SigMatchAlloc();
245
 
    if (nm == NULL) {
246
 
        SCLogError(SC_ERR_MEM_ALLOC, "SigMatchAlloc failed");
247
 
        goto error;
248
 
    }
249
 
 
250
 
    /* Setup the HttpStatMsg data from Content data structure */
251
 
    hd = SCMalloc(sizeof(DetectContentData));
252
 
    if (hd == NULL)
253
 
        goto error;
254
 
 
255
 
    memset(hd, 0, sizeof(DetectContentData));
256
 
 
257
 
    /* Setup the http_stat_msg keyword data */
258
 
    hd->content_len = ((DetectContentData *)pm->ctx)->content_len;
259
 
    hd->content = ((DetectContentData *)pm->ctx)->content;
260
 
    hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NOCASE) ?
261
 
        DETECT_CONTENT_NOCASE : 0x00;
262
 
    hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NEGATED) ?
263
 
        DETECT_CONTENT_NEGATED : 0x00;
264
 
    nm->type = DETECT_AL_HTTP_STAT_MSG;
265
 
    nm->ctx = (void *)hd;
266
 
 
267
 
    /* pull the previous content from the pmatch list, append
268
 
     * the new match to the match list */
269
 
    SigMatchReplaceContent(s, pm, nm);
270
 
 
271
 
    /* free the old content sigmatch, the content pattern memory
272
 
     * is taken over by the new sigmatch */
273
 
    BoyerMooreCtxDeInit(((DetectContentData *)pm->ctx)->bm_ctx);
274
 
    SCFree(pm->ctx);
275
 
    SCFree(pm);
276
 
 
277
 
    /* Flagged the signature as to inspect the app layer data */
 
129
    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) {
 
130
        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http "
 
131
                   "alproto set");
 
132
        goto error;
 
133
    }
 
134
 
 
135
    if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) {
 
136
        SigMatch *pm =  SigMatchGetLastSMFromLists(s, 4,
 
137
                                                   DETECT_CONTENT, sm->prev,
 
138
                                                   DETECT_PCRE, sm->prev);
 
139
        /* pm can be NULL now.  To accomodate parsing sigs like -
 
140
         * content:one; http_modifier; content:two; distance:0; http_modifier */
 
141
        if (pm != NULL) {
 
142
            if (pm->type == DETECT_CONTENT) {
 
143
                DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
 
144
                tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT;
 
145
            } else {
 
146
                DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
 
147
                tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT;
 
148
            }
 
149
 
 
150
        } /* if (pm != NULL) */
 
151
 
 
152
        /* reassigning pm */
 
153
        pm = SigMatchGetLastSMFromLists(s, 4,
 
154
                                        DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
 
155
                                        DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]);
 
156
        if (pm == NULL) {
 
157
            SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg seen with a "
 
158
                       "distance or within without a previous http_stat_msg "
 
159
                       "content.  Invalidating signature.");
 
160
            goto error;
 
161
        }
 
162
        if (pm->type == DETECT_PCRE) {
 
163
            DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
 
164
            tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
 
165
        } else {
 
166
            DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
 
167
            tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
 
168
        }
 
169
    }
 
170
    cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HSMDMATCH);
 
171
    sm->type = DETECT_CONTENT;
 
172
 
 
173
    /* transfer the sm from the pmatch list to hcbdmatch list */
 
174
    SigMatchTransferSigMatchAcrossLists(sm,
 
175
                                        &s->sm_lists[DETECT_SM_LIST_PMATCH],
 
176
                                        &s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
 
177
                                        &s->sm_lists[DETECT_SM_LIST_HSMDMATCH],
 
178
                                        &s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]);
 
179
 
 
180
    /* flag the signature to indicate that we scan the app layer data */
278
181
    s->flags |= SIG_FLAG_APPLAYER;
279
 
 
280
 
    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) {
281
 
        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting"
282
 
                " keywords.");
283
 
        goto error;
284
 
    }
285
 
 
286
182
    s->alproto = ALPROTO_HTTP;
 
183
 
287
184
    return 0;
 
185
 
288
186
error:
289
 
    if (hd != NULL)
290
 
        DetectHttpStatMsgFree(hd);
291
 
    if (sm != NULL)
292
 
        SCFree(sm);
 
187
 
293
188
    return -1;
294
189
}
295
190
 
322
217
 
323
218
    de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
324
219
                               "(msg:\"Testing http_stat_msg\"; content:\"one\";"
325
 
            "fast_pattern; http_stat_msg;sid:1;)");
326
 
    if (de_ctx->sig_list == NULL ||
327
 
            ((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH]->ctx)->flags &
328
 
            DETECT_CONTENT_FAST_PATTERN)
 
220
            "fast_pattern; http_stat_msg; sid:1;)");
 
221
    if (de_ctx->sig_list == NULL)
 
222
        goto end;
 
223
    if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]->ctx)->flags &
 
224
        DETECT_CONTENT_FAST_PATTERN))
329
225
    {
330
226
        goto end;
331
227
    }
362
258
    }
363
259
 
364
260
    result = 0;
365
 
    sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH];
 
261
    sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH];
366
262
    if (sm == NULL) {
367
263
        printf("no sigmatch(es): ");
368
264
        goto end;
370
266
 
371
267
    SigMatch *prev = NULL;
372
268
    while (sm != NULL) {
373
 
        if (sm->type == DETECT_AL_HTTP_STAT_MSG) {
 
269
        if (sm->type == DETECT_CONTENT) {
374
270
            result = 1;
375
271
        } else {
376
 
            printf("expected DETECT_AL_HTTP_STAT_MSG, got %d: ", sm->type);
 
272
            printf("expected DETECT_CONTENT for http_stat_msg, got %d: ", sm->type);
377
273
            goto end;
378
274
        }
379
275
        prev = sm;
417
313
    f.flags |= FLOW_IPV4;
418
314
 
419
315
    p->flow = &f;
420
 
    p->flowflags |= FLOW_PKT_TOSERVER;
 
316
    p->flowflags |= FLOW_PKT_TOCLIENT;
421
317
    p->flowflags |= FLOW_PKT_ESTABLISHED;
422
318
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
423
319
    f.alproto = ALPROTO_HTTP;
440
336
 
441
337
    s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP "
442
338
                      "Status message nocase\"; content:\"ok\"; nocase; "
443
 
            "http_stat_msg; sid:2;)");
 
339
                      "http_stat_msg; sid:2;)");
444
340
    if (s->next == NULL) {
445
341
        goto end;
446
342
    }
523
419
    f.flags |= FLOW_IPV4;
524
420
 
525
421
    p->flow = &f;
526
 
    p->flowflags |= FLOW_PKT_TOSERVER;
 
422
    p->flowflags |= FLOW_PKT_TOCLIENT;
527
423
    p->flowflags |= FLOW_PKT_ESTABLISHED;
528
424
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
529
425
    f.alproto = ALPROTO_HTTP;
619
515
    f.flags |= FLOW_IPV4;
620
516
 
621
517
    p->flow = &f;
622
 
    p->flowflags |= FLOW_PKT_TOSERVER;
 
518
    p->flowflags |= FLOW_PKT_TOCLIENT;
623
519
    p->flowflags |= FLOW_PKT_ESTABLISHED;
624
520
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
625
521
    f.alproto = ALPROTO_HTTP;