|
|
|
/* Copyright (C) 2007-2011 Open Information Security Foundation
|
|
|
|
*
|
|
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
|
|
* the GNU General Public License version 2 as published by the Free
|
|
|
|
* Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \defgroup httplayer HTTP layer support
|
|
|
|
*
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \file
|
|
|
|
*
|
|
|
|
* \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
|
|
|
|
* \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
|
|
|
|
*
|
|
|
|
* This file provides a HTTP protocol support for the engine using HTP library.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __APP_LAYER_HTP_H__
|
|
|
|
#define __APP_LAYER_HTP_H__
|
|
|
|
|
|
|
|
#include "util-radix-tree.h"
|
|
|
|
#include "util-file.h"
|
|
|
|
#include "app-layer-htp-mem.h"
|
|
|
|
#include "detect-engine-state.h"
|
|
|
|
#include "util-streaming-buffer.h"
|
|
|
|
|
|
|
|
#include <htp/htp.h>
|
|
|
|
|
|
|
|
/* default request body limit */
|
|
|
|
#define HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT 4096U
|
|
|
|
#define HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT 4096U
|
|
|
|
#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE 32768U
|
|
|
|
#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW 4096U
|
|
|
|
#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE 32768U
|
|
|
|
#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW 4096U
|
|
|
|
#define HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT 9000U
|
|
|
|
#define HTP_CONFIG_DEFAULT_FIELD_LIMIT_HARD 18000U
|
|
|
|
|
|
|
|
#define HTP_CONFIG_DEFAULT_RANDOMIZE 1
|
|
|
|
#define HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE 10
|
|
|
|
|
|
|
|
/** a boundary should be smaller in size */
|
|
|
|
#define HTP_BOUNDARY_MAX 200U
|
|
|
|
|
file handling: expand filestore keyword
Filestore keyword by default (... filestore; ... ) marks only the file in the
same direction as the rule match for storing. This makes sense when inspecting
individual files (filemagic, filename, etc) but not so much when looking at
suspicious file requests, where the actual file is in the response.
The filestore keyword now takes 2 optional options:
filestore:<direction>,<scope>;
By default the direction is "same as rule match", and scope is "currently
inspected file".
For direction the following values are possible: "request" and "to_server",
"response" and "to_client", "both".
For scope the following values are possible: "tx" for all files in the current
HTTP/1.1 transation, "ssn" and "flow" for all files in the session/flow.
For the above case, where a suspious request should lead to a response file
download, this would work:
alert http ... content:"/suspicious/"; http_uri; filestore:response; ...
14 years ago
|
|
|
#define HTP_FLAG_STATE_OPEN 0x0001 /**< Flag to indicate that HTTP
|
|
|
|
connection is open */
|
|
|
|
#define HTP_FLAG_STATE_CLOSED_TS 0x0002 /**< Flag to indicate that HTTP
|
|
|
|
connection is closed */
|
|
|
|
#define HTP_FLAG_STATE_CLOSED_TC 0x0004 /**< Flag to indicate that HTTP
|
|
|
|
connection is closed */
|
|
|
|
#define HTP_FLAG_STATE_DATA 0x0008 /**< Flag to indicate that HTTP
|
|
|
|
connection needs more data */
|
|
|
|
#define HTP_FLAG_STATE_ERROR 0x0010 /**< Flag to indicate that an error
|
|
|
|
has been occured on HTTP
|
|
|
|
connection */
|
|
|
|
#define HTP_FLAG_NEW_BODY_SET 0x0020 /**< Flag to indicate that HTTP
|
|
|
|
has parsed a new body (for
|
|
|
|
pcre) */
|
|
|
|
#define HTP_FLAG_STORE_FILES_TS 0x0040
|
|
|
|
#define HTP_FLAG_STORE_FILES_TC 0x0080
|
|
|
|
#define HTP_FLAG_STORE_FILES_TX_TS 0x0100
|
|
|
|
#define HTP_FLAG_STORE_FILES_TX_TC 0x0200
|
|
|
|
/** flag the state that a new file has been set in this tx */
|
|
|
|
#define HTP_FLAG_NEW_FILE_TX_TS 0x0400
|
|
|
|
/** flag the state that a new file has been set in this tx */
|
|
|
|
#define HTP_FLAG_NEW_FILE_TX_TC 0x0800
|
file handling: expand filestore keyword
Filestore keyword by default (... filestore; ... ) marks only the file in the
same direction as the rule match for storing. This makes sense when inspecting
individual files (filemagic, filename, etc) but not so much when looking at
suspicious file requests, where the actual file is in the response.
The filestore keyword now takes 2 optional options:
filestore:<direction>,<scope>;
By default the direction is "same as rule match", and scope is "currently
inspected file".
For direction the following values are possible: "request" and "to_server",
"response" and "to_client", "both".
For scope the following values are possible: "tx" for all files in the current
HTTP/1.1 transation, "ssn" and "flow" for all files in the session/flow.
For the above case, where a suspious request should lead to a response file
download, this would work:
alert http ... content:"/suspicious/"; http_uri; filestore:response; ...
14 years ago
|
|
|
|
|
|
|
enum {
|
|
|
|
HTP_BODY_NONE = 0, /**< Flag to indicate the current
|
|
|
|
operation */
|
|
|
|
HTP_BODY_REQUEST, /**< Flag to indicate that the
|
|
|
|
current operation is a request */
|
|
|
|
HTP_BODY_RESPONSE /**< Flag to indicate that the current
|
|
|
|
* operation is a response */
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
HTP_BODY_REQUEST_NONE = 0,
|
|
|
|
HTP_BODY_REQUEST_MULTIPART, /* POST, MP */
|
|
|
|
HTP_BODY_REQUEST_POST, /* POST, no MP */
|
|
|
|
HTP_BODY_REQUEST_PUT,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
/* libhtp errors/warnings */
|
|
|
|
HTTP_DECODER_EVENT_UNKNOWN_ERROR,
|
|
|
|
HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED,
|
|
|
|
HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON,
|
|
|
|
HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE,
|
|
|
|
HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN,
|
|
|
|
HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT,
|
|
|
|
HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID,
|
|
|
|
HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID,
|
|
|
|
HTTP_DECODER_EVENT_MISSING_HOST_HEADER,
|
|
|
|
HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING,
|
|
|
|
HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING,
|
|
|
|
HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG,
|
|
|
|
HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG,
|
|
|
|
HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH,
|
|
|
|
HTTP_DECODER_EVENT_URI_HOST_INVALID,
|
|
|
|
HTTP_DECODER_EVENT_HEADER_HOST_INVALID,
|
|
|
|
HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT,
|
|
|
|
HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT,
|
|
|
|
HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE,
|
|
|
|
|
|
|
|
/* suricata errors/warnings */
|
|
|
|
HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR,
|
|
|
|
HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA,
|
|
|
|
HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct HTPCfgDir_ {
|
|
|
|
uint32_t body_limit;
|
|
|
|
uint32_t inspect_min_size;
|
|
|
|
uint32_t inspect_window;
|
|
|
|
StreamingBufferConfig sbcfg;
|
|
|
|
} HTPCfgDir;
|
|
|
|
|
|
|
|
/** Need a linked list in order to keep track of these */
|
|
|
|
typedef struct HTPCfgRec_ {
|
|
|
|
htp_cfg_t *cfg;
|
|
|
|
struct HTPCfgRec_ *next;
|
|
|
|
|
|
|
|
int uri_include_all; /**< use all info in uri (bool) */
|
|
|
|
|
|
|
|
/** max size of the client body we inspect */
|
|
|
|
int randomize;
|
|
|
|
int randomize_range;
|
|
|
|
int http_body_inline;
|
|
|
|
|
|
|
|
HTPCfgDir request;
|
|
|
|
HTPCfgDir response;
|
|
|
|
} HTPCfgRec;
|
|
|
|
|
|
|
|
/** Struct used to hold chunks of a body on a request */
|
|
|
|
struct HtpBodyChunk_ {
|
|
|
|
struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */
|
|
|
|
StreamingBufferSegment sbseg;
|
|
|
|
int logged;
|
|
|
|
} __attribute__((__packed__));
|
|
|
|
typedef struct HtpBodyChunk_ HtpBodyChunk;
|
|
|
|
|
|
|
|
/** Struct used to hold all the chunks of a body on a request */
|
|
|
|
typedef struct HtpBody_ {
|
|
|
|
HtpBodyChunk *first; /**< Pointer to the first chunk */
|
|
|
|
HtpBodyChunk *last; /**< Pointer to the last chunk */
|
|
|
|
|
|
|
|
StreamingBuffer *sb;
|
|
|
|
|
|
|
|
/* Holds the length of the htp request body seen so far */
|
|
|
|
uint64_t content_len_so_far;
|
|
|
|
/* parser tracker */
|
|
|
|
uint64_t body_parsed;
|
|
|
|
/* inspection tracker */
|
|
|
|
uint64_t body_inspected;
|
|
|
|
} HtpBody;
|
|
|
|
|
|
|
|
#define HTP_CONTENTTYPE_SET 0x01 /**< We have the content type */
|
|
|
|
#define HTP_BOUNDARY_SET 0x02 /**< We have a boundary string */
|
|
|
|
#define HTP_BOUNDARY_OPEN 0x04 /**< We have a boundary string */
|
|
|
|
#define HTP_FILENAME_SET 0x08 /**< filename is registered in the flow */
|
|
|
|
#define HTP_DONTSTORE 0x10 /**< not storing this file */
|
|
|
|
|
|
|
|
/** Now the Body Chunks will be stored per transaction, at
|
|
|
|
* the tx user data */
|
|
|
|
typedef struct HtpTxUserData_ {
|
mpm: run engines as few times as possible
In various scenarios buffers would be checked my MPM more than
once. This was because the buffers would be inspected for a
certain progress value or higher.
For example, for each packet in a file upload, the engine would
not just rerun the 'http client body' MPM on the new data, it
would also rerun the method, uri, headers, cookie, etc MPMs.
This was obviously inefficent, so this patch changes the logic.
The patch only runs the MPM engines when the progress is exactly
the intended progress. If the progress is beyond the desired
value, it is run once. A tracker is added to the app layer API,
where the completed MPMs are tracked.
Implemented for HTTP, TLS and SSH.
8 years ago
|
|
|
/** flags to track which mpm has run */
|
|
|
|
uint64_t mpm_ids;
|
|
|
|
|
|
|
|
/* Body of the request (if any) */
|
|
|
|
uint8_t request_body_init;
|
|
|
|
uint8_t response_body_init;
|
|
|
|
|
|
|
|
uint8_t request_has_trailers;
|
|
|
|
uint8_t response_has_trailers;
|
|
|
|
|
|
|
|
/* indicates which loggers that have logged */
|
|
|
|
uint32_t logged;
|
|
|
|
|
|
|
|
HtpBody request_body;
|
|
|
|
HtpBody response_body;
|
|
|
|
|
|
|
|
bstr *request_uri_normalized;
|
|
|
|
|
|
|
|
uint8_t *request_headers_raw;
|
|
|
|
uint8_t *response_headers_raw;
|
|
|
|
uint32_t request_headers_raw_len;
|
|
|
|
uint32_t response_headers_raw_len;
|
|
|
|
|
|
|
|
AppLayerDecoderEvents *decoder_events; /**< per tx events */
|
|
|
|
|
|
|
|
/** Holds the boundary identificator string if any (used on
|
|
|
|
* multipart/form-data only)
|
|
|
|
*/
|
|
|
|
uint8_t *boundary;
|
|
|
|
uint8_t boundary_len;
|
|
|
|
|
|
|
|
uint8_t tsflags;
|
|
|
|
uint8_t tcflags;
|
|
|
|
|
|
|
|
int16_t operation;
|
|
|
|
|
|
|
|
uint8_t request_body_type;
|
|
|
|
uint8_t response_body_type;
|
|
|
|
|
|
|
|
DetectEngineState *de_state;
|
|
|
|
} HtpTxUserData;
|
|
|
|
|
|
|
|
typedef struct HtpState_ {
|
|
|
|
/* Connection parser structure for each connection */
|
|
|
|
htp_connp_t *connp;
|
|
|
|
/* Connection structure for each connection */
|
|
|
|
htp_conn_t *conn;
|
|
|
|
Flow *f; /**< Needed to retrieve the original flow when usin HTPLib callbacks */
|
|
|
|
uint64_t transaction_cnt;
|
|
|
|
uint64_t store_tx_id;
|
|
|
|
FileContainer *files_ts;
|
|
|
|
FileContainer *files_tc;
|
|
|
|
const struct HTPCfgRec_ *cfg;
|
|
|
|
uint16_t flags;
|
|
|
|
uint16_t events;
|
|
|
|
uint16_t htp_messages_offset; /**< offset into conn->messages list */
|
|
|
|
uint64_t tx_with_detect_state_cnt;
|
|
|
|
} HtpState;
|
|
|
|
|
|
|
|
/** part of the engine needs the request body (e.g. http_client_body keyword) */
|
|
|
|
#define HTP_REQUIRE_REQUEST_BODY (1 << 0)
|
|
|
|
/** part of the engine needs the request body multipart header (e.g. filename
|
|
|
|
* and / or fileext keywords) */
|
|
|
|
#define HTP_REQUIRE_REQUEST_MULTIPART (1 << 1)
|
|
|
|
/** part of the engine needs the request file (e.g. log-file module) */
|
|
|
|
#define HTP_REQUIRE_REQUEST_FILE (1 << 2)
|
|
|
|
/** part of the engine needs the request body (e.g. file_data keyword) */
|
|
|
|
#define HTP_REQUIRE_RESPONSE_BODY (1 << 3)
|
|
|
|
|
|
|
|
SC_ATOMIC_DECLARE(uint32_t, htp_config_flags);
|
|
|
|
|
|
|
|
void RegisterHTPParsers(void);
|
|
|
|
void HTPParserRegisterTests(void);
|
|
|
|
void HTPAtExitPrintStats(void);
|
|
|
|
void HTPFreeConfig(void);
|
|
|
|
|
|
|
|
void HtpBodyPrint(HtpBody *);
|
|
|
|
void HtpBodyFree(HtpBody *);
|
|
|
|
/* To free the state from unittests using app-layer-htp */
|
|
|
|
void HTPStateFree(void *);
|
|
|
|
void AppLayerHtpEnableRequestBodyCallback(void);
|
|
|
|
void AppLayerHtpEnableResponseBodyCallback(void);
|
|
|
|
void AppLayerHtpNeedFileInspection(void);
|
|
|
|
void AppLayerHtpPrintStats(void);
|
|
|
|
|
|
|
|
void HTPConfigure(void);
|
|
|
|
|
|
|
|
void HtpConfigCreateBackup(void);
|
|
|
|
void HtpConfigRestoreBackup(void);
|
|
|
|
|
|
|
|
#endif /* __APP_LAYER_HTP_H__ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
*/
|