|
|
|
/* 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 <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; ...
13 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; ...
13 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_URI_DELIM_NON_COMPLIANT,
|
|
|
|
|
|
|
|
/* suricata errors/warnings */
|
|
|
|
HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR,
|
|
|
|
HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA,
|
|
|
|
HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define HTP_PCRE_NONE 0x00 /**< No pcre executed yet */
|
|
|
|
#define HTP_PCRE_DONE 0x01 /**< Flag to indicate that pcre has
|
|
|
|
done some inspection in the
|
|
|
|
chunks */
|
|
|
|
#define HTP_PCRE_HAS_MATCH 0x02 /**< Flag to indicate that the chunks
|
|
|
|
matched on some rule */
|
|
|
|
|
|
|
|
/** 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 */
|
|
|
|
uint32_t request_body_limit;
|
|
|
|
uint32_t response_body_limit;
|
|
|
|
|
|
|
|
uint32_t request_inspect_min_size;
|
|
|
|
uint32_t request_inspect_window;
|
|
|
|
|
|
|
|
uint32_t response_inspect_min_size;
|
|
|
|
uint32_t response_inspect_window;
|
|
|
|
int randomize;
|
|
|
|
int randomize_range;
|
|
|
|
} HTPCfgRec;
|
|
|
|
|
|
|
|
/** Struct used to hold chunks of a body on a request */
|
|
|
|
struct HtpBodyChunk_ {
|
|
|
|
uint8_t *data; /**< Pointer to the data of the chunk */
|
|
|
|
struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */
|
|
|
|
uint64_t stream_offset;
|
|
|
|
uint32_t len; /**< Length of the chunk */
|
|
|
|
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 */
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|
|
|
|
#define HTP_TX_HAS_FILE 0x01
|
|
|
|
#define HTP_TX_HAS_FILENAME 0x02 /**< filename is known at this time */
|
|
|
|
#define HTP_TX_HAS_TYPE 0x04
|
|
|
|
#define HTP_TX_HAS_FILECONTENT 0x08 /**< file has content so we can do type detect */
|
|
|
|
|
|
|
|
#define HTP_RULE_NEED_FILE HTP_TX_HAS_FILE
|
|
|
|
#define HTP_RULE_NEED_FILENAME HTP_TX_HAS_FILENAME
|
|
|
|
#define HTP_RULE_NEED_TYPE HTP_TX_HAS_TYPE
|
|
|
|
#define HTP_RULE_NEED_FILECONTENT HTP_TX_HAS_FILECONTENT
|
|
|
|
|
|
|
|
/** Now the Body Chunks will be stored per transaction, at
|
|
|
|
* the tx user data */
|
|
|
|
typedef struct HtpTxUserData_ {
|
|
|
|
/* Body of the request (if any) */
|
|
|
|
uint8_t request_body_init;
|
|
|
|
uint8_t response_body_init;
|
|
|
|
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;
|
|
|
|
|
|
|
|
} 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;
|
|
|
|
struct HTPCfgRec_ *cfg;
|
|
|
|
uint16_t flags;
|
|
|
|
uint16_t events;
|
|
|
|
uint16_t htp_messages_offset; /**< offset into conn->messages list */
|
|
|
|
} 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);
|
|
|
|
|
|
|
|
htp_tx_t *HTPTransactionMain(const HtpState *);
|
|
|
|
|
|
|
|
int HTPCallbackRequestBodyData(htp_tx_data_t *);
|
|
|
|
int HtpTransactionGetLoggableId(Flow *);
|
|
|
|
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__ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
*/
|