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