#define UNIFIED2_EVENT3 114
#define MAX_EVENT_APPNAME_LEN 64
+#define MAX_HTTP_METHOD_LEN 80
+#define MAX_HTTP_VERSION_LEN 16
+#define MAX_HTTP_USER_AGENT_LEN 256
+#define MAX_HTTP_REFERER_LEN 256
+#define MAX_MESSAGE_DETAIL_LEN 256
/* Data structure used for serialization of Unified2 Records */
struct Serial_Unified2_Header
uint8_t snort_action; // pass=0, drop, block, reset
char app_name[MAX_EVENT_APPNAME_LEN];
+
+ uint32_t request_size;
+ uint32_t response_size;
+
+ char http_method[MAX_HTTP_METHOD_LEN];
+ char http_version[MAX_HTTP_VERSION_LEN];
+ char http_user_agent[MAX_HTTP_USER_AGENT_LEN];
+ char http_referer[MAX_HTTP_REFERER_LEN];
+ char message_detail[MAX_MESSAGE_DETAIL_LEN];
};
// UNIFIED2_IDS_EVENT_VLAN = type 104
u2_event.snort_status = p->active->get_status();
u2_event.snort_action = p->active->get_action();
+
+ if ( p->flow && p->flow->gadget )
+ {
+ Inspector* gadget = p->flow->gadget;
+ InspectionBuffer buf;
+
+ if ( gadget->get_buf("http_method_str", p, buf) )
+ strncpy(u2_event.http_method,
+ reinterpret_cast<const char*>(buf.data), MAX_HTTP_METHOD_LEN - 1);
+
+ if ( gadget->get_buf("request_size", p, buf) )
+ u2_event.request_size = htonl(*reinterpret_cast<const uint32_t*>(buf.data));
+
+ if ( gadget->get_buf("response_size", p, buf) )
+ u2_event.response_size = htonl(*reinterpret_cast<const uint32_t*>(buf.data));
+
+ if ( gadget->get_buf("http_version_str", p, buf) )
+ strncpy(u2_event.http_version,
+ reinterpret_cast<const char*>(buf.data), MAX_HTTP_VERSION_LEN - 1);
+
+ if ( gadget->get_buf("http_user_agent_str", p, buf) )
+ strncpy(u2_event.http_user_agent,
+ reinterpret_cast<const char*>(buf.data), MAX_HTTP_USER_AGENT_LEN - 1);
+
+ if ( gadget->get_buf("http_referer_str", p, buf) )
+ strncpy(u2_event.http_referer,
+ reinterpret_cast<const char*>(buf.data), MAX_HTTP_REFERER_LEN - 1);
+
+ std::string message_detail = "detail_" + std::to_string(gid) + "_" + std::to_string(sid);
+ if ( gadget->get_buf(message_detail.c_str(), p, buf) )
+ strncpy(u2_event.message_detail,
+ reinterpret_cast<const char*>(buf.data), MAX_MESSAGE_DETAIL_LEN - 1);
+ }
}
Serial_Unified2_Header hdr;
tcp_close(false)
{}
void HttpMsgSection::clear(){}
+void HttpMsgSection::clear_tmp_buffers() { }
bool HttpMsgSection::run_detection(snort::Packet*) { return false; }
void HttpMsgHeadShared::analyze() {}
"http_uri", \
"http_version", \
"js_data", \
- "vba_data"
+ "vba_data", \
+ "http_method_str", \
+ "request_size", \
+ "response_size", \
+ "http_version_str", \
+ "http_user_agent_str", \
+ "http_referer_str", \
+ "detail_119_20", \
+ "detail_119_287"
class HttpApi
{
HTTP_BUFFER_RAW_TRAILER, HTTP_BUFFER_RAW_URI, HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG,
HTTP_BUFFER_TRAILER, HTTP_BUFFER_TRUE_IP, HTTP_BUFFER_URI, HTTP_BUFFER_VERSION,
BUFFER_JS_DATA, BUFFER_VBA_DATA, HTTP__BUFFER_MAX = BUFFER_VBA_DATA,
+ HTTP_BUFFER_METHOD_STR, BUFFER_REQUEST_SIZE, BUFFER_RESPONSE_SIZE,
+ HTTP_BUFFER_VERSION_STR, HTTP_BUFFER_USER_AGENT_STR, HTTP_BUFFER_REFERER_STR,
+ DETAIL_119_20, DETAIL_119_287,
+ HTTP__TMP_BUFFER_MAX = DETAIL_119_287,
HTTP_RANGE_NUM_HDRS, HTTP_RANGE_NUM_TRAILERS, HTTP_VERSION_MATCH,
HTTP_HEADER_TEST, HTTP_TRAILER_TEST, HTTP_RANGE_NUM_COOKIES, HTTP_RANGE_MAX_HEADER_LINE,
HTTP_RANGE_MAX_TRAILER_LINE, HTTP__MAX_RULE_OPTION };
discard_list = discard_list->next;
delete tmp;
}
+
+ HttpMsgSection::clear_tmp_buffers();
}
void HttpFlowData::half_reset(SourceId source_id)
const Field& get_all_header_values_raw(HttpEnums::HeaderId header_id);
const Field& get_header_value_norm(HttpEnums::HeaderId header_id);
int get_header_count(HttpEnums::HeaderId header_id) const;
+ uint32_t get_length() const override
+ // +4 to account for \r\n\r\n at the end of the section that was removed by the splitter
+ { auto len = HttpMsgSection::get_length(); return (len > 0) ? len + 4 : 0; }
// Tables of header field names and header value names
static const StrCode header_list[];
using namespace HttpEnums;
using namespace snort;
+static constexpr uint TMP_BUFFER_CNT = HTTP__TMP_BUFFER_MAX - HTTP__BUFFER_MAX;
+THREAD_LOCAL Field* tmp_buffers[TMP_BUFFER_CNT] = { nullptr };
+
+void HttpMsgSection::clear_tmp_buffers()
+{
+ for (unsigned i = 0; i < TMP_BUFFER_CNT; i++)
+ {
+ delete tmp_buffers[i];
+ tmp_buffers[i] = nullptr;
+ }
+}
+
+static Field* tmp_field_from_data(const uint8_t* data, uint32_t len)
+{
+ uint8_t* val_buf = new uint8_t[len + 1];
+ memcpy(val_buf, data, len);
+ val_buf[len] = '\0';
+ return new Field(len + 1, val_buf, true);
+}
+
+static Field* tmp_field(uint32_t val)
+{
+ uint32_t* val_buf = new uint32_t[1];
+ *val_buf = val;
+ return new Field(sizeof(uint32_t), reinterpret_cast<uint8_t*>(val_buf), true);
+}
+
+static Field* tmp_field(const std::string& str)
+{
+ return tmp_field_from_data(reinterpret_cast<const uint8_t*>(str.c_str()), str.length());
+}
+
+static Field* tmp_field(const Field& f)
+{
+ int32_t len = f.length();
+ if (len <= 0)
+ return new Field(STAT_NOT_PRESENT);
+
+ const uint8_t* data = f.start();
+ const uint8_t* end = data + len;
+ const uint8_t* p = data;
+ for (; p < end; ++p)
+ {
+ uint8_t c = *p;
+ if (c < 0x20 || c > 0x7E || c == '\\')
+ break;
+ }
+
+ if (p == end)
+ return tmp_field_from_data(data, len); // No escaping needed
+
+ static constexpr char hex_chars[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ std::string escaped;
+ escaped.reserve(len * 2); // Will grow if needed
+ escaped.append(reinterpret_cast<const char*>(data), p - data);
+
+ for (; p < end; ++p)
+ {
+ uint8_t c = *p;
+
+ if (c == '\\')
+ escaped.append("\\x5c");
+ else if (c < 0x20 || c > 0x7E)
+ {
+ escaped.append("\\x");
+ escaped.push_back(hex_chars[(c >> 4) & 0x0F]);
+ escaped.push_back(hex_chars[c & 0x0F]);
+ }
+ else
+ escaped.push_back(c);
+ }
+
+ return tmp_field_from_data(reinterpret_cast<const uint8_t*>(escaped.c_str()), escaped.length());
+}
+
+Field* HttpMsgSection::compute_http_method_str(const HttpBufferInfo&)
+{
+ return tmp_field(get_classic_buffer(HTTP_BUFFER_METHOD, 0, 0));
+}
+
+Field* HttpMsgSection::compute_request_size(const HttpBufferInfo&)
+{
+ uint32_t val = 0;
+ val += get_section_len(request);
+ val += get_section_len(header[SRC_CLIENT]);
+ val += transaction->get_body_len(HttpCommon::SRC_CLIENT);
+ val += get_section_len(trailer[SRC_CLIENT]);
+ return tmp_field(val);
+}
+
+Field* HttpMsgSection::compute_response_size(const HttpBufferInfo&)
+{
+ uint32_t val = 0;
+ val += get_section_len(status);
+ val += get_section_len(header[SRC_SERVER]);
+ val += transaction->get_body_len(HttpCommon::SRC_SERVER);
+ val += get_section_len(trailer[SRC_SERVER]);
+ return tmp_field(val);
+}
+
+Field* HttpMsgSection::compute_http_version_str(const HttpBufferInfo& buf)
+{
+ VersionId version = get_version_id(buf);
+ const auto& iter = VersionEnumToStr.find(version);
+ if (iter == VersionEnumToStr.end())
+ return new Field(STAT_NOT_PRESENT);
+
+ std::string val = "HTTP/";
+ val.append(iter->second);
+ return tmp_field(val);
+}
+
+Field* HttpMsgSection::compute_http_user_agent_str(const HttpBufferInfo&)
+{
+ return tmp_field(get_classic_buffer(HTTP_BUFFER_HEADER, HEAD_USER_AGENT, 0));
+}
+
+Field* HttpMsgSection::compute_http_referer_str(const HttpBufferInfo&)
+{
+ return tmp_field(get_classic_buffer(HTTP_BUFFER_HEADER, HEAD_REFERER, 0));
+}
+
+Field* HttpMsgSection::compute_detail_119_20(const HttpBufferInfo& buf)
+{
+ // EVENT_MAX_HEADERS
+ // Header Count: XXX
+ std::string val = "Header Count: ";
+ auto cnt = get_num_headers(buf);
+ if (cnt >= 0)
+ val.append(std::to_string(cnt));
+ else
+ {
+ val.append("<no header ");
+ val.append(std::to_string(cnt));
+ val.append(">");
+ }
+
+ return tmp_field(val);
+}
+
+Field* HttpMsgSection::compute_detail_119_287(const HttpBufferInfo&)
+{
+ // EVENT_DISALLOWED_METHOD
+ // HTTP Method: XXX
+ std::string val = "HTTP Method: ";
+ const Field& method = get_classic_buffer(HTTP_BUFFER_METHOD, 0, 0);
+ if (method.length() > 0)
+ val.append(reinterpret_cast<const char*>(method.start()), method.length());
+ else
+ {
+ val.append("<no method ");
+ val.append(std::to_string(method.length()));
+ val.append(">");
+ }
+
+ return tmp_field(val);
+}
+
+const Field& HttpMsgSection::get_tmp_buffer(const HttpBufferInfo& buf)
+{
+ typedef Field* (HttpMsgSection::*ComputeFunction)(const HttpBufferInfo&);
+
+ static const ComputeFunction compute_functions[TMP_BUFFER_CNT] = {
+ &HttpMsgSection::compute_http_method_str, // HTTP_BUFFER_METHOD_STR
+ &HttpMsgSection::compute_request_size, // BUFFER_REQUEST_SIZE
+ &HttpMsgSection::compute_response_size, // BUFFER_RESPONSE_SIZE
+ &HttpMsgSection::compute_http_version_str, // HTTP_BUFFER_VERSION_STR
+ &HttpMsgSection::compute_http_user_agent_str, // HTTP_BUFFER_USER_AGENT_STR
+ &HttpMsgSection::compute_http_referer_str, // HTTP_BUFFER_REFERER_STR
+ &HttpMsgSection::compute_detail_119_20, // DETAIL_119_20, EVENT_MAX_HEADERS
+ &HttpMsgSection::compute_detail_119_287 // DETAIL_119_287, EVENT_DISALLOWED_METHOD
+ };
+
+ const unsigned index = buf.type - (HTTP__BUFFER_MAX + 1);
+ assert(index < TMP_BUFFER_CNT);
+
+ if (tmp_buffers[index] == nullptr)
+ tmp_buffers[index] = (this->*compute_functions[index])(buf);
+
+ assert(tmp_buffers[index] != nullptr);
+ return *tmp_buffers[index];
+}
+
HttpMsgSection::HttpMsgSection(const uint8_t* buffer, const uint16_t buf_size,
HttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
const HttpParaList* params_) :
return Field::FIELD_NULL;
}
default:
- assert(buf.type <= HTTP__BUFFER_MAX);
+ if (buf.type <= HTTP__BUFFER_MAX)
+ return Field::FIELD_NULL;
+ else if (buf.type <= HTTP__TMP_BUFFER_MAX)
+ return get_tmp_buffer(buf);
+ assert(false);
return Field::FIELD_NULL;
}
}
void HttpMsgSection::clear()
{
+ clear_tmp_buffers();
transaction->clear_section();
cleared = true;
}
int32_t get_status_code_num() const { return status_code_num; }
+ static void clear_tmp_buffers();
virtual void clear();
bool is_clear() { return cleared; }
int32_t get_num_cookies(const HttpBufferInfo& buf) const;
HttpEnums::VersionId get_version_id(const HttpBufferInfo& buf) const;
+ static uint32_t get_section_len(const HttpMsgSection* sec)
+ { return (sec != nullptr) ? sec->get_length() : 0; }
+ virtual uint32_t get_length() const
+ { return (msg_text.length() > 0) ? msg_text.length() : 0; }
+
HttpMsgSection* next = nullptr;
#ifdef REG_TEST
void print_section_wrapup(FILE* output) const;
void print_peg_counts(FILE* output) const;
#endif
+
+private:
+ const Field& get_tmp_buffer(const HttpBufferInfo& buf);
+ Field* compute_http_method_str(const HttpBufferInfo& buf);
+ Field* compute_request_size(const HttpBufferInfo& buf);
+ Field* compute_response_size(const HttpBufferInfo& buf);
+ Field* compute_http_version_str(const HttpBufferInfo& buf);
+ Field* compute_http_user_agent_str(const HttpBufferInfo& buf);
+ Field* compute_http_referer_str(const HttpBufferInfo& buf);
+ Field* compute_detail_119_20(const HttpBufferInfo& buf);
+ Field* compute_detail_119_287(const HttpBufferInfo& buf);
};
#endif
bool detection_required() const override { return false; }
const Field& get_version() const { return version; }
HttpEnums::VersionId get_version_id() const { return version_id; }
+ uint32_t get_length() const override
+ // +2 to account for \r\n at the end of the section that was removed by the splitter
+ { auto len = HttpMsgSection::get_length(); return (len > 0) ? len + 2 : 0; }
protected:
HttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
#include "service_inspectors/http_inspect/http_flow_data.h"
#include "service_inspectors/http_inspect/http_inspect.h"
#include "service_inspectors/http_inspect/http_module.h"
+#include "service_inspectors/http_inspect/http_msg_section.h"
#include "service_inspectors/http_inspect/http_transaction.h"
#include "service_inspectors/http2_inspect/http2_flow_data.h"
}
bool HttpStreamSplitter::finish(snort::Flow*) { return false; }
void HttpStreamSplitter::prep_partial_flush(snort::Flow*, uint32_t, uint32_t, uint32_t) { }
+void HttpMsgSection::clear_tmp_buffers() { }
THREAD_LOCAL PegCount HttpModule::peg_counts[PEG_COUNT_MAX] = { };
const Field Field::FIELD_NULL { STAT_NO_SOURCE };
printf("\tApp Name: %s\n", event.app_name[0] ? event.app_name : "none");
+ if (event.http_method[0])
+ printf("\tHTTP Method: %s\n", event.http_method);
+ if (event.request_size)
+ printf("\tRequest Size: %u\n", htonl(event.request_size));
+ if (event.response_size)
+ printf("\tResponse Size: %u\n", htonl(event.response_size));
+ if (event.http_version[0])
+ printf("\tHTTP Version: %s\n", event.http_version);
+ if (event.http_user_agent[0])
+ printf("\tHTTP User-Agent: %s\n", event.http_user_agent);
+ if (event.http_referer[0])
+ printf("\tHTTP Referer: %s\n", event.http_referer);
+ if (event.message_detail[0])
+ printf("\tMessage Detail: %s\n", event.message_detail);
+
printf(
"\tStatus: %s\tAction: %s\n",
get_status(event.snort_status), get_action(event.snort_action));