suricata
detect-http-raw-header.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2019 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 Pablo Rincon <pablo.rincon.crespo@gmail.com>
29  *
30  * Implements support for http_raw_header keyword.
31  */
32 
33 #include "suricata-common.h"
34 #include "threads.h"
35 #include "decode.h"
36 
37 #include "detect.h"
38 #include "detect-parse.h"
39 #include "detect-engine.h"
40 #include "detect-engine-mpm.h"
42 #include "detect-content.h"
43 
44 #include "flow.h"
45 #include "flow-var.h"
46 #include "flow-util.h"
47 
48 #include "util-debug.h"
49 
50 #include "app-layer.h"
51 #include "app-layer-parser.h"
52 #include "app-layer-htp.h"
53 #include "detect-http-raw-header.h"
54 
55 static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *);
56 static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
57 #ifdef UNITTESTS
58 static void DetectHttpRawHeaderRegisterTests(void);
59 #endif
60 static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror);
61 static int g_http_raw_header_buffer_id = 0;
62 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
63  const DetectEngineTransforms *transforms, Flow *_f,
64  const uint8_t flow_flags, void *txv, const int list_id);
65 
66 static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx,
67  SigGroupHead *sgh, MpmCtx *mpm_ctx,
68  const DetectBufferMpmRegistery *mpm_reg, int list_id);
69 static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx,
70  SigGroupHead *sgh, MpmCtx *mpm_ctx,
71  const DetectBufferMpmRegistery *mpm_reg, int list_id);
72 
73 /**
74  * \brief Registers the keyword handlers for the "http_raw_header" keyword.
75  */
77 {
78  /* http_raw_header content modifier */
79  sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].name = "http_raw_header";
80  sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].desc = "content modifier to match the raw HTTP header buffer";
81  sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-header-and-http-raw-header";
82  sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup;
83 #ifdef UNITTESTS
85 #endif
88 
89  /* http.header.raw sticky buffer */
90  sigmatch_table[DETECT_HTTP_RAW_HEADER].name = "http.header.raw";
91  sigmatch_table[DETECT_HTTP_RAW_HEADER].desc = "sticky buffer to match the raw HTTP header buffer";
92  sigmatch_table[DETECT_HTTP_RAW_HEADER].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-header-and-http-raw-header";
93  sigmatch_table[DETECT_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetupSticky;
95 
97  SIG_FLAG_TOSERVER, HTP_REQUEST_HEADERS+1,
100  SIG_FLAG_TOCLIENT, HTP_RESPONSE_HEADERS+1,
102 
103  DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOSERVER, 2,
104  PrefilterMpmHttpHeaderRawRequestRegister, NULL, ALPROTO_HTTP,
105  0); /* progress handled in register */
106  DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOCLIENT, 2,
107  PrefilterMpmHttpHeaderRawResponseRegister, NULL, ALPROTO_HTTP,
108  0); /* progress handled in register */
109 
110  DetectBufferTypeSetDescriptionByName("http_raw_header",
111  "raw http headers");
112 
114  DetectHttpRawHeaderValidateCallback);
115 
116  g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header");
117 }
118 
119 /**
120  * \brief The setup function for the http_raw_header keyword for a signature.
121  *
122  * \param de_ctx Pointer to the detection engine context.
123  * \param s Pointer to signature for the current Signature being parsed
124  * from the rules.
125  * \param m Pointer to the head of the SigMatchs for the current rule
126  * being parsed.
127  * \param arg Pointer to the string holding the keyword value.
128  *
129  * \retval 0 On success.
130  * \retval -1 On failure.
131  */
132 int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
133 {
134  return DetectEngineContentModifierBufferSetup(de_ctx, s, arg,
136  g_http_raw_header_buffer_id,
137  ALPROTO_HTTP);
138 }
139 
140 /**
141  * \brief this function setup the http.header.raw 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  */
149 static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
150 {
151  if (DetectBufferSetActiveList(s, g_http_raw_header_buffer_id) < 0)
152  return -1;
154  return -1;
155  return 0;
156 }
157 
158 static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror)
159 {
161  *sigerror = "http_raw_header signature "
162  "without a flow direction. Use flow:to_server for "
163  "inspecting request headers or flow:to_client for "
164  "inspecting response headers.";
165 
166  SCLogError(SC_ERR_INVALID_SIGNATURE, "%s", *sigerror);
168  }
169  return TRUE;
170 }
171 
172 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
173  const DetectEngineTransforms *transforms, Flow *_f,
174  const uint8_t flow_flags, void *txv, const int list_id)
175 {
176  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
177  if (buffer->inspect == NULL) {
178  htp_tx_t *tx = (htp_tx_t *)txv;
179 
180  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
181  if (tx_ud == NULL)
182  return NULL;
183 
184  const bool ts = ((flow_flags & STREAM_TOSERVER) != 0);
185  const uint8_t *data = ts ?
187  if (data == NULL)
188  return NULL;
189  const uint8_t data_len = ts ?
191 
192  InspectionBufferSetup(buffer, data, data_len);
193  InspectionBufferApplyTransforms(buffer, transforms);
194  }
195 
196  return buffer;
197 }
198 
200  int list_id;
201  const MpmCtx *mpm_ctx;
204 
205 /** \brief Generic Mpm prefilter callback
206  *
207  * \param det_ctx detection engine thread ctx
208  * \param p packet to inspect
209  * \param f flow to inspect
210  * \param txv tx to inspect
211  * \param pectx inspection context
212  */
213 static void PrefilterMpmHttpHeaderRaw(DetectEngineThreadCtx *det_ctx,
214  const void *pectx,
215  Packet *p, Flow *f, void *txv,
216  const uint64_t idx, const uint8_t flags)
217 {
218  SCEnter();
219 
220  const PrefilterMpmHttpHeaderRawCtx *ctx = pectx;
221  const MpmCtx *mpm_ctx = ctx->mpm_ctx;
222  SCLogDebug("running on list %d", ctx->list_id);
223 
224  const int list_id = ctx->list_id;
225 
226  InspectionBuffer *buffer = GetData(det_ctx, ctx->transforms, f,
227  flags, txv, list_id);
228  if (buffer == NULL)
229  return;
230 
231  const uint32_t data_len = buffer->inspect_len;
232  const uint8_t *data = buffer->inspect;
233 
234  SCLogDebug("mpm'ing buffer:");
235  //PrintRawDataFp(stdout, data, data_len);
236 
237  if (data != NULL && data_len >= mpm_ctx->minlen) {
238  (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
239  &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
240  }
241 }
242 
243 static void PrefilterMpmHttpTrailerRaw(DetectEngineThreadCtx *det_ctx,
244  const void *pectx,
245  Packet *p, Flow *f, void *txv,
246  const uint64_t idx, const uint8_t flags)
247 {
248  SCEnter();
249 
250  htp_tx_t *tx = txv;
251  const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx);
252  /* if the request wasn't flagged as having a trailer, we skip */
253  if (htud && (
254  ((flags & STREAM_TOSERVER) && !htud->request_has_trailers) ||
255  ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers))) {
256  SCReturn;
257  }
258  PrefilterMpmHttpHeaderRaw(det_ctx, pectx, p, f, txv, idx, flags);
259  SCReturn;
260 }
261 
262 static void PrefilterMpmHttpHeaderRawFree(void *ptr)
263 {
264  SCFree(ptr);
265 }
266 
267 static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx,
268  SigGroupHead *sgh, MpmCtx *mpm_ctx,
269  const DetectBufferMpmRegistery *mpm_reg, int list_id)
270 {
271  SCEnter();
272 
273  /* header */
274  PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
275  if (pectx == NULL)
276  return -1;
277  pectx->list_id = list_id;
278  pectx->mpm_ctx = mpm_ctx;
279  pectx->transforms = &mpm_reg->transforms;
280 
281  int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw,
282  mpm_reg->app_v2.alproto, HTP_REQUEST_HEADERS+1,
283  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
284  if (r != 0) {
285  SCFree(pectx);
286  return r;
287  }
288 
289  /* trailer */
290  pectx = SCCalloc(1, sizeof(*pectx));
291  if (pectx == NULL)
292  return -1;
293  pectx->list_id = list_id;
294  pectx->mpm_ctx = mpm_ctx;
295  pectx->transforms = &mpm_reg->transforms;
296 
297  r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw,
298  mpm_reg->app_v2.alproto, HTP_REQUEST_TRAILER+1,
299  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
300  if (r != 0) {
301  SCFree(pectx);
302  }
303  return r;
304 }
305 
306 static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx,
307  SigGroupHead *sgh, MpmCtx *mpm_ctx,
308  const DetectBufferMpmRegistery *mpm_reg, int list_id)
309 {
310  SCEnter();
311 
312  /* header */
313  PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
314  if (pectx == NULL)
315  return -1;
316  pectx->list_id = list_id;
317  pectx->mpm_ctx = mpm_ctx;
318  pectx->transforms = &mpm_reg->transforms;
319 
320  int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw,
321  mpm_reg->app_v2.alproto, HTP_RESPONSE_HEADERS,
322  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
323  if (r != 0) {
324  SCFree(pectx);
325  return r;
326  }
327 
328  /* trailer */
329  pectx = SCCalloc(1, sizeof(*pectx));
330  if (pectx == NULL)
331  return -1;
332  pectx->list_id = list_id;
333  pectx->mpm_ctx = mpm_ctx;
334  pectx->transforms = &mpm_reg->transforms;
335 
336  r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw,
337  mpm_reg->app_v2.alproto, HTP_RESPONSE_TRAILER,
338  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
339  if (r != 0) {
340  SCFree(pectx);
341  }
342  return r;
343 }
344 
345 /************************************Unittests*********************************/
346 
347 #ifdef UNITTESTS
349 #endif
350 
351 /**
352  * @}
353  */
void DetectHttpRawHeaderRegister(void)
Registers the keyword handlers for the "http_raw_header" keyword.
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1448
uint32_t request_headers_raw_len
uint16_t flags
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1186
#define SCLogDebug(...)
Definition: util-debug.h:335
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
uint16_t minlen
Definition: util-mpm.h:99
uint32_t flags
Definition: detect.h:523
#define FALSE
DetectEngineTransforms transforms
Definition: detect.h:618
const DetectEngineTransforms * transforms
struct DetectBufferMpmRegistery_::@95::@97 app_v2
#define SIGMATCH_INFO_CONTENT_MODIFIER
Definition: detect.h:1391
Handle HTTP raw header match.
Container for matching data for a signature group.
Definition: detect.h:1336
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
const char * name
Definition: detect.h:1200
Signature container.
Definition: detect.h:522
#define TRUE
void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistery *mpm_reg, int list_id), InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register a MPM engine
uint8_t response_has_trailers
uint8_t * request_headers_raw
main detection engine ctx
Definition: detect.h:761
int DetectBufferTypeGetByName(const char *name)
#define str(s)
#define SCCalloc(nm, a)
Definition: util-mem.h:253
#define SIG_FLAG_TOCLIENT
Definition: detect.h:237
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect.h:1393
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
uint8_t mpm_type
Definition: util-mpm.h:90
one time registration of keywords at start up
Definition: detect.h:605
#define SIG_FLAG_TOSERVER
Definition: detect.h:236
#define SCEnter(...)
Definition: util-debug.h:337
void DetectAppLayerInspectEngineRegister2(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr2 Callback2, InspectionBufferGetDataPtr GetData)
register inspect engine at start up time
PrefilterRuleStore pmq
Definition: detect.h:1102
uint16_t alternative
Definition: detect.h:1198
#define STREAM_TOCLIENT
Definition: stream.h:32
int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, int sm_type, int sm_list, AppProto alproto)
Definition: detect-parse.c:143
int DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
#define SCReturnInt(x)
Definition: util-debug.h:341
const char * desc
Definition: detect.h:1202
uint8_t request_has_trailers
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.h:169
#define SCFree(a)
Definition: util-mem.h:322
void InspectionBufferSetup(InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
MpmThreadCtx mtcu
Definition: detect.h:1100
uint8_t * response_headers_raw
void InspectionBufferApplyTransforms(InspectionBuffer *buffer, const DetectEngineTransforms *transforms)
uint64_t ts
#define SIGMATCH_NOOPT
Definition: detect.h:1369
const char * url
Definition: detect.h:1203
void DetectHttpRawHeaderRegisterTests(void)
#define STREAM_TOSERVER
Definition: stream.h:31
struct PrefilterMpmHttpHeaderRawCtx PrefilterMpmHttpHeaderRawCtx
uint32_t inspect_len
Definition: detect.h:345
int DetectBufferSetActiveList(Signature *s, const int list)
const uint8_t * inspect
Definition: detect.h:343
#define DOC_URL
Definition: suricata.h:86
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
uint32_t response_headers_raw_len
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:162
#define SCReturn
Definition: util-debug.h:339
int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void(*PrefilterTxFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *tx, const uint64_t idx, const uint8_t flags), AppProto alproto, int tx_min_progress, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
void DetectBufferTypeRegisterValidateCallback(const char *name, _Bool(*ValidateCallback)(const Signature *, const char **sigerror))
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1194
Flow data structure.
Definition: flow.h:325
void(* RegisterTests)(void)
Definition: detect.h:1192