"true-client-ip" if both headers are present in the stream. The header names
should be delimited by a space.
+===== maximum_host_length
+
+Setting maximum_host_length causes http_inspect to generate 119:25 if the
+Host header value including optional white space exceeds the specified length.
+In the abnormal case of multiple Host headers, the total length of the combined
+values is used. The default value is -1, meaning do not perform this check.
+
+===== maximum_chunk_length
+
+http_inspect strictly limits individual chunks within a chunked message
+body to be less than four gigabytes.
+
+A lower limit may be configured by setting maximum_chunk_length. Any chunk
+longer than maximum chunk length will generate a 119:16 alert.
+
===== URI processing
Normalization and inspection of the URI in the HTTP request message is a
else
{
expected = expected * 16 + as_hex[buffer[k]];
- if (++digits_seen > 8)
+ if ((++digits_seen > 8) || (expected > maximum_chunk_length))
{
- // overflow protection: must fit into 32 bits
- *infractions += INF_CHUNK_TOO_LARGE;
- events->create_event(EVENT_BROKEN_CHUNK);
- transition_to_chunk_bad(accelerate_this_packet);
- k--;
+ // alert for exceeding configurable limit
+ *infractions += INF_CHUNK_OVER_MAXIMUM;
+ events->create_event(EVENT_LARGE_CHUNK);
+ if (digits_seen > 8)
+ {
+ // overflow protection: absolutely must fit into 32 bits
+ *infractions += INF_CHUNK_TOO_LARGE;
+ events->create_event(EVENT_BROKEN_CHUNK);
+ transition_to_chunk_bad(accelerate_this_packet);
+ k--;
+ }
}
if (expected != 0)
zero_chunk = false;
class HttpBodyChunkCutter : public HttpBodyCutter
{
public:
- HttpBodyChunkCutter(bool accelerated_blocking, ScriptFinder* finder,
- HttpEnums::CompressId compression, HttpFlowData* ssn_data) :
- HttpBodyCutter(accelerated_blocking, finder, compression, ssn_data)
+ HttpBodyChunkCutter(int64_t maximum_chunk_length_, bool accelerated_blocking,
+ ScriptFinder* finder, HttpEnums::CompressId compression, HttpFlowData* ssn_data) :
+ HttpBodyCutter(accelerated_blocking, finder, compression, ssn_data),
+ maximum_chunk_length(maximum_chunk_length_)
{}
HttpEnums::ScanResult cut(const uint8_t* buffer, uint32_t length,
HttpInfractions* infractions, HttpEventGen* events, uint32_t flow_target, bool stretch,
private:
void transition_to_chunk_bad(bool& accelerate_this_packet);
+ const int64_t maximum_chunk_length;
+
uint32_t data_seen = 0;
HttpEnums::ChunkState curr_state = HttpEnums::CHUNK_NEWLINES;
uint32_t expected = 0;
INF_JS_SHORTENED_TAG,
INF_JS_IDENTIFIER_OVERFLOW,
INF_JS_TMPL_NEST_OVFLOW,
+ INF_CHUNK_OVER_MAXIMUM,
+ INF_LONG_HOST_VALUE,
INF__MAX_VALUE
};
EVENT_DOUBLE_DECODE = 2,
EVENT_U_ENCODE = 3,
EVENT_BARE_BYTE = 4,
- // EVENT_OBSOLETE_BASE_36 = 5, // Previously used, do not reuse this number
+ // EVENT_BASE_36 = 5, // Retired. Do not reuse this number
EVENT_UTF_8 = 6,
EVENT_CODE_POINT_IN_URI = 7,
EVENT_MULTI_SLASH = 8,
EVENT_LF_WITHOUT_CR = 13,
EVENT_NON_RFC_CHAR = 14,
EVENT_OVERSIZE_DIR = 15,
- // EVENT_LARGE_CHUNK = 16,
- // EVENT_PROXY_USE = 17,
+ EVENT_LARGE_CHUNK = 16,
+ // EVENT_PROXY_USE = 17, // Retired. Do not reuse this number
EVENT_WEBROOT_DIR = 18,
EVENT_LONG_HDR = 19,
EVENT_MAX_HEADERS = 20,
EVENT_MULTIPLE_CONTLEN = 21,
- // EVENT_OBSOLETE_CHUNK_SIZE_MISMATCH = 22, // Previously used, do not reuse this number
- // EVENT_INVALID_TRUEIP = 23,
+ // EVENT_CHUNK_SIZE_MISMATCH = 22, // Retired. Do not reuse this number
+ // EVENT_INVALID_TRUEIP = 23, // Retired. Do not reuse this number
EVENT_MULTIPLE_HOST_HDRS = 24,
- // EVENT_LONG_HOSTNAME = 25,
- // EVENT_EXCEEDS_SPACES = 26,
- // EVENT_CONSECUTIVE_SMALL_CHUNKS = 27,
+ EVENT_LONG_HOSTNAME = 25,
+ // EVENT_EXCEEDS_SPACES = 26, // Retired. Do not reuse this number
+ // EVENT_CONSECUTIVE_SMALL_CHUNKS = 27, // Retired. Do not reuse this number
EVENT_UNBOUNDED_POST = 28,
- // EVENT_MULTIPLE_TRUEIP_IN_SESSION = 29,
- // EVENT_BOTH_TRUEIP_XFF_HDRS = 30,
+ // EVENT_MULTIPLE_TRUEIP_IN_SESSION = 29, // Retired. Do not reuse this number
+ // EVENT_BOTH_TRUEIP_XFF_HDRS = 30, // Retired. Do not reuse this number
EVENT_UNKNOWN_METHOD = 31,
EVENT_SIMPLE_REQUEST = 32,
EVENT_UNESCAPED_SPACE_URI = 33,
EVENT_PIPELINE_MAX = 34,
- // EVENT_OBSOLETE_ANOM_SERVER = 101, // Previously used, do not reuse this number
+ // EVENT_ANOM_SERVER = 101, // Retired. Do not reuse this number
EVENT_INVALID_STATCODE = 102,
- // EVENT_UNUSED_1 = 103,
+ // EVENT_UNUSED_1 = 103, // Retired. Do not reuse this number
EVENT_UTF_NORM_FAIL = 104,
EVENT_UTF7 = 105,
- // EVENT_DECOMPR_FAILED = 106,
- // EVENT_CONSECUTIVE_SMALL_CHUNKS_S = 107,
- // EVENT_UNUSED_2 = 108,
+ // EVENT_DECOMPR_FAILED = 106, // Retired. Do not reuse this number
+ // EVENT_CONSECUTIVE_SMALL_CHUNKS_S = 107, // Retired. Do not reuse this number
+ // EVENT_UNUSED_2 = 108, // Retired. Do not reuse this number
EVENT_JS_OBFUSCATION_EXCD = 109,
EVENT_JS_EXCESS_WS = 110,
EVENT_MIXED_ENCODINGS = 111,
{ "unzip", Parameter::PT_BOOL, nullptr, "true",
"decompress gzip and deflate message bodies" },
+ { "maximum_host_length", Parameter::PT_INT, "-1:max53", "-1",
+ "maximum allowed length for Host header value (-1 no limit)" },
+
+ { "maximum_chunk_length", Parameter::PT_INT, "0:4294967295", "4294967295",
+ "maximum allowed length for a message body chunk" },
+
{ "normalize_utf", Parameter::PT_BOOL, nullptr, "true",
"normalize charset utf encodings in response bodies" },
{
params->normalize_utf = val.get_bool();
}
+ else if (val.is("maximum_host_length"))
+ {
+ params->maximum_host_length = val.get_int64();
+ }
+ else if (val.is("maximum_chunk_length"))
+ {
+ params->maximum_chunk_length = val.get_int64();
+ }
else if (val.is("decompress_pdf"))
{
params->decompress_pdf = val.get_bool();
bool unzip = true;
bool normalize_utf = true;
+ int64_t maximum_host_length = -1;
+ int64_t maximum_chunk_length = 0xFFFFFFFF;
bool decompress_pdf = false;
bool decompress_swf = false;
bool decompress_zip = false;
if (source_id == SRC_CLIENT)
get_header_value_norm(HEAD_HOST);
+ // Host header value too long
+ if ((params->maximum_host_length != -1) && (source_id == SRC_CLIENT))
+ {
+ if (get_all_header_values_raw(HEAD_HOST).length() > params->maximum_host_length)
+ {
+ add_infraction(INF_LONG_HOST_VALUE);
+ create_event(EVENT_LONG_HOSTNAME);
+ }
+ }
+
// Content-Transfer-Encoding is a MIME header not sanctioned by HTTP. Which may not prevent
// some clients from recognizing it and applying a decoding that Snort does not expect.
if (get_header_count(HEAD_CONTENT_TRANSFER_ENCODING) > 0)
session_data->compression[source_id], session_data);
case SEC_BODY_CHUNK:
return (HttpCutter*)new HttpBodyChunkCutter(
+ my_inspector->params->maximum_chunk_length,
session_data->accelerated_blocking[source_id],
my_inspector->script_finder,
session_data->compression[source_id], session_data);
{ EVENT_DOUBLE_DECODE, "double decoding attack" },
{ EVENT_U_ENCODE, "u encoding" },
{ EVENT_BARE_BYTE, "bare byte unicode encoding" },
- // { EVENT_OBSOLETE_BASE_36, "obsolete event--deleted" },
{ EVENT_UTF_8, "UTF-8 encoding" },
{ EVENT_CODE_POINT_IN_URI, "unicode map code point encoding in URI" },
{ EVENT_MULTI_SLASH, "multi_slash encoding" },
{ EVENT_LF_WITHOUT_CR, "HTTP header line terminated by LF without a CR" },
{ EVENT_NON_RFC_CHAR, "non-RFC defined char" },
{ EVENT_OVERSIZE_DIR, "oversize request-uri directory" },
- // { EVENT_LARGE_CHUNK, "oversize chunk encoding" },
- // { EVENT_PROXY_USE, "unauthorized proxy use detected" },
+ { EVENT_LARGE_CHUNK, "oversize chunk encoding" },
{ EVENT_WEBROOT_DIR, "webroot directory traversal" },
{ EVENT_LONG_HDR, "long header" },
{ EVENT_MAX_HEADERS, "max header fields" },
{ EVENT_MULTIPLE_CONTLEN, "multiple content length" },
- // { EVENT_OBSOLETE_CHUNK_SIZE_MISMATCH, "obsolete event--deleted" },
- // { EVENT_INVALID_TRUEIP, "invalid IP in true-client-IP/XFF header" },
{ EVENT_MULTIPLE_HOST_HDRS, "Host header field appears more than once or has multiple "
"values" },
- // { EVENT_LONG_HOSTNAME, "hostname exceeds 255 characters" },
- // { EVENT_EXCEEDS_SPACES, "too much whitespace in header (not implemented yet)" },
- // { EVENT_CONSECUTIVE_SMALL_CHUNKS, "client consecutive small chunk sizes" },
+ { EVENT_LONG_HOSTNAME, "Host header value is too long" },
{ EVENT_UNBOUNDED_POST, "POST or PUT w/o content-length or chunks" },
- // { EVENT_MULTIPLE_TRUEIP_IN_SESSION, "multiple true ips in a session" },
- // { EVENT_BOTH_TRUEIP_XFF_HDRS, "both true-client-IP and XFF hdrs present" },
{ EVENT_UNKNOWN_METHOD, "unknown method" },
{ EVENT_SIMPLE_REQUEST, "simple request" },
{ EVENT_UNESCAPED_SPACE_URI, "unescaped space in HTTP URI" },
{ EVENT_PIPELINE_MAX, "too many pipelined requests" },
- // { EVENT_OBSOLETE_ANOM_SERVER, "obsolete event--deleted" },
{ EVENT_INVALID_STATCODE, "invalid status code in HTTP response" },
- // { EVENT_UNUSED_1, "unused event number--should not appear" },
{ EVENT_UTF_NORM_FAIL, "HTTP response has UTF charset that failed to normalize" },
{ EVENT_UTF7, "HTTP response has UTF-7 charset" },
- // { EVENT_DECOMPR_FAILED, "HTTP response gzip decompression failed" },
- // { EVENT_CONSECUTIVE_SMALL_CHUNKS_S, "server consecutive small chunk sizes" },
- // { EVENT_UNUSED_2, "unused event number--should not appear" },
{ EVENT_JS_OBFUSCATION_EXCD, "javascript obfuscation levels exceeds 1" },
{ EVENT_JS_EXCESS_WS, "javascript whitespaces exceeds max allowed" },
{ EVENT_MIXED_ENCODINGS, "multiple encodings within javascript obfuscated data" },