suricata
detect-http-client-body.c
Go to the documentation of this file.
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 Anoop Saldanha <anoopsaldanha@gmail.com>
29  *
30  * Implements support for the http_client_body 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"
41 #include "detect-engine-state.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-unittest.h"
52 #include "util-unittest-helper.h"
53 #include "util-spm.h"
54 
55 #include "app-layer.h"
56 #include "app-layer-parser.h"
57 #include "app-layer-htp.h"
59 #include "stream-tcp.h"
60 
61 static int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, const char *);
62 static int DetectHttpClientBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
63 #ifdef UNITTESTS
64 static void DetectHttpClientBodyRegisterTests(void);
65 #endif
66 static void DetectHttpClientBodySetupCallback(const DetectEngineCtx *de_ctx,
67  Signature *s);
68 static int g_http_client_body_buffer_id = 0;
69 
70 static InspectionBuffer *HttpClientBodyGetDataCallback(
71  DetectEngineThreadCtx *det_ctx,
72  const DetectEngineTransforms *transforms,
73  Flow *f, const uint8_t flow_flags,
74  void *txv, const int list_id);
75 
76 /**
77  * \brief Registers the keyword handlers for the "http_client_body" keyword.
78  */
80 {
81  /* http_client_body content modifier */
82  sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].name = "http_client_body";
83  sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].desc = "content modifier to match only on HTTP request-body";
84  sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-client-body";
85  sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup;
86 #ifdef UNITTESTS
88 #endif
92 
93  /* http.request_body sticky buffer */
94  sigmatch_table[DETECT_HTTP_REQUEST_BODY].name = "http.request_body";
95  sigmatch_table[DETECT_HTTP_REQUEST_BODY].desc = "sticky buffer to match the HTTP request body buffer";
96  sigmatch_table[DETECT_HTTP_REQUEST_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-client-body";
97  sigmatch_table[DETECT_HTTP_REQUEST_BODY].Setup = DetectHttpClientBodySetupSticky;
100 
102  SIG_FLAG_TOSERVER, HTP_REQUEST_BODY,
104  HttpClientBodyGetDataCallback);
105 
106  DetectAppLayerMpmRegister2("http_client_body", SIG_FLAG_TOSERVER, 2,
107  PrefilterGenericMpmRegister, HttpClientBodyGetDataCallback,
108  ALPROTO_HTTP, HTP_REQUEST_BODY);
109 
110  DetectBufferTypeSetDescriptionByName("http_client_body",
111  "http request body");
112 
113  DetectBufferTypeRegisterSetupCallback("http_client_body",
114  DetectHttpClientBodySetupCallback);
115 
116  g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body");
117 }
118 
119 static void DetectHttpClientBodySetupCallback(const DetectEngineCtx *de_ctx,
120  Signature *s)
121 {
122  SCLogDebug("callback invoked by %u", s->id);
124 
125  /* client body needs to be inspected in sync with stream if possible */
127 }
128 
129 /**
130  * \brief The setup function for the http_client_body keyword for a signature.
131  *
132  * \param de_ctx Pointer to the detection engine context.
133  * \param s Pointer to signature for the current Signature being parsed
134  * from the rules.
135  * \param m Pointer to the head of the SigMatchs for the current rule
136  * being parsed.
137  * \param arg Pointer to the string holding the keyword value.
138  *
139  * \retval 0 On success
140  * \retval -1 On failure
141  */
142 int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
143 {
144  return DetectEngineContentModifierBufferSetup(de_ctx, s, arg,
146  g_http_client_body_buffer_id,
147  ALPROTO_HTTP);
148 }
149 
150 /**
151  * \brief this function setup the http.request_body keyword used in the rule
152  *
153  * \param de_ctx Pointer to the Detection Engine Context
154  * \param s Pointer to the Signature to which the current keyword belongs
155  * \param str Should hold an empty string always
156  *
157  * \retval 0 On success
158  */
159 static int DetectHttpClientBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
160 {
161  if (DetectBufferSetActiveList(s, g_http_client_body_buffer_id) < 0)
162  return -1;
164  return -1;
165  return 0;
166 }
167 
168 static inline HtpBody *GetRequestBody(htp_tx_t *tx)
169 {
170  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
171  if (htud == NULL) {
172  SCLogDebug("no htud");
173  return NULL;
174  }
175 
176  return &htud->request_body;
177 }
178 
179 static InspectionBuffer *HttpClientBodyGetDataCallback(DetectEngineThreadCtx *det_ctx,
180  const DetectEngineTransforms *transforms,
181  Flow *f, const uint8_t flow_flags,
182  void *txv, const int list_id)
183 {
184  SCEnter();
185 
186  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
187  if (buffer->inspect != NULL)
188  return buffer;
189 
190  htp_tx_t *tx = txv;
191  HtpState *htp_state = f->alstate;
192  const uint8_t flags = flow_flags;
193 
194  HtpBody *body = GetRequestBody(tx);
195  if (body == NULL) {
196  return NULL;
197  }
198 
199  /* no new data */
200  if (body->body_inspected == body->content_len_so_far) {
201  SCLogDebug("no new data");
202  return NULL;
203  }
204 
205  HtpBodyChunk *cur = body->first;
206  if (cur == NULL) {
207  SCLogDebug("No http chunks to inspect for this transacation");
208  return NULL;
209  }
210 
211  SCLogDebug("request.body_limit %u request_body.content_len_so_far %"PRIu64
212  ", request.inspect_min_size %"PRIu32", EOF %s, progress > body? %s",
213  htp_state->cfg->request.body_limit, body->content_len_so_far,
214  htp_state->cfg->request.inspect_min_size,
215  flags & STREAM_EOF ? "true" : "false",
216  (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) ? "true" : "false");
217 
218  if (!htp_state->cfg->http_body_inline) {
219  /* inspect the body if the transfer is complete or we have hit
220  * our body size limit */
221  if ((htp_state->cfg->request.body_limit == 0 ||
222  body->content_len_so_far < htp_state->cfg->request.body_limit) &&
223  body->content_len_so_far < htp_state->cfg->request.inspect_min_size &&
224  !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) &&
225  !(flags & STREAM_EOF)) {
226  SCLogDebug("we still haven't seen the entire request body. "
227  "Let's defer body inspection till we see the "
228  "entire body.");
229  return NULL;
230  }
231  }
232 
233  /* get the inspect buffer
234  *
235  * make sure that we have at least the configured inspect_win size.
236  * If we have more, take at least 1/4 of the inspect win size before
237  * the new data.
238  */
239  uint64_t offset = 0;
240  if (body->body_inspected > htp_state->cfg->request.inspect_min_size) {
242  uint64_t inspect_win = body->content_len_so_far - body->body_inspected;
243  SCLogDebug("inspect_win %"PRIu64, inspect_win);
244  if (inspect_win < htp_state->cfg->request.inspect_window) {
245  uint64_t inspect_short = htp_state->cfg->request.inspect_window - inspect_win;
246  if (body->body_inspected < inspect_short)
247  offset = 0;
248  else
249  offset = body->body_inspected - inspect_short;
250  } else {
251  offset = body->body_inspected - (htp_state->cfg->request.inspect_window / 4);
252  }
253  }
254 
255  const uint8_t *data;
256  uint32_t data_len;
257 
259  &data, &data_len, offset);
260  InspectionBufferSetup(buffer, data, data_len);
261  buffer->inspect_offset = offset;
262 
263  /* move inspected tracker to end of the data. HtpBodyPrune will consider
264  * the window sizes when freeing data */
265  body->body_inspected = body->content_len_so_far;
266  SCLogDebug("body->body_inspected now: %"PRIu64, body->body_inspected);
267 
268  SCReturnPtr(buffer, "InspectionBuffer");
269 }
270 
271 #ifdef UNITTESTS
273 #endif /* UNITTESTS */
274 
275 /**
276  * @}
277  */
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1409
SignatureInitData * init_data
Definition: detect.h:564
uint16_t flags
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1150
#define SCLogDebug(...)
Definition: util-debug.h:335
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
uint32_t inspect_window
#define SIG_FLAG_INIT_NEED_FLUSH
Definition: detect.h:268
#define BUG_ON(x)
uint32_t id
Definition: detect.h:529
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t flags)
get the progress value for a tx/protocol
Handle HTTP request body match corresponding to http_client_body keyword.
int StreamingBufferGetDataAtOffset(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
const struct HTPCfgRec_ * cfg
uint32_t inspect_min_size
int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectMpmAppLayerRegistery *mpm_reg, int list_id)
uint64_t offset
#define SIGMATCH_INFO_CONTENT_MODIFIER
Definition: detect.h:1354
void DetectBufferTypeRegisterSetupCallback(const char *name, void(*SetupCallback)(const DetectEngineCtx *, Signature *))
void DetectHttpClientBodyRegister(void)
Registers the keyword handlers for the "http_client_body" keyword.
int http_body_inline
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
const char * name
Definition: detect.h:1164
Signature container.
Definition: detect.h:496
HtpBody request_body
main detection engine ctx
Definition: detect.h:724
void * alstate
Definition: flow.h:438
int DetectBufferTypeGetByName(const char *name)
#define str(s)
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect.h:1356
HTPCfgDir request
uint64_t inspect_offset
Definition: detect.h:348
uint64_t body_inspected
Data structures and function prototypes for keeping state for the detection engine.
void AppLayerHtpEnableRequestBodyCallback(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request body...
StreamingBuffer * sb
#define STREAM_EOF
Definition: stream.h:30
#define SIG_FLAG_TOSERVER
Definition: detect.h:241
#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
uint16_t alternative
Definition: detect.h:1162
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.
const char * desc
Definition: detect.h:1166
uint32_t body_limit
uint64_t content_len_so_far
uint32_t init_flags
Definition: detect.h:460
void InspectionBufferSetup(InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
#define SIGMATCH_NOOPT
Definition: detect.h:1332
const char * url
Definition: detect.h:1167
#define SCReturnPtr(x, type)
Definition: util-debug.h:353
int DetectBufferSetActiveList(Signature *s, const int list)
const uint8_t * inspect
Definition: detect.h:347
#define DOC_URL
Definition: suricata.h:86
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
HtpBodyChunk * first
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1158
void DetectHttpClientBodyRegisterTests(void)
Flow data structure.
Definition: flow.h:325
void(* RegisterTests)(void)
Definition: detect.h:1156
void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectMpmAppLayerRegistery *mpm_reg, int list_id), InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register a MPM engine