00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 //
00004 // This program is free software; you can redistribute it and/or modify it
00005 // under the terms of the GNU General Public License Version 2 as published
00006 // by the Free Software Foundation. You may not use, modify or distribute
00007 // this program under any other version of the GNU General Public License.
00008 //
00009 // This program is distributed in the hope that it will be useful, but
00010 // WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program; if not, write to the Free Software Foundation, Inc.,
00016 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 //--------------------------------------------------------------------------
00018 // http_inspect.cc author Tom Peters <thopeter@cisco.com>
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include "config.h"
00022 #endif
00023
00024 #include "http_inspect.h"
00025
00026 #include "detection/detection_engine.h"
00027 #include "http_js_norm.h"
00028 #include "http_msg_body.h"
00029 #include "http_msg_body_chunk.h"
00030 #include "http_msg_body_cl.h"
00031 #include "http_msg_body_old.h"
00032 #include "http_msg_header.h"
00033 #include "http_msg_request.h"
00034 #include "http_msg_status.h"
00035 #include "http_msg_trailer.h"
00036 #include "http_test_manager.h"
00037 #include "log/unified2.h"
00038 #include "protocols/packet.h"
00039 #include "stream/stream.h"
00040 #include "main/snort_debug.h"
00041
00042 using namespace HttpEnums;
00043
00044 uint32_t HttpInspect::xtra_trueip_id;
00045 uint32_t HttpInspect::xtra_uri_id;
00046 uint32_t HttpInspect::xtra_host_id;
00047 uint32_t HttpInspect::xtra_jsnorm_id;
00048
00049 HttpInspect::HttpInspect(const HttpParaList* params_) : params(params_)
00050 {
00051 #ifdef REG_TEST
00052 if (params->test_input)
00053 {
00054 HttpTestManager::activate_test_input();
00055 }
00056 if (params->test_output)
00057 {
00058 HttpTestManager::activate_test_output();
00059 }
00060 HttpTestManager::set_print_amount(params->print_amount);
00061 HttpTestManager::set_print_hex(params->print_hex);
00062 HttpTestManager::set_show_pegs(params->show_pegs);
00063 HttpTestManager::set_show_scan(params->show_scan);
00064 #endif
00065 }
00066
00067 bool HttpInspect::configure(SnortConfig* )
00068 {
00069 if (params->js_norm_param.normalize_javascript)
00070 params->js_norm_param.js_norm->configure();
00071
00072 xtra_trueip_id = Stream::reg_xtra_data_cb(get_xtra_trueip);
00073 xtra_uri_id = Stream::reg_xtra_data_cb(get_xtra_uri);
00074 xtra_host_id = Stream::reg_xtra_data_cb(get_xtra_host);
00075 xtra_jsnorm_id = Stream::reg_xtra_data_cb(get_xtra_jsnorm);
00076
00077 return true;
00078 }
00079
00080 InspectSection HttpInspect::get_latest_is(const Packet* p)
00081 {
00082 const HttpFlowData* const session_data =
00083 (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::inspector_id);
00084
00085 if ((session_data == nullptr) || (session_data->latest_section == nullptr))
00086 return HttpEnums::IS_NONE;
00087
00088 return session_data->latest_section->get_inspection_section();
00089 }
00090
00091 SourceId HttpInspect::get_latest_src(const Packet* p)
00092 {
00093 const HttpFlowData* const session_data =
00094 (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::inspector_id);
00095
00096 if ((session_data == nullptr) || (session_data->latest_section == nullptr))
00097 return HttpEnums::SRC__NOT_COMPUTE;
00098
00099 return session_data->latest_section->get_source_id();
00100 }
00101
00102 bool HttpInspect::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
00103 {
00104 switch (ibt)
00105 {
00106 case InspectionBuffer::IBT_KEY:
00107 return http_get_buf(HTTP_BUFFER_URI, 0, 0, p, b);
00108 case InspectionBuffer::IBT_HEADER:
00109 if (get_latest_is(p) == IS_TRAILER)
00110 return http_get_buf(HTTP_BUFFER_TRAILER, 0, 0, p, b);
00111 else
00112 return http_get_buf(HTTP_BUFFER_HEADER, 0, 0, p, b);
00113 case InspectionBuffer::IBT_BODY:
00114 return http_get_buf(HTTP_BUFFER_CLIENT_BODY, 0, 0, p, b);
00115 default:
00116 return false;
00117 }
00118 }
00119
00120 bool HttpInspect::get_buf(unsigned id, Packet* p, InspectionBuffer& b)
00121 {
00122 return http_get_buf(id, 0, 0, p, b);
00123 }
00124
00125 bool HttpInspect::http_get_buf(unsigned id, uint64_t sub_id, uint64_t form, Packet* p,
00126 InspectionBuffer& b)
00127 {
00128 const HttpFlowData* const session_data =
00129 (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::inspector_id);
00130
00131 if ((session_data == nullptr) || (session_data->latest_section == nullptr))
00132 return false;
00133
00134 const Field& buffer = session_data->latest_section->get_classic_buffer(id, sub_id, form);
00135
00136 if (buffer.length() <= 0)
00137 return false;
00138
00139 b.data = buffer.start();
00140 b.len = buffer.length();
00141 return true;
00142 }
00143
00144 bool HttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
00145 {
00146 // Fast pattern buffers only supplied at specific times
00147 switch (ibt)
00148 {
00149 case InspectionBuffer::IBT_KEY:
00150 if ((get_latest_is(p) != IS_DETECTION) || (get_latest_src(p) != SRC_CLIENT))
00151 return false;
00152 break;
00153 case InspectionBuffer::IBT_HEADER:
00154 if ((get_latest_is(p) != IS_DETECTION) && (get_latest_is(p) != IS_TRAILER))
00155 return false;
00156 break;
00157 case InspectionBuffer::IBT_BODY:
00158 if ((get_latest_is(p) != IS_DETECTION) && (get_latest_is(p) != IS_BODY))
00159 return false;
00160 break;
00161 default:
00162 return false;
00163 }
00164 return get_buf(ibt, p, b);
00165 }
00166
00167 int HttpInspect::get_xtra_trueip(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
00168 {
00169 const HttpFlowData* const session_data =
00170 (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
00171
00172 if ((session_data == nullptr) || (session_data->latest_section == nullptr))
00173 return 0;
00174
00175 const HttpTransaction* const transaction = session_data->latest_section->get_transaction();
00176 HttpMsgHeader* const req_header = transaction->get_header(SRC_CLIENT);
00177 if (req_header == nullptr)
00178 return 0;
00179 const Field& true_ip = req_header->get_true_ip();
00180 if (true_ip.length() <= 0)
00181 return 0;
00182
00183 *buf = const_cast<uint8_t*>(true_ip.start());
00184 *len = true_ip.length();
00185 *type = (*len == 4) ? EVENT_INFO_XFF_IPV4 : EVENT_INFO_XFF_IPV6;
00186 return 1;
00187 }
00188
00189 int HttpInspect::get_xtra_uri(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
00190 {
00191 const HttpFlowData* const session_data =
00192 (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
00193
00194 if ((session_data == nullptr) || (session_data->latest_section == nullptr))
00195 return 0;
00196
00197 const HttpTransaction* const transaction = session_data->latest_section->get_transaction();
00198 HttpMsgRequest* const request = transaction->get_request();
00199 if (request == nullptr)
00200 return 0;
00201 const Field& uri = request->get_uri();
00202 if (uri.length() <= 0)
00203 return 0;
00204
00205 *buf = const_cast<uint8_t*>(uri.start());
00206 *len = uri.length();
00207 *type = EVENT_INFO_HTTP_URI;
00208
00209 return 1;
00210 }
00211
00212 int HttpInspect::get_xtra_host(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
00213 {
00214 const HttpFlowData* const session_data =
00215 (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
00216
00217 if ((session_data == nullptr) || (session_data->latest_section == nullptr))
00218 return 0;
00219
00220 const HttpTransaction* const transaction = session_data->latest_section->get_transaction();
00221 HttpMsgHeader* const req_header = transaction->get_header(SRC_CLIENT);
00222 if (req_header == nullptr)
00223 return 0;
00224 const Field& host = req_header->get_header_value_norm(HEAD_HOST);
00225 if (host.length() <= 0)
00226 return 0;
00227
00228 *buf = const_cast<uint8_t*>(host.start());
00229 *len = host.length();
00230 *type = EVENT_INFO_HTTP_HOSTNAME;
00231
00232 return 1;
00233 }
00234
00235 // The name of this method reflects its legacy purpose. We actually return the normalized data
00236 // from a response message body which may include other forms of normalization in addition to
00237 // JavaScript normalization. But if you don't turn JavaScript normalization on you get nothing.
00238 int HttpInspect::get_xtra_jsnorm(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
00239 {
00240 const HttpFlowData* const session_data =
00241 (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
00242
00243 if ((session_data == nullptr) || (session_data->latest_section == nullptr) ||
00244 (session_data->latest_section->get_source_id() != SRC_SERVER) ||
00245 !session_data->latest_section->get_params()->js_norm_param.normalize_javascript)
00246 return 0;
00247
00248 const HttpTransaction* const transaction = session_data->latest_section->get_transaction();
00249 HttpMsgBody* const body = transaction->get_body();
00250 if (body == nullptr)
00251 return 0;
00252 assert((void*)body == (void*)session_data->latest_section);
00253 const Field& detect_data = body->get_detect_data();
00254 if (detect_data.length() <= 0)
00255 return 0;
00256
00257 *buf = const_cast<uint8_t*>(detect_data.start());
00258 *len = detect_data.length();
00259 *type = EVENT_INFO_JSNORM_DATA;
00260
00261 return 1;
00262 }
00263
00264 void HttpInspect::eval(Packet* p)
00265 {
00266 const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER;
00267
00268 HttpFlowData* session_data =
00269 (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::inspector_id);
00270
00271 // FIXIT-H Workaround for unexpected eval() calls
00272 if (session_data->section_type[source_id] == SEC__NOT_COMPUTE)
00273 return;
00274
00275
00276 new_invoked_inspector(21, p, 0);
00277
00278 const int remove_workaround = session_data->zero_byte_workaround[source_id] ? 1 : 0;
00279 if (!process(p->data, p->dsize - remove_workaround, p->flow, source_id, true, p))
00280 {
00281 DetectionEngine::disable_content(p);
00282 }
00283 #ifdef REG_TEST
00284 else
00285 {
00286 if (HttpTestManager::use_test_output())
00287 {
00288 fprintf(HttpTestManager::get_output_file(), "Sent to detection %hu octets\n\n",
00289 p->dsize);
00290 fflush(HttpTestManager::get_output_file());
00291 }
00292 }
00293 #endif
00294
00295 // Whenever we process a packet we set these flags. If someone asks for an extra data
00296 // buffer the JIT code will figure out if we actually have it.
00297 SetExtraData(p, xtra_trueip_id);
00298 SetExtraData(p, xtra_uri_id);
00299 SetExtraData(p, xtra_host_id);
00300 SetExtraData(p, xtra_jsnorm_id);
00301 }
00302
00303 bool HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow,
00304 SourceId source_id, bool buf_owner, Packet* packet) const
00305 {
00306 HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
00307 assert(session_data != nullptr);
00308
00309 HttpModule::increment_peg_counts(PEG_INSPECT);
00310
00311 switch (session_data->section_type[source_id])
00312 {
00313 case SEC_REQUEST:
00314 session_data->latest_section = new HttpMsgRequest(
00315 data, dsize, session_data, source_id, buf_owner, flow, params);
00316 break;
00317 case SEC_STATUS:
00318 session_data->latest_section = new HttpMsgStatus(
00319 data, dsize, session_data, source_id, buf_owner, flow, params);
00320 break;
00321 case SEC_HEADER:
00322 session_data->latest_section = new HttpMsgHeader(
00323 data, dsize, session_data, source_id, buf_owner, flow, params);
00324 break;
00325 case SEC_BODY_CL:
00326 session_data->latest_section = new HttpMsgBodyCl(
00327 data, dsize, session_data, source_id, buf_owner, flow, params);
00328 break;
00329 case SEC_BODY_OLD:
00330 session_data->latest_section = new HttpMsgBodyOld(
00331 data, dsize, session_data, source_id, buf_owner, flow, params);
00332 break;
00333 case SEC_BODY_CHUNK:
00334 session_data->latest_section = new HttpMsgBodyChunk(
00335 data, dsize, session_data, source_id, buf_owner, flow, params);
00336 break;
00337 case SEC_TRAILER:
00338 session_data->latest_section = new HttpMsgTrailer(
00339 data, dsize, session_data, source_id, buf_owner, flow, params);
00340 break;
00341 default:
00342 assert(false);
00343 if (buf_owner)
00344 {
00345 delete[] data;
00346 }
00347 return false;
00348 }
00349
00350 session_data->latest_section->analyze();
00351 session_data->latest_section->gen_events();
00352
00353 if (packet) {
00354 int type;
00355 if (packet->is_from_client()) type = session_data->get_section_type(0);
00356 else if (packet->is_from_server()) type = session_data->get_section_type(1);
00357
00358 add_http_section_type(packet, type);
00359 }
00360
00361 session_data->latest_section->update_flow();
00362
00363 #ifdef REG_TEST
00364 if (HttpTestManager::use_test_output())
00365 {
00366 session_data->latest_section->print_section(HttpTestManager::get_output_file());
00367 fflush(HttpTestManager::get_output_file());
00368 if (HttpTestManager::use_test_input())
00369 {
00370 printf("Finished processing section from test %" PRIi64 "\n",
00371 HttpTestManager::get_test_number());
00372 }
00373 fflush(stdout);
00374 }
00375 #endif
00376
00377 session_data->latest_section->publish();
00378 return session_data->latest_section->detection_required();
00379 }
00380
00381 void HttpInspect::clear(Packet* p)
00382 {
00383 HttpFlowData* const session_data =
00384 (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::inspector_id);
00385
00386 if (session_data == nullptr)
00387 return;
00388 session_data->latest_section = nullptr;
00389
00390 const SourceId source_id = (p->is_from_client()) ? SRC_CLIENT : SRC_SERVER;
00391
00392 if (session_data->transaction[source_id] == nullptr)
00393 return;
00394
00395 // If current transaction is complete then we are done with it and should reclaim the space
00396 if ((source_id == SRC_SERVER) && (session_data->type_expected[SRC_SERVER] == SEC_STATUS) &&
00397 session_data->transaction[SRC_SERVER]->final_response())
00398 {
00399 HttpTransaction::delete_transaction(session_data->transaction[SRC_SERVER]);
00400 session_data->transaction[SRC_SERVER] = nullptr;
00401 }
00402 else
00403 {
00404 // Get rid of most recent body section if present
00405 session_data->transaction[source_id]->set_body(nullptr);
00406 }
00407 }
00408
END OF CODE