1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // http_msg_section.cc author Tom Peters <thopeter@cisco.com>
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <cstring>
25
26 #include "service_inspectors/http2_inspect/http2_flow_data.h"
27
28 #include "http_msg_section.h"
29
30 #include "http_context_data.h"
31 #include "http_common.h"
32 #include "http_enum.h"
33 #include "http_module.h"
34 #include "http_msg_body.h"
35 #include "http_msg_head_shared.h"
36 #include "http_msg_header.h"
37 #include "http_msg_request.h"
38 #include "http_msg_status.h"
39 #include "http_msg_trailer.h"
40 #include "http_param.h"
41 #include "http_query_parser.h"
42 #include "http_test_manager.h"
43 #include "stream/flush_bucket.h"
44
45 using namespace HttpCommon;
46 using namespace HttpEnums;
47 using namespace snort;
48
HttpMsgSection(const uint8_t * buffer,const uint16_t buf_size,HttpFlowData * session_data_,SourceId source_id_,bool buf_owner,Flow * flow_,const HttpParaList * params_)49 HttpMsgSection::HttpMsgSection(const uint8_t* buffer, const uint16_t buf_size,
50 HttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
51 const HttpParaList* params_) :
52 msg_text(buf_size, buffer, buf_owner),
53 session_data(session_data_),
54 flow(flow_),
55 params(params_),
56 transaction(HttpTransaction::attach_my_transaction(session_data, source_id_)),
57 trans_num(session_data->expected_trans_num[source_id_]),
58 status_code_num((source_id_ == SRC_SERVER) ? session_data->status_code_num : STAT_NOT_PRESENT),
59 source_id(source_id_),
60 version_id(session_data->version_id[source_id]),
61 method_id((source_id == SRC_CLIENT) ? session_data->method_id : METH__NOT_PRESENT),
62 tcp_close(session_data->tcp_close[source_id])
63 {
64 assert((source_id == SRC_CLIENT) || (source_id == SRC_SERVER));
65
66 if (Http2FlowData::inspector_id != 0)
67 {
68 Http2FlowData* const h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
69 if (h2i_flow_data != nullptr)
70 {
71 h2i_flow_data->set_hi_msg_section(this);
72 return;
73 }
74 }
75
76 HttpContextData::save_snapshot(this);
77 }
78
add_infraction(int infraction)79 void HttpMsgSection::add_infraction(int infraction)
80 {
81 *transaction->get_infractions(source_id) += infraction;
82 }
83
create_event(int sid)84 void HttpMsgSection::create_event(int sid)
85 {
86 session_data->events[source_id]->create_event(sid);
87 }
88
update_depth() const89 void HttpMsgSection::update_depth() const
90 {
91 const int64_t& file_depth_remaining = session_data->file_depth_remaining[source_id];
92 const int64_t& detect_depth_remaining = session_data->detect_depth_remaining[source_id];
93 const int32_t& publish_depth_remaining = session_data->publish_depth_remaining[source_id];
94
95 if ((detect_depth_remaining <= 0) &&
96 (session_data->detection_status[source_id] == DET_ON) &&
97 !session_data->for_http2)
98 {
99 session_data->detection_status[source_id] = DET_DEACTIVATING;
100 }
101
102 const unsigned target_size = (session_data->compression[source_id] == CMP_NONE) ?
103 SnortConfig::get_conf()->max_pdu : GZIP_BLOCK_SIZE;
104
105 if (detect_depth_remaining <= 0)
106 {
107 if ((file_depth_remaining <= 0) && (publish_depth_remaining <= 0))
108 {
109 // Don't need any more of the body
110 session_data->section_size_target[source_id] = 0;
111 }
112 else
113 {
114 // Need data for file processing or publishing
115 session_data->stretch_section_to_packet[source_id] = true;
116 const int64_t max_remaining = (file_depth_remaining > publish_depth_remaining) ?
117 file_depth_remaining : publish_depth_remaining;
118 session_data->section_size_target[source_id] = (max_remaining <= target_size) ?
119 max_remaining : target_size;
120 }
121 return;
122 }
123
124 if (detect_depth_remaining <= target_size)
125 {
126 // Go to detection as soon as detect depth is reached
127 session_data->section_size_target[source_id] = detect_depth_remaining;
128 session_data->stretch_section_to_packet[source_id] = true;
129 }
130 else
131 {
132 // Randomize the split point a little bit to make it harder to evade detection.
133 // FlushBucket provides pseudo random numbers in the range 128 to 255.
134 const int random_increment = FlushBucket::get_size() - 192;
135 assert((random_increment >= -64) && (random_increment <= 63));
136 session_data->section_size_target[source_id] = target_size + random_increment;
137 session_data->stretch_section_to_packet[source_id] = false;
138 }
139 }
140
classic_normalize(const Field & raw,Field & norm,bool do_path,const HttpParaList::UriParam & uri_param)141 const Field& HttpMsgSection::classic_normalize(const Field& raw, Field& norm,
142 bool do_path, const HttpParaList::UriParam& uri_param)
143 {
144 if (norm.length() != STAT_NOT_COMPUTE)
145 return norm;
146
147 if ((raw.length() <= 0) || !UriNormalizer::classic_need_norm(raw, do_path, uri_param))
148 {
149 norm.set(raw);
150 return norm;
151 }
152 UriNormalizer::classic_normalize(raw, norm, do_path, uri_param);
153 return norm;
154 }
155
get_classic_buffer(unsigned id,uint64_t sub_id,uint64_t form)156 const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, uint64_t form)
157 {
158 Cursor c;
159 HttpBufferInfo buffer_info(id, sub_id, form);
160
161 return get_classic_buffer(c, buffer_info);
162 }
163
get_classic_buffer(Cursor & c,const HttpBufferInfo & buf)164 const Field& HttpMsgSection::get_classic_buffer(Cursor& c, const HttpBufferInfo& buf)
165 {
166 // buffer_side replaces source_id for buffers that support the request option
167 const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
168
169 switch (buf.type)
170 {
171 case HTTP_BUFFER_CLIENT_BODY:
172 {
173 if (source_id != SRC_CLIENT)
174 return Field::FIELD_NULL;
175 return (get_body() != nullptr) ? get_body()->get_classic_client_body() : Field::FIELD_NULL;
176 }
177 case HTTP_BUFFER_COOKIE:
178 case HTTP_BUFFER_RAW_COOKIE:
179 {
180 if (header[buffer_side] == nullptr)
181 return Field::FIELD_NULL;
182 return (buf.type == HTTP_BUFFER_COOKIE) ? header[buffer_side]->get_classic_norm_cookie() :
183 header[buffer_side]->get_classic_raw_cookie();
184 }
185 case HTTP_BUFFER_HEADER:
186 case HTTP_BUFFER_TRAILER:
187 {
188 HttpMsgHeadShared* const head = (buf.type == HTTP_BUFFER_HEADER) ?
189 (HttpMsgHeadShared*)header[buffer_side] : (HttpMsgHeadShared*)trailer[buffer_side];
190 if (head == nullptr)
191 return Field::FIELD_NULL;
192 if (buf.sub_id == 0)
193 return head->get_classic_norm_header();
194 return head->get_header_value_norm((HeaderId)buf.sub_id);
195 }
196 case HTTP_BUFFER_METHOD:
197 {
198 return (request != nullptr) ? request->get_method() : Field::FIELD_NULL;
199 }
200 case HTTP_BUFFER_PARAM:
201 {
202 if (buf.param == nullptr || request == nullptr)
203 return Field::FIELD_NULL;
204
205 HttpUri* query = request->get_http_uri();
206 HttpMsgBody* body = (source_id == SRC_CLIENT) ? get_body() : nullptr;
207
208 if (query == nullptr && body == nullptr)
209 return Field::FIELD_NULL;
210
211 const HttpParaList::UriParam& uri_config = params->uri_param;
212
213 ParameterMap& query_params = request->get_query_params();
214 ParameterMap& body_params = request->get_body_params();
215
216 // cache lookup
217 HttpParam& param = *buf.param;
218 ParameterData& query_data = query_params[param.str_upper()];
219 ParameterData& body_data = body_params[param.str_upper()];
220
221 if (!query_data.parsed && query != nullptr)
222 {
223 // query has not been parsed for this parameter
224 const Field& rq = query->get_query();
225 const Field& nq = query->get_norm_query();
226
227 if (rq.length() > 0 && nq.length() > 0)
228 {
229 HttpQueryParser parser(rq.start(), rq.length(),
230 nq.start(), nq.length(), uri_config,
231 session_data, source_id);
232
233 parser.parse(param, query_data);
234 query_data.parsed = true;
235 }
236 }
237
238 if (!body_data.parsed && body != nullptr)
239 {
240 // body has not been parsed for this parameter
241 const Field& rb = body->get_detect_data();
242 const Field& nb = body->get_classic_client_body();
243
244 if (rb.length() > 0 && nb.length() > 0 && body->is_first())
245 {
246 HttpQueryParser parser(rb.start(), rb.length(),
247 nb.start(), nb.length(), uri_config,
248 session_data, source_id);
249
250 parser.parse(param, body_data);
251 body_data.parsed = true;
252 }
253 }
254
255 KeyValueVec& query_kv = query_data.kv_vec;
256 KeyValueVec& body_kv = body_data.kv_vec;
257
258 unsigned num_query_params = query_kv.size();
259 unsigned num_body_params = body_kv.size();
260
261 if (num_query_params == 0 && num_body_params == 0)
262 return Field::FIELD_NULL;
263
264 // get data stored on the cursor
265 HttpCursorData* cd = (HttpCursorData*)c.get_data(HttpCursorData::id);
266
267 if (!cd)
268 {
269 cd = new HttpCursorData();
270 c.set_data(cd);
271 }
272
273 // save the parameter count on the cursor
274 cd->num_query_params = num_query_params;
275 cd->num_body_params = num_body_params;
276
277 unsigned& query_index = cd->query_index;
278 unsigned& body_index = cd->body_index;
279
280 while (query_index < num_query_params)
281 {
282 KeyValue* fields = query_kv[query_index];
283
284 Field& key = fields->key;
285 Field& value = fields->value;
286
287 ++query_index;
288
289 if (param.is_nocase())
290 return value;
291
292 if (!memcmp(key.start(), param.c_str(), key.length()))
293 return value;
294 }
295
296 while (body_index < num_body_params)
297 {
298 KeyValue* fields = body_kv[body_index];
299
300 Field& key = fields->key;
301 Field& value = fields->value;
302
303 ++body_index;
304
305 if (param.is_nocase())
306 return value;
307
308 if (!memcmp(key.start(), param.c_str(), key.length()))
309 return value;
310 }
311
312 return Field::FIELD_NULL;
313 }
314 case HTTP_BUFFER_RAW_BODY:
315 {
316 return (get_body() != nullptr) ? get_body()->msg_text : Field::FIELD_NULL;
317 }
318 case HTTP_BUFFER_RAW_HEADER:
319 case HTTP_BUFFER_RAW_TRAILER:
320 {
321 HttpMsgHeadShared* const head = (buf.type == HTTP_BUFFER_RAW_HEADER) ?
322 (HttpMsgHeadShared*)header[buffer_side] : (HttpMsgHeadShared*)trailer[buffer_side];
323 if (head == nullptr)
324 return Field::FIELD_NULL;
325 if (buf.sub_id == 0)
326 return head->msg_text;
327 return head->get_all_header_values_raw((HeaderId)buf.sub_id);
328 }
329 case HTTP_BUFFER_RAW_REQUEST:
330 {
331 return (request != nullptr) ? request->msg_text : Field::FIELD_NULL;
332 }
333 case HTTP_BUFFER_RAW_STATUS:
334 {
335 return (status != nullptr) ? status->msg_text : Field::FIELD_NULL;
336 }
337 case HTTP_BUFFER_STAT_CODE:
338 {
339 return (status != nullptr) ? status->get_status_code() : Field::FIELD_NULL;
340 }
341 case HTTP_BUFFER_STAT_MSG:
342 {
343 return (status != nullptr) ? status->get_reason_phrase() : Field::FIELD_NULL;
344 }
345 case HTTP_BUFFER_TRUE_IP:
346 {
347 return (header[SRC_CLIENT] != nullptr) ? header[SRC_CLIENT]->get_true_ip() :
348 Field::FIELD_NULL;
349 }
350 case HTTP_BUFFER_URI:
351 case HTTP_BUFFER_RAW_URI:
352 {
353 const bool raw = (buf.type == HTTP_BUFFER_RAW_URI);
354 if (request == nullptr)
355 return Field::FIELD_NULL;
356 if (buf.sub_id == 0)
357 return raw ? request->get_uri() : request->get_uri_norm_classic();
358 HttpUri* const uri = request->get_http_uri();
359 if (uri == nullptr)
360 return Field::FIELD_NULL;
361 switch ((UriComponent)buf.sub_id)
362 {
363 case UC_SCHEME:
364 return raw ? uri->get_scheme() : uri->get_norm_scheme();
365 case UC_HOST:
366 return raw ? uri->get_host() : uri->get_norm_host();
367 case UC_PORT:
368 return uri->get_port();
369 case UC_PATH:
370 return raw ? uri->get_path() : uri->get_norm_path();
371 case UC_QUERY:
372 return raw ? uri->get_query() : uri->get_norm_query();
373 case UC_FRAGMENT:
374 return raw ? uri->get_fragment() : uri->get_norm_fragment();
375 }
376 assert(false);
377 return Field::FIELD_NULL;
378 }
379 case HTTP_BUFFER_VERSION:
380 {
381 HttpMsgStart* start = (buffer_side == SRC_CLIENT) ?
382 (HttpMsgStart*)request : (HttpMsgStart*)status;
383 return (start != nullptr) ? start->get_version() : Field::FIELD_NULL;
384 }
385 case BUFFER_VBA_DATA:
386 {
387 HttpMsgBody* msg_body = get_body();
388 if (msg_body)
389 return msg_body->get_decomp_vba_data();
390 else
391 return Field::FIELD_NULL;
392 }
393 case BUFFER_JS_DATA:
394 {
395 HttpMsgBody* msg_body = get_body();
396 if (msg_body)
397 return msg_body->get_norm_js_data();
398 else
399 return Field::FIELD_NULL;
400 }
401 default:
402 assert(false);
403 return Field::FIELD_NULL;
404 }
405 }
406
get_num_headers(const HttpBufferInfo & buf) const407 int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const
408 {
409 // buffer_side replaces source_id for buffers that support the request option
410 const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
411
412 const HttpMsgHeadShared* const head = (buf.type == HTTP_RANGE_NUM_TRAILERS) ?
413 (HttpMsgHeadShared*)trailer[buffer_side]:
414 (HttpMsgHeadShared*)header[buffer_side] ;
415 if (head == nullptr)
416 return HttpCommon::STAT_NOT_COMPUTE;
417
418 return head->get_num_headers();
419 }
420
get_related_sections()421 void HttpMsgSection::get_related_sections()
422 {
423 // When a message section is created these relationships become fixed so we make copies for
424 // future reference.
425 request = transaction->get_request();
426 status = transaction->get_status();
427 header[SRC_CLIENT] = transaction->get_header(SRC_CLIENT);
428 header[SRC_SERVER] = transaction->get_header(SRC_SERVER);
429 trailer[SRC_CLIENT] = transaction->get_trailer(SRC_CLIENT);
430 trailer[SRC_SERVER] = transaction->get_trailer(SRC_SERVER);
431 }
432
clear()433 void HttpMsgSection::clear()
434 {
435 transaction->clear_section();
436 cleared = true;
437 }
438
439 #ifdef REG_TEST
440
print_section_title(FILE * output,const char * title) const441 void HttpMsgSection::print_section_title(FILE* output, const char* title) const
442 {
443 fprintf(output, "HTTP message %" PRIu64 " %s:\n", trans_num, title);
444 msg_text.print(output, "Input");
445 }
446
print_section_wrapup(FILE * output) const447 void HttpMsgSection::print_section_wrapup(FILE* output) const
448 {
449 fprintf(output, "Infractions: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 ", Events: %016"
450 PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 ", TCP Close: %s\n\n",
451 transaction->get_infractions(source_id)->get_raw3(),
452 transaction->get_infractions(source_id)->get_raw2(),
453 transaction->get_infractions(source_id)->get_raw(),
454 session_data->events[source_id]->get_raw4(),
455 session_data->events[source_id]->get_raw3(),
456 session_data->events[source_id]->get_raw2(),
457 session_data->events[source_id]->get_raw(),
458 tcp_close ? "True" : "False");
459 if (HttpTestManager::get_show_pegs())
460 {
461 print_peg_counts(output);
462 }
463 session_data->show(output);
464 fprintf(output, "\n");
465 }
466
print_peg_counts(FILE * output) const467 void HttpMsgSection::print_peg_counts(FILE* output) const
468 {
469 const PegInfo* const peg_names = HttpModule::get_peg_names();
470 const PegCount* const peg_counts = HttpModule::get_peg_counts();
471
472 fprintf(output, "Peg Counts\n");
473 for (unsigned k = 0; k < PEG_COUNT_MAX; k++)
474 {
475 if (peg_counts[k] > 0)
476 {
477 fprintf(output, "%s: %" PRIu64 "\n", peg_names[k].name, peg_counts[k]);
478 }
479 }
480 fprintf(output, "\n");
481 }
482
483 #endif
484
485