From: Yehor Velykozhon -X (yvelykoz - SOFTSERVE INC at Cisco) Date: Tue, 8 Aug 2023 07:08:43 +0000 (+0000) Subject: Pull request #3943: remove asn1 X-Git-Tag: 3.1.69.0~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6265466852f8872a0ccafe65ab224bd4d46c5e7b;p=thirdparty%2Fsnort3.git Pull request #3943: remove asn1 Merge in SNORT/snort3 from ~YVELYKOZ/snort3:asn1_fixing to master Squashed commit of the following: commit 9fd16701a67d1e244ba110de1f6a3160991f4baf Author: Yehor Velykozhon Date: Fri Aug 4 16:05:50 2023 +0300 doc: udpate tutorial commit db8e6783b1850e54024d4bb84364b166f7aff021 Author: Yehor Velykozhon Date: Tue Jul 11 18:55:55 2023 +0300 src: remove ips option asn1 --- diff --git a/doc/user/tutorial.txt b/doc/user/tutorial.txt index 1f31870be..d296cc242 100644 --- a/doc/user/tutorial.txt +++ b/doc/user/tutorial.txt @@ -324,7 +324,6 @@ The following parameters can't be changed during reload, and require a restart: * attribute_table.max_hosts * attribute_table.max_services_per_host * daq.snaplen -* detection.asn1 * file_id.max_files_cached * process.chroot * process.daemon diff --git a/src/detection/detection_engine.cc b/src/detection/detection_engine.cc index e68d50597..4f5c3b916 100644 --- a/src/detection/detection_engine.cc +++ b/src/detection/detection_engine.cc @@ -98,7 +98,9 @@ void DetectionEngine::thread_init() } void DetectionEngine::thread_term() -{ delete offloader; } +{ + delete offloader; +} DetectionEngine::DetectionEngine() { diff --git a/src/detection/detection_module.cc b/src/detection/detection_module.cc index a87a0b073..c314832b1 100644 --- a/src/detection/detection_module.cc +++ b/src/detection/detection_module.cc @@ -79,9 +79,6 @@ static const Parameter detection_params[] = { "allow_missing_so_rules", Parameter::PT_BOOL, nullptr, "false", "warn (true) or error (false) when an SO rule stub refers to an SO rule that isn't loaded" }, - { "asn1", Parameter::PT_INT, "0:65535", "0", - "maximum decode nodes" }, - { "global_default_rule_state", Parameter::PT_BOOL, nullptr, "true", "enable or disable rules by default (overridden by ips policy settings)" }, @@ -207,9 +204,6 @@ bool DetectionModule::set(const char*, Value& v, SnortConfig* sc) if ( v.is("allow_missing_so_rules") ) sc->allow_missing_so_rules = v.get_bool(); - else if ( v.is("asn1") ) - sc->asn1_mem = v.get_uint16(); - else if ( v.is("global_default_rule_state") ) sc->global_default_rule_state = v.get_bool(); diff --git a/src/ips_options/CMakeLists.txt b/src/ips_options/CMakeLists.txt index 966778899..d81ed4bb4 100644 --- a/src/ips_options/CMakeLists.txt +++ b/src/ips_options/CMakeLists.txt @@ -1,11 +1,6 @@ SET( PLUGIN_LIST - asn1_detect.cc - asn1_detect.h - asn1_util.cc - asn1_util.h ips_ack.cc - ips_asn1.cc ips_base64.cc ips_ber_data.cc ips_ber_skip.cc @@ -100,7 +95,6 @@ else (STATIC_IPS_OPTIONS) ) add_dynamic_module(ips_ack ips_options ips_ack.cc) - add_dynamic_module(ips_asn1 ips_options ips_asn1.cc asn1_detect.cc asn1_detect.h asn1_util.h asn1_util.cc) add_dynamic_module(ips_base64 ips_options ips_base64.cc) add_dynamic_module(ips_ber_data ips_options ips_ber_data.cc) add_dynamic_module(ips_ber_skip ips_options ips_ber_skip.cc) diff --git a/src/ips_options/asn1_detect.cc b/src/ips_options/asn1_detect.cc deleted file mode 100644 index 7569b0223..000000000 --- a/src/ips_options/asn1_detect.cc +++ /dev/null @@ -1,371 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2002-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// 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 along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -/** -** @file sp_asn1_detect.c -** -** @author Daniel Roelker -** -** @brief Decode and detect ASN.1 types, lengths, and data. -** -** This detection plugin adds ASN.1 detection functions on a per rule -** basis. ASN.1 detection plugins can be added by editing this file and -** providing an interface in the configuration code. -** -** Detection Plugin Interface: -** -** asn1: [detection function],[arguments],[offset type],[size] -** -** Detection Functions: -** -** bitstring_overflow: no arguments -** double_overflow: no arguments -** oversize_length: max size (if no max size, then just return value) -** -** alert udp any any -> any 161 (msg:"foo"; \ -** asn1: oversize_length 10000, absolute_offset 0;) -** -** alert tcp any any -> any 162 (msg:"foo2"; \ -** asn1: bitstring_overflow, oversize_length 500, relative_offset 7;) -** -** -** Note that further general information about ASN.1 can be found in -** the file doc/README.asn1. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "asn1_detect.h" - -#include "utils/snort_bounds.h" - -#include "asn1_util.h" - -/* -** NAME -** BitStringOverflow:: -*/ -/** -** The necessary info to detect possible bitstring overflows. Thanks -** once again to microsoft for keeping us in business. -** -** @return integer -** -** @retval 0 failed -** @retval 1 detected -*/ -static int BitStringOverflow(ASN1_TYPE* asn1, void*) -{ - if (!asn1) - return 0; - - /* - ** Here's what this means: - ** - ** If the ASN.1 type is a non-constructed bitstring (meaning that - ** there is only one encoding, not multiple encodings). And - ** the number of bits to ignore (this is taken from the first byte) - ** is greater than the total number of bits, then we have an - ** exploit attempt. - */ - if (asn1->ident.tag == SF_ASN1_TAG_BIT_STR && !asn1->ident.flag) - { - if (asn1->len.size && asn1->data && - (((asn1->len.size - 1)<<3) < (unsigned int)asn1->data[0])) - { - return 1; - } - } - - return 0; -} - -/* -** NAME -** DetectBitStringOverflow:: -*/ -/** -** This is just a wrapper to the traverse function. It's important because -** this allows us to do more with individual nodes in the future. -** -** @return integer -** -** @retval 0 failed -** @rteval 1 detected -*/ -static int DetectBitStringOverflow(ASN1_TYPE* asn1) -{ - return asn1_traverse(asn1, nullptr, BitStringOverflow); -} - -/* -** NAME -** DoubleOverflow:: -*/ -/** -** This is the info to detect double overflows. This may not be a -** remotely exploitable (remote services may not call the vulnerable -** microsoft function), but better safe than sorry. -** -** @return integer -** -** @retval 0 failed -** @retval 1 detected -*/ -static int DoubleOverflow(ASN1_TYPE* asn1, void*) -{ - if (!asn1) - return 0; - - /* - ** Here's what this does. - ** - ** There is a vulnerability in the MSASN1 library when decoding - ** a double (real) type. If the encoding is ASCII (specified by - ** not setting bit 7 or 8), and the buffer is greater than 256, - ** then you overflow the array in the function. - */ - if (asn1->ident.tag == SF_ASN1_TAG_REAL && !asn1->ident.flag) - { - if (asn1->len.size && asn1->data && - ((asn1->data[0] & 0xc0) == 0x00) && - (asn1->len.size > 256)) - { - return 1; - } - } - - return 0; -} - -/* -** NAME -** DetectDoubleOverflow:: -*/ -/** -** This is just a wrapper to the traverse function. It's important because -** this allows us to do more with individual nodes in the future. -** -** @return integer -** -** @retval 0 failed -** @rteval 1 detected -*/ -static int DetectDoubleOverflow(ASN1_TYPE* asn1) -{ - return asn1_traverse(asn1, nullptr, DoubleOverflow); -} - -/* -** NAME -** OversizeLength:: -*/ -/** -** This is the most generic of our ASN.1 detection functionalities. This -** will compare the ASN.1 type lengths against the user defined max -** length and alert if the length is greater than the user supplied length. -** -** @return integer -** -** @retval 0 failed -** @retval 1 detected -*/ -static int OversizeLength(ASN1_TYPE* asn1, void* user) -{ - unsigned int* max_size; - - if (!asn1 || !user) - return 0; - - max_size = (unsigned int*)user; - - if (*max_size && *max_size <= asn1->len.size) - return 1; - - return 0; -} - -/* -** NAME -** DetectOversizeLength:: -*/ -/** -** This is just a wrapper to the traverse function. It's important because -** this allows us to do more with individual nodes in the future. -** -** @return integer -** -** @retval 0 failed -** @rteval 1 detected -*/ -static int DetectOversizeLength(ASN1_TYPE* asn1, unsigned int max_size) -{ - return asn1_traverse(asn1, (void*)&max_size, OversizeLength); -} - -/* -** NAME -** Asn1DetectFuncs:: -*/ -/** -** The main function for adding ASN.1 detection type functionality. -** -** @return integer -** -** @retval 0 failed -** @retval 1 detected -*/ -static int Asn1DetectFuncs(ASN1_TYPE* asn1, ASN1_CTXT* ctxt, int dec_ret_val) -{ - int iRet = 0; - - /* - ** Print first, before we do other detection. If print is the only - ** option, then we want to evaluate this option as true and continue. - ** Otherwise, if another option is wrong, then we - */ - if (ctxt->print) - { - asn1_traverse(asn1, nullptr, asn1_print_types); - iRet = 1; - } - - /* - ** Let's check the bitstring overflow. - */ - if (ctxt->bs_overflow) - { - iRet = DetectBitStringOverflow(asn1); - if (iRet) - return 1; - } - - if (ctxt->double_overflow) - { - iRet = DetectDoubleOverflow(asn1); - if (iRet) - return 1; - } - - if (ctxt->length) - { - iRet = DetectOversizeLength(asn1, ctxt->max_length); - - /* - ** If we didn't detect any oversize length in the decoded structs, - ** that might be because we had a really overlong length that is - ** bigger than our data type could hold. In this case, it's - ** overlong too. - */ - if (!iRet && dec_ret_val == ASN1_ERR_OVERLONG_LEN) - iRet = 1; - - /* - ** We add this return in here, so that we follow suit with the - ** previous detections. Just trying to short-circuit any future - ** problems if we change the code flow here. - */ - if (iRet) - return 1; - } - - return iRet; -} - -/* -** NAME -** Asn1DoDetect:: -*/ -/** -** Workhorse detection function. Does not depend on OTN. -** We check all the offsets to make sure we're in bounds, etc. -** -** @return integer -** -** @retval 0 failed -** @retval 1 detected -*/ -int Asn1DoDetect(const uint8_t* data, uint16_t dsize, ASN1_CTXT* ctxt, const uint8_t* rel_ptr) -{ - ASN1_TYPE* asn1; - int iRet; - unsigned int size; - const uint8_t* start; - const uint8_t* end; - const uint8_t* offset = nullptr; - - /* - ** Failed if there is no data to decode. - */ - if (data == nullptr) - return 0; - - start = data; - end = start + dsize; - - switch (ctxt->offset_type) - { - case REL_OFFSET: - if (!rel_ptr) - return 0; - - /* - ** Check that it is in bounds first. - ** Because rel_ptr can be "end" in the last match, - ** use end + 1 for upper bound - ** Bound checked also after offset is applied - */ - if (!inBounds(start, end + 1, rel_ptr)) - return 0; - - offset = rel_ptr+ctxt->offset; - - if (!inBounds(start, end, offset)) - return 0; - - break; - - case ABS_OFFSET: - default: - offset = start+ctxt->offset; - - if (!inBounds(start, end, offset)) - return 0; - - break; - } - - /* - ** Set size for asn1_decode(). This should never be <0 since - ** we do the previous in bounds check. - */ - size = end - offset; - - iRet = asn1_decode(offset, size, &asn1); - if (iRet && !asn1) - return 0; - - /* - ** Let's do detection now. - */ - return Asn1DetectFuncs(asn1, ctxt, iRet); -} - diff --git a/src/ips_options/asn1_detect.h b/src/ips_options/asn1_detect.h deleted file mode 100644 index 78dd14bd1..000000000 --- a/src/ips_options/asn1_detect.h +++ /dev/null @@ -1,42 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2005-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// 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 along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -#ifndef ASN1_DETECT_H -#define ASN1_DETECT_H - -#include - -#define ABS_OFFSET 1 -#define REL_OFFSET 2 - -typedef struct s_ASN1_CTXT -{ - int bs_overflow; - int double_overflow; - int print; - int length; - unsigned int max_length; - int offset; - int offset_type; -} ASN1_CTXT; - -int Asn1DoDetect(const uint8_t*, uint16_t, ASN1_CTXT*, const uint8_t*); - -#endif - diff --git a/src/ips_options/asn1_util.cc b/src/ips_options/asn1_util.cc deleted file mode 100644 index a1f52c5e2..000000000 --- a/src/ips_options/asn1_util.cc +++ /dev/null @@ -1,1007 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2004-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// 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 along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -/** -** @file asn1.c -** -** @author Daniel Roelker -** -** @brief ASN.1 Decoding API for BER and DER encodings. -** -** Author: Daniel Roelker -** -** ASN.1 decoding functions that incorporate an internal stack for -** processing. That way we don't have to worry about attackers trying -** to overload the machine stack. -** -** Handles both DER and BER encodings, and also the indefinite encoding -** that BER supports. Lots of functionality can be added on top of -** this library. SNMP will probably be the first. -** -** NOTES: -** - Stop using global variables so we can have multiple instances, -** but we don't need that functionality right now. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "asn1_util.h" - -#include "main/thread.h" -#include "utils/util.h" - -using namespace snort; - -/* -** Macros -*/ -#define SF_ASN1_CLASS(c) (((uint8_t)(c)) & SF_ASN1_CLASS_MASK) -#define SF_ASN1_FLAG(c) (((uint8_t)(c)) & SF_ASN1_FLAG_MASK) -#define SF_ASN1_TAG(c) (((uint8_t)(c)) & SF_ASN1_TAG_MASK) -#define SF_ASN1_LEN_EXT(c) (((uint8_t)(c)) & SF_BER_LEN_MASK) - -#define ASN1_OOB(s,e,d) (!(((s) <= (d)) && ((d) < (e)))) -#define ASN1_FATAL_ERR(e) ((e) < 0) -#define ASN1_NONFATAL_ERR(e) ((e) > 0) - -#define ASN1_MAX_STACK 128 - -static ASN1_CONFIG asn1_config; -static THREAD_LOCAL int node_index; - -/* -** NAME -** asn1_init_node_index:: -*/ -/** -** This function should get called whenever we decode a new ASN.1 -** string to initialize the memory. -** -** @return void -*/ -static void asn1_init_node_index() -{ - node_index = 0; -} - -/* -** NAME -** asn1_node_alloc:: -*/ -/** -** Allocate an ASN1_NODE. -** -** @return ASN1_TYPE * -** -** @retval null - memory allocation failed -** @retval !null - function successful -*/ -static ASN1_TYPE* asn1_node_alloc() -{ - if ((asn1_config.mem == nullptr) || (asn1_config.num_nodes <= node_index)) - return nullptr; - - return &asn1_config.mem[node_index++]; -} - -/* -** NAME -** asn1_init_mem:: -*/ -/** -** This function initializes the number of nodes that we want to track in -** an ASN.1 decode. Pass in the max number of nodes for an ASN.1 decode and -** we will track that many. -** -** @return none -** -*/ -void asn1_init_mem(int asn1_mem) -{ - asn1_config.num_nodes = asn1_mem; - - if (asn1_config.num_nodes > 0) - asn1_config.mem = (ASN1_TYPE*)snort_calloc(asn1_config.num_nodes, sizeof(ASN1_TYPE)); - node_index = 0; -} - -/* -** NAME -** asn1_free_mem:: -*/ -/** -** This function frees the number of nodes that we were tracking in -** an ASN.1 decode. -** -** @return none -** -*/ -void asn1_free_mem() -{ - if (asn1_config.mem != nullptr) - { - snort_free(asn1_config.mem); - asn1_config.mem = nullptr; - } -} - -/* -** NAME -** asn1_decode_tag_num_ext:: -*/ -/** -** This routine decodes extended tag numbers and checks for overlong -** tag numbers, etc. -** -** @param ASN1_DATA ptr to data -** @param unsigned ptr to tag num -** -** @return integer -** -** @retval ASN1_OK function successful -** @retval ASN1_ERR_OVERLONG_LEN tag number too large -** @retval ASN1_ERR_OOB encoding goes out of bounds -** @retval ASN1_ERR_NULL_MEM function arguments are null -*/ -static int asn1_decode_tag_num_ext(ASN1_DATA* asn1_data, unsigned* tag_num) -{ - int iExtension = 0; - - if (!asn1_data || !tag_num) - return ASN1_ERR_NULL_MEM; - - *tag_num = 0; - - /* - ** Loop through the tag type while extension bit is set - */ - do - { - /* - ** Is this an extension byte? - */ - iExtension = SF_ASN1_LEN_EXT(*asn1_data->data); - - unsigned new_tag_num = ((*tag_num << 7) | (*asn1_data->data & 0x7f)); - if (*tag_num != 0 && new_tag_num <= *tag_num) - { - return ASN1_ERR_OVERLONG_LEN; - } - - *tag_num = new_tag_num; - - asn1_data->data++; - if (ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data)) - { - return ASN1_ERR_OOB; - } - } - while (iExtension); - - return ASN1_OK; -} - -/* -** NAME -** asn1_decode_ident:: -*/ -/** -** This function decodes the identifier byte(s) of an ASN.1 structure. -** We handle long tag numbers and check for overflows in the extended -** tag numbers. -** -** @return integer -** -** @retval ASN1_ERR_NULL_MEM function arguments are null -** @retval ASN1_ERR_OOB buffer out of bounds -** @retval ASN1_ERR_INVALID_BER_TAG_LEN tag num too large or bad encoding -** @retval ASN1_OK function ok -*/ -static int asn1_decode_ident(ASN1_TYPE* asn1_type, ASN1_DATA* asn1_data) -{ - ASN1_IDENT* ident; - - if (!asn1_type || !asn1_data) - return ASN1_ERR_NULL_MEM; - - ident = &asn1_type->ident; - - ident->asn1_class = SF_ASN1_CLASS(*asn1_data->data); - ident->flag = SF_ASN1_FLAG(*asn1_data->data); - ident->tag = SF_ASN1_TAG(*asn1_data->data); - - asn1_data->data++; - if (ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data)) - { - //printf("** decode_ident: oob\n"); - return ASN1_ERR_OOB; - } - - /* - ** Is tag extended? - */ - if (ident->tag == SF_ASN1_TAG_EXTENSION) - { - ident->tag_type = SF_ASN1_TAG_EXTENSION; - - if ( asn1_decode_tag_num_ext(asn1_data, &ident->tag) ) - { - //printf("** decode_ident: ext_len error\n"); - return ASN1_ERR_INVALID_BER_TAG_LEN; - } - } - - return ASN1_OK; -} - -/* -** NAME -** asn1_decode_len_type:: -*/ -/** -** Determine the type of len encoding. Could be short, long or -** indeterminate. -** -** @return integer -** -** @retval SF_BER_LEN_DEF_LONG extended length -** @retval SF_BER_LEN_DEF_SHORT one byte length < 127 -** @retval SF_BER_LEN_INDEF indeterminate length -*/ -static int asn1_decode_len_type(const uint8_t* data) -{ - int iExt; - - iExt = SF_ASN1_LEN_EXT(*data); - if (iExt) - { - if (*data & 0x7f) - { - return SF_BER_LEN_DEF_LONG; - } - else - { - return SF_BER_LEN_INDEF; - } - } - - return SF_BER_LEN_DEF_SHORT; -} - -/* -** NAME -** asn1_decode_len_ext:: -*/ -/** -** Decode the extended length version. Basically we read the first -** byte for the number of bytes in the extended length. We then read -** that number of bytes to determine the length. If the number of bytes -** in the length is greater than our variable, then we return -** ASN1_ERR_OVERLONG_LEN, and exit decoding. -** -** @return integer -** -** @retval ASN1_ERR_NULL_MEM function arguments null -** @retval ASN1_ERR_OVERLONG_LEN length to long for us to decode -** @retval ASN1_ERR_OOB out of bounds condition -** @retval ASN1_OK function successful -*/ -static int asn1_decode_len_ext(ASN1_DATA* asn1_data, unsigned* size) -{ - int iBytes; - - if (!asn1_data || !size) - return ASN1_ERR_NULL_MEM; - - *size = 0; - - iBytes = (*asn1_data->data & 0x7f); - - asn1_data->data++; - if (ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data)) - { - return ASN1_ERR_OOB; - } - - for (int iCtr = 0; iCtr < iBytes; iCtr++) - { - unsigned new_size = ((*size << 8) | (*asn1_data->data)); - - /* - ** If we've just added some data to the size, and - ** we are still the same or less than the previous - ** size, we've just overflowed our variable - */ - if (*size != 0 && new_size <= *size) - { - return ASN1_ERR_OVERLONG_LEN; - } - - *size = new_size; - - asn1_data->data++; - if (ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data)) - { - /* - ** Check to see if this was just an extended length that was zero at - ** the end of the buffer. If it was, then return normal. - */ - if (*size == 0 && (iCtr+1) == iBytes) - break; - - return ASN1_ERR_OOB; - } - } - - return ASN1_OK; -} - -/* -** NAME -** asn1_decode_len:: -*/ -/** -** This function decodes the ASN.1 type length. Determines what type of -** BER encoding is used for the length and decodes that length. -** -** @return integer -** -** @retval ASN1_ERR_NULL_MEM function arguments null -** @retval ASN1_ERR_FATAL should never get this -** @retval ASN1_ERR_OOB out of bounds condition -** @retval ASN1_OK function successful -*/ -static int asn1_decode_len(ASN1_TYPE* asn1_type, ASN1_DATA* asn1_data) -{ - ASN1_LEN* len; - int iRet; - - if (!asn1_type || !asn1_data) - return ASN1_ERR_NULL_MEM; - - len = &asn1_type->len; - - len->type = (unsigned char)asn1_decode_len_type(asn1_data->data); - - switch (len->type) - { - case SF_BER_LEN_DEF_SHORT: - len->size = *asn1_data->data; - - (asn1_data->data)++; - if (ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data)) - { - /* - ** Only return OOB if the short length wasn't zero. Otherwise, - ** it's a valid encoding. - */ - if (len->size != 0) - return ASN1_ERR_OOB; - } - - break; - - case SF_BER_LEN_DEF_LONG: - iRet = asn1_decode_len_ext(asn1_data, &len->size); - if (iRet) - return iRet; - - break; - - case SF_BER_LEN_INDEF: - /* - ** Not sure what to do here, so we'll just set the length - ** to 0 and proceed for now. - */ - len->size = 0; - - asn1_data->data++; - if (ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data)) - return ASN1_ERR_OOB; - - break; - - default: - /* - ** This should be one of the three values. So we are in - ** error condition. - */ - return ASN1_ERR_FATAL; - } - - return ASN1_OK; -} - -/* -** NAME -** asn1_is_eoc:: -*/ -/** -** This function checks and ASN1_TYPE for end-of-content encoding. This -** doesn't determine that this is what it is, but what it could be. -** -** @return int -** -** @retval 0 not EOC -** @retval 1 is EOC -*/ -static int asn1_is_eoc(ASN1_TYPE* asn1) -{ - if (!asn1) - return 0; - - if (asn1->ident.asn1_class == 0x00 && asn1->ident.flag == 0x00 && - asn1->ident.tag == 0x00 && asn1->len.type == SF_BER_LEN_DEF_SHORT && - asn1->len.size == 0) - { - return 1; - } - - return 0; -} - -/* -** NAME -** asn1_decode_type:: -*/ -/** -** This function decodes an ASN1_TYPE structure. It processes the type in -** three parts. -** -** 1) Identifier -** 2) Length -** 3) Data -** -** The data processing skips over primitive data (if it can) and processes -** construct data (if it can). -** -** This function also updates the data and len ptrs so we continue moving -** through the data. -** -** @return integer -** -** @retval ASN1_OK function successful -** @retval ASN1_ERR_MEM_ALLOC memory allocation failed -** @retval ASN1_ERR_INVALID_INDEF_LEN invalid indefinite encoding -** @retval ASN1_ERR_INVALID_ARG invalid argument -** @retval ASN1_ERR_OOB out of bounds -*/ -static int asn1_decode_type(const uint8_t** data, unsigned* len, ASN1_TYPE** asn1_type) -{ - ASN1_DATA asn1data; - unsigned uiRawLen; - int iRet; - - if (!*data) - return ASN1_ERR_INVALID_ARG; - - *asn1_type = nullptr; - - /* - ** Check len first, because if it's 0, then we already decoded a valid - ** construct. We let the caller know this, by returning OK, but setting - ** the asn1_type ptr to null. - */ - if (*len == 0) - return ASN1_OK; - - if (ASN1_OOB(*data, (*data) + *len, *data)) - return ASN1_ERR_OOB; - - *asn1_type = asn1_node_alloc(); - if (*asn1_type == nullptr) - { - return ASN1_ERR_MEM_ALLOC; - } - memset(*asn1_type, 0x00, sizeof(ASN1_TYPE)); - - asn1data.start = *data; - asn1data.end = (*data) + *len; - asn1data.data = *data; - - iRet = asn1_decode_ident(*asn1_type, &asn1data); - if (iRet) - { - return iRet; - } - - iRet = asn1_decode_len(*asn1_type, &asn1data); - if (iRet) - { - return iRet; - } - - /* - ** Set this variable here, so we can set the data_len for - ** indeterminate constructs. - */ - uiRawLen = asn1data.end - asn1data.data; - - /* - ** This is an important check. If the length is zero, it means that - ** we've either hit a zero length type or we've hit a BER indefinite - ** encoding (hate those). - ** - ** Standard says that only constructs can have the indefinite length - ** encoding, but we still need to "prove" that. Thanks M$. - */ - if (!(*asn1_type)->len.size) - { - if ((*asn1_type)->len.type != SF_BER_LEN_INDEF || - (*asn1_type)->ident.flag == SF_ASN1_FLAG_CONSTRUCT) - { - (*asn1_type)->data = asn1data.data; - - if ((*asn1_type)->len.type == SF_BER_LEN_INDEF) - { - (*asn1_type)->data_len = uiRawLen; - } - else - { - /* - ** If we're not an indefinite type, then we check to - ** see if we are an eoc, so we don't have to check again. - */ - (*asn1_type)->data_len = 0; - - if (asn1_is_eoc(*asn1_type)) - (*asn1_type)->eoc = 1; - } - - goto valid; - } - - return ASN1_ERR_INVALID_INDEF_LEN; - } - - /* - ** Set data ptr for asn1 types that have data. - */ - (*asn1_type)->data = asn1data.data; - - /* - ** Check for the ASN.1 type being larger than we have room for. - */ - if (uiRawLen < (*asn1_type)->len.size) - { - (*asn1_type)->data_len = uiRawLen; - - /* - ** If we're a construct, then don't skip over the data because - ** we have to process it. - */ - if ((*asn1_type)->ident.flag == SF_ASN1_FLAG_CONSTRUCT) - goto valid; - - return ASN1_ERR_OOB; - } - - /* - ** We got enough data in the buffer for the true identifier size, so - ** we set it. - */ - (*asn1_type)->data_len = (*asn1_type)->len.size; - - /* - ** Only jump data that's not going to be decoded. That means jump - ** over primitive data and decode construct data. - */ - if (!((*asn1_type)->ident.flag == SF_ASN1_FLAG_CONSTRUCT)) - { - asn1data.data += (*asn1_type)->len.size; - } - -valid: - /* - ** Update data buffer, before we return. Depending on if we just decoded - ** a zero length identifier and are on the last data byte, we could be at - ** the end of our buffer. Otherwise, we're still in the buffer. - */ - *len = asn1data.end - asn1data.data; - *data = asn1data.data; - - return ASN1_OK; -} - -/* -** NAME -** asn1_decode:: -*/ -/** -** This function decodes an ASN.1 string and returns the decoded -** structures. We BER encoding, which means we handle both -** definite and indefinite length encodings (that was a B). -** -** @return integer -** -** @retval ASN1_OK function successful -** @retval !ASN1_OK lots of error conditions, figure it out -*/ -int asn1_decode(const uint8_t* data, unsigned len, ASN1_TYPE** asn1_type) -{ - ASN1_TYPE* cur; - ASN1_TYPE* child = nullptr; - ASN1_TYPE* indef; - ASN1_TYPE* asnstack[ASN1_MAX_STACK]; - - const uint8_t* end; - unsigned con_len; - int index = 0; - int iRet; - - if (!data || !len) - return ASN1_ERR_NULL_MEM; - - asn1_init_node_index(); - - /* - ** Keep track of where the end of the data buffer is so we can continue - ** processing if there is a construct. - */ - end = data + len; - - iRet = asn1_decode_type(&data,&len,asn1_type); - if (iRet || !(*asn1_type)) - { - //printf("** initial bad decode\n"); - return iRet; - } - - cur = *asn1_type; - - while (cur) - { - /* - ** This is where we decode the ASN.1 constructs. We do while() - ** because we may have back to back constructs. We bail on the - ** first identifier that isn't a construct. - */ - while (cur && cur->ident.flag == SF_ASN1_FLAG_CONSTRUCT) - { - if (index < ASN1_MAX_STACK) - asnstack[index++] = cur; - else - return ASN1_ERR_STACK; - - /* - ** We now set the current len for this constructs true length, - ** or raw length if true length is past buffer. - */ - if (cur->len.type != SF_BER_LEN_INDEF) - { - if (len < cur->data_len) - return ASN1_ERR_OVERLONG_LEN; - - len = cur->data_len; - } - - iRet = asn1_decode_type(&data, &len, &cur->cnext); - if (iRet) - { - return iRet; - } - - /* - ** Check next child for ending of indefinite encodings. - */ - if (cur->cnext && cur->cnext->eoc) - { - if (index && (indef = asnstack[--index]) != nullptr) - { - if (indef->len.type == SF_BER_LEN_INDEF) - { - indef->len.size = data - indef->data - 2; - indef->data_len = indef->len.size; - - cur->cnext = nullptr; - cur = indef; - break; - } - else - { - /* - ** Not an EOC type, so it's just a strange child - ** encoding. Put the construct back on the stack. - */ - asnstack[index++] = indef; - } - } - } - - cur = cur->cnext; - } - - /* - ** If there is a node, then process any peers that this node has. - */ - if (cur) - { - iRet = asn1_decode_type(&data, &len, &cur->next); - if (iRet) - return iRet; - - /* - ** Cycle through any eoc that might be back to back - */ - while (cur->next && cur->next->eoc) - { - if (index && (indef = asnstack[--index]) != nullptr) - { - if (indef->len.type == SF_BER_LEN_INDEF) - { - indef->len.size = data - indef->data - 2; - indef->data_len = indef->len.size; - cur->next = nullptr; - cur = indef; - - iRet = asn1_decode_type(&data, &len, &cur->next); - if (iRet) - { - return iRet; - } - - continue; - } - - asnstack[index++] = indef; - } - - break; - } - - cur = cur->next; - if (cur) - continue; - } - - /* - ** We only get here if the peer decode fails. - ** - ** Traverse the stack and close off any constructs that we - ** are done with. This gets a little trickier, because we have to - ** check for additional peers for each construct, depending on the - ** length of the parent construct. - */ - while (index && (cur = asnstack[--index]) != nullptr) - { - /* - ** Get the construct length and set the length appropriately - ** if there is more data in this construct. - */ - con_len = data - cur->data; - if (cur->data_len > con_len) - { - len = cur->data_len - con_len; - } - - /* - ** If this construct has no more data left, then save it off as - ** the last child of the previous construct. - */ - if (len == 0) - { - child = cur; - } - else if (child) - { - /* - ** Means this construct has more data left, so if the child is set - ** then we set it's next ptr. Otherwise, this means we are in - ** an indeterminate construct, and need to check for eoc before we - ** continue processing. - */ - asnstack[index++] = cur; - cur = child; - child = nullptr; - } - - iRet = asn1_decode_type(&data, &len, &cur->next); - if (iRet) - { - return iRet; - } - - if (cur->next && cur->next->eoc) - { - if (index && (indef = asnstack[--index]) != nullptr) - { - if (indef->len.type == SF_BER_LEN_INDEF) - { - indef->len.size = data - indef->data - 2; - indef->data_len = indef->len.size; - cur->next = nullptr; - cur = indef; - } - else - { - asnstack[index++] = indef; - } - } - } - - /* - ** This logic tell us that we are on the root construct, but there - ** are additional peers because there is more data. We recalculate - ** the length and continue on. - ** - ** NOTE: - ** We may not want this because research may only be able to point - ** us at the first sequence and it's anyone's guess after that. - */ - if (!index && !(cur->next) && (data < end)) - { - len = (end - data); - - iRet = asn1_decode_type(&data, &len, &cur->next); - if (iRet) - return iRet; - } - - cur = cur->next; - if (cur) - break; - } - - /* - ** The loop logic bails us out if there is no cur. - */ - } - - return ASN1_OK; -} - -/* -** NAME -** asn1_traverse:: -*/ -/** -** This function traverses a decoded ASN1 structure, applying a detection -** function for the different types. This is just to make this user stack -** generic AND easy. -** -** @return integer -** -** @retval 1 detection function successful -** @retval 0 detection function unsuccessful -*/ -int asn1_traverse(ASN1_TYPE* asn1, void* user, - int (* DetectFunc)(ASN1_TYPE*, void*)) -{ - ASN1_TYPE* asnstack[ASN1_MAX_STACK]; - int index = 0; - ASN1_TYPE* cur; - int iRet; - - if (!asn1) - return 0; - - cur = asn1; - - while (cur) - { - while (cur && cur->ident.flag == SF_ASN1_FLAG_CONSTRUCT) - { - if (index < ASN1_MAX_STACK) - asnstack[index++] = cur; - else - return 0; - - iRet = DetectFunc(cur, user); - if (iRet) - return 1; - - cur = cur->cnext; - } - - if (cur) - { - iRet = DetectFunc(cur, user); - if (iRet) - return 1; - - cur = cur->next; - if (cur) - continue; - } - - while (index && (cur = asnstack[--index]) != nullptr) - { - cur = cur->next; - if (cur) - break; - } - } - - return 0; -} - -/* -** NAME -** asn1_print_types:: -*/ -/** -** Print out the ASN.1 type. -** -** @return integer -** -** @retval 0 printed -*/ -int asn1_print_types(ASN1_TYPE* asn1_type, void* user) -{ - unsigned int iTabs = 0; - unsigned int iCtr; - - if (user) - iTabs = *((int*)user); - - for (iCtr = 0; iCtr < iTabs; iCtr++) - printf(" "); - - printf("## PRINT ASN1_TYPE STRUCTURE ##\n"); - - for (iCtr = 0; iCtr < iTabs; iCtr++) - printf(" "); - - printf("IDENT - asn1_class: %.2x | flag: %.2x | tag_type: %.2x | " - "tag_num: %u\n", asn1_type->ident.asn1_class, asn1_type->ident.flag, - asn1_type->ident.tag_type, asn1_type->ident.tag); - - for (iCtr = 0; iCtr < iTabs; iCtr++) - printf(" "); - - printf("LEN - type: %d | size: %u\n", asn1_type->len.type, - asn1_type->len.size); - - for (iCtr = 0; iCtr < iTabs; iCtr++) - printf(" "); - - printf("DATA | data_len: %u | ", asn1_type->data_len); - if (asn1_type->data) - { - for (iCtr = 0; iCtr < asn1_type->data_len; iCtr++) - printf(" %.2x", asn1_type->data[iCtr]); - } - else - { - printf(" NULL"); - } - - printf("\n\n"); - - /* - - printf("\n"); - //if(BitStringOverflow(asn1_type)) - //{ - // printf("BITSTRING OVERFLOW\n"); - //} - printf("\n"); - - if(asn1_type->cnext) - asn1_print_types(asn1_type->cnext, iTabs+1); - - if(asn1_type->next) - asn1_print_types(asn1_type->next, iTabs); - */ - - return 0; -} - diff --git a/src/ips_options/asn1_util.h b/src/ips_options/asn1_util.h deleted file mode 100644 index 2ab7bd770..000000000 --- a/src/ips_options/asn1_util.h +++ /dev/null @@ -1,158 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2004-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// 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 along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -#ifndef ASN1_H -#define ASN1_H - -/* -** ASN.1 Identifier Classes -*/ -#define SF_ASN1_CLASS_MASK 0xc0 -#define SF_ASN1_CLASS_UNIVERSAL 0x00 -#define SF_ASN1_CLASS_APPLICATION 0x40 -#define SF_ASN1_CLASS_CONTEXT 0x80 -#define SF_ASN1_CLASS_PRIVATE 0xc0 - -/* -** ASN.1 Identifier Flags -*/ -#define SF_ASN1_FLAG_MASK 0x20 -#define SF_ASN1_FLAG_PRIMITIVE 0x00 -#define SF_ASN1_FLAG_CONSTRUCT 0x20 - -/* -** ASN.1 Universal Tags -*/ -#define SF_ASN1_TAG_MASK 0x1f - -#define SF_ASN1_TAG_RSV_ENC 0 -#define SF_ASN1_TAG_BOOL 1 -#define SF_ASN1_TAG_INT 2 -#define SF_ASN1_TAG_BIT_STR 3 -#define SF_ASN1_TAG_OCT_STR 4 -#define SF_ASN1_TAG_NULL 5 -#define SF_ASN1_TAG_OBJ_IDENT 6 -#define SF_ASN1_TAG_OBJ_DESC 7 -#define SF_ASN1_TAG_EXT 8 -#define SF_ASN1_TAG_REAL 9 -#define SF_ASN1_TAG_ENUM 10 -#define SF_ASN1_TAG_EMB_PDV 11 -#define SF_ASN1_TAG_REL_OBJ 13 - -#define SF_ASN1_TAG_SEQ 16 -#define SF_ASN1_TAG_SET 17 - -#define SF_ASN1_TAG_UTF8_STR 12 -#define SF_ASN1_TAG_NUM_STR 18 -#define SF_ASN1_TAG_PRINT_STR 19 -#define SF_ASN1_TAG_T61_STR 20 -#define SF_ASN1_TAG_VID_STR 21 -#define SF_ASN1_TAG_IA5_STR 22 -#define SF_ASN1_TAG_GRAPH_STR 25 -#define SF_ASN1_TAG_VIS_STR 26 -#define SF_ASN1_TAG_GEN_STR 27 -#define SF_ASN1_TAG_UNIV_STR 28 -#define SF_ASN1_TAG_BMP_STR 30 - -#define SF_ASN1_TAG_UTC_TIME 23 -#define SF_ASN1_TAG_GEN_TIME 24 - -#define SF_ASN1_TAG_EXTENSION 31 - -/* -** BER Length Decoding -*/ -#define SF_BER_LEN_MASK 0x80 -#define SF_BER_LEN_DEF_SHORT 1 -#define SF_BER_LEN_DEF_LONG 2 -#define SF_BER_LEN_INDEF 3 - -struct ASN1_LEN -{ - unsigned char type; - unsigned int size; -}; - -struct ASN1_IDENT -{ - unsigned char asn1_class; - unsigned char flag; - unsigned char tag_type; - unsigned int tag; -}; - -struct ASN1_TYPE -{ - ASN1_IDENT ident; - ASN1_LEN len; - - const unsigned char* data; - unsigned int data_len; - - unsigned char eoc; - - struct ASN1_TYPE* next; - struct ASN1_TYPE* cnext; -}; - -struct ASN1_DATA -{ - const unsigned char* data; - const unsigned char* start; - const unsigned char* end; - unsigned int len; -}; - -struct ASN1_CONFIG -{ - ASN1_TYPE* mem; - int num_nodes; -}; - -namespace snort -{ -struct SnortConfig; -} - -/* -** Error Codes -*/ -#define ASN1_ERR_OOB 1 -#define ASN1_ERR_NONFATAL 2 -#define ASN1_ERR_OVERLONG_LEN 3 - -#define ASN1_OK 0 - -#define ASN1_ERR_NULL_MEM (-1) -#define ASN1_ERR_INVALID_BER_TAG_LEN (-3) -#define ASN1_ERR_MEM_ALLOC (-4) -#define ASN1_ERR_FATAL (-5) -#define ASN1_ERR_INVALID_INDEF_LEN (-6) -#define ASN1_ERR_INVALID_ARG (-7) -#define ASN1_ERR_STACK (-8) - -void asn1_init_mem(int asn1_mem); -void asn1_free_mem(); - -int asn1_decode(const unsigned char* data, unsigned int len, ASN1_TYPE** asn1_type); -int asn1_print_types(ASN1_TYPE* asn1_type, void* user); -int asn1_traverse(ASN1_TYPE* asn1, void* user, int (* DetectFunc)(ASN1_TYPE*, void*)); - -#endif - diff --git a/src/ips_options/ips_asn1.cc b/src/ips_options/ips_asn1.cc deleted file mode 100644 index 3e16aada9..000000000 --- a/src/ips_options/ips_asn1.cc +++ /dev/null @@ -1,315 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2002-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// 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 along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -/* -** @file sp_asn1.c -** -** @author Daniel Roelker -** -** @brief Decode and detect ASN.1 types, lengths, and data. -** -** This detection plugin adds ASN.1 detection functions on a per rule -** basis. ASN.1 detection plugins can be added by editing this file and -** providing an interface in the configuration code. -** -** Detection Plugin Interface: -** -** asn1: [detection function],[arguments],[offset type],[size] -** -** Detection Functions: -** -** bitstring_overflow: no arguments -** double_overflow: no arguments -** oversize_length: max size (if no max size, then just return value) -** -** alert udp any any -> any 161 (msg:"foo"; \ -** asn1: oversize_length 10000, absolute_offset 0;) -** -** alert tcp any any -> any 162 (msg:"foo2"; \ -** asn1: bitstring_overflow, oversize_length 500, relative_offset 7;) -** -** -** Note that further general information about ASN.1 can be found in -** the file doc/README.asn1. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "framework/cursor.h" -#include "framework/ips_option.h" -#include "framework/module.h" -#include "hash/hash_key_operations.h" -#include "main/snort_config.h" -#include "profiler/profiler.h" -#include "protocols/packet.h" - -#include "asn1_detect.h" -#include "asn1_util.h" - -using namespace snort; - -#define BITSTRING_OPT "bitstring_overflow" -#define DOUBLE_OPT "double_overflow" -#define PRINT_OPT "print" - -#define LENGTH_OPT "oversize_length" -#define ABS_OFFSET_OPT "absolute_offset" -#define REL_OFFSET_OPT "relative_offset" - -#define DELIMITERS " ,\t\n" - -static THREAD_LOCAL ProfileStats asn1PerfStats; - -#define s_name "asn1" - -#define s_help \ - "rule option for asn1 detection" - -class Asn1Option : public IpsOption -{ -public: - Asn1Option(const ASN1_CTXT& c) : IpsOption(s_name) - { config = c; } - - uint32_t hash() const override; - bool operator==(const IpsOption&) const override; - - bool is_relative() override - { return ( config.offset_type == REL_OFFSET ); } - - EvalStatus eval(Cursor&, Packet*) override; - - CursorActionType get_cursor_type() const override - { return CAT_READ; } - -private: - ASN1_CTXT config; -}; - -//------------------------------------------------------------------------- -// class methods -//------------------------------------------------------------------------- - -uint32_t Asn1Option::hash() const -{ - uint32_t a = config.bs_overflow; - uint32_t b = config.double_overflow; - uint32_t c = config.print; - - mix(a,b,c); - - a += config.length; - b += config.max_length; - c += config.offset; - - mix(a,b,c); - - a += config.offset_type; - b += IpsOption::hash(); - - finalize(a,b,c); - return c; -} - -bool Asn1Option::operator==(const IpsOption& rhs) const -{ - if ( !IpsOption::operator==(rhs) ) - return false; - - const Asn1Option& asn1 = (const Asn1Option&)rhs; - - const ASN1_CTXT* left = &config; - const ASN1_CTXT* right = &asn1.config; - - if ((left->bs_overflow == right->bs_overflow) && - (left->double_overflow == right->double_overflow) && - (left->print == right->print) && - (left->length == right->length) && - (left->max_length == right->max_length) && - (left->offset == right->offset) && - (left->offset_type == right->offset_type)) - { - return true; - } - - return false; -} - -IpsOption::EvalStatus Asn1Option::eval(Cursor& c, Packet* p) -{ - RuleProfile profile(asn1PerfStats); - - // Failed if there is no data to decode. - if (!p->data) - return NO_MATCH; - - if ( Asn1DoDetect(c.buffer(), c.size(), &config, c.start()) ) - return MATCH; - - return NO_MATCH; -} - -//------------------------------------------------------------------------- -// module -//------------------------------------------------------------------------- - -static const Parameter s_params[] = -{ - { BITSTRING_OPT, Parameter::PT_IMPLIED, nullptr, nullptr, - "detects invalid bitstring encodings that are known to be remotely exploitable" }, - - { DOUBLE_OPT, Parameter::PT_IMPLIED, nullptr, nullptr, - "detects a double ASCII encoding that is larger than a standard buffer" }, - - { PRINT_OPT, Parameter::PT_IMPLIED, nullptr, nullptr, - "dump decode data to console; always true" }, - - { LENGTH_OPT, Parameter::PT_INT, "0:max32", nullptr, - "compares ASN.1 type lengths with the supplied argument" }, - - { ABS_OFFSET_OPT, Parameter::PT_INT, "0:65535", nullptr, - "absolute offset from the beginning of the packet" }, - - { REL_OFFSET_OPT, Parameter::PT_INT, "-65535:65535", nullptr, - "relative offset from the cursor" }, - - { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } -}; - -class Asn1Module : public Module -{ -public: - Asn1Module() : Module(s_name, s_help, s_params) { } - - bool begin(const char*, int, SnortConfig*) override; - bool set(const char*, Value&, SnortConfig*) override; - - ProfileStats* get_profile() const override - { return &asn1PerfStats; } - - Usage get_usage() const override - { return DETECT; } - -public: - ASN1_CTXT data = {}; -}; - -bool Asn1Module::begin(const char*, int, SnortConfig*) -{ - memset(&data, 0, sizeof(data)); - return true; -} - -bool Asn1Module::set(const char*, Value& v, SnortConfig*) -{ - if ( v.is(BITSTRING_OPT) ) - data.bs_overflow = 1; - - else if ( v.is(DOUBLE_OPT) ) - data.double_overflow = 1; - - else if ( v.is(PRINT_OPT) ) - data.print = 1; - - else if ( v.is(LENGTH_OPT) ) - { - data.length = 1; - data.max_length = v.get_uint32(); - } - else if ( v.is(ABS_OFFSET_OPT) ) - { - data.offset_type = ABS_OFFSET; - data.offset = v.get_uint16(); - } - else if ( v.is(REL_OFFSET_OPT) ) - { - data.offset_type = REL_OFFSET; - data.offset = v.get_int32(); - } - return true; -} - -//------------------------------------------------------------------------- -// api methods -//------------------------------------------------------------------------- - -static Module* mod_ctor() -{ - return new Asn1Module; -} - -static void mod_dtor(Module* m) -{ - delete m; -} - -static void asn1_init(const SnortConfig* sc) -{ asn1_init_mem(sc->asn1_mem); } - -static void asn1_term(const SnortConfig*) -{ asn1_free_mem(); } - -static IpsOption* asn1_ctor(Module* p, OptTreeNode*) -{ - Asn1Module* m = (Asn1Module*)p; - return new Asn1Option(m->data); -} - -static void asn1_dtor(IpsOption* p) -{ - delete p; -} - -static const IpsApi asn1_api = -{ - { - PT_IPS_OPTION, - sizeof(IpsApi), - IPSAPI_VERSION, - 0, - API_RESERVED, - API_OPTIONS, - s_name, - s_help, - mod_ctor, - mod_dtor - }, - OPT_TYPE_DETECTION, - 0, 0, - asn1_init, - asn1_term, - nullptr, - nullptr, - asn1_ctor, - asn1_dtor, - nullptr -}; - -#ifdef BUILDING_SO -SO_PUBLIC const BaseApi* snort_plugins[] = -#else -const BaseApi* ips_asn1[] = -#endif -{ - &asn1_api.base, - nullptr -}; - diff --git a/src/ips_options/ips_options.cc b/src/ips_options/ips_options.cc index 231e3361b..81990760a 100644 --- a/src/ips_options/ips_options.cc +++ b/src/ips_options/ips_options.cc @@ -49,7 +49,6 @@ extern const BaseApi* ips_vba_data; #ifdef STATIC_IPS_OPTIONS extern const BaseApi* ips_ack[]; -extern const BaseApi* ips_asn1[]; extern const BaseApi* ips_base64[]; extern const BaseApi* ips_ber_data[]; extern const BaseApi* ips_ber_skip[]; @@ -124,7 +123,6 @@ void load_ips_options() #ifdef STATIC_IPS_OPTIONS PluginManager::load_plugins(ips_ack); - PluginManager::load_plugins(ips_asn1); PluginManager::load_plugins(ips_base64); PluginManager::load_plugins(ips_ber_data); PluginManager::load_plugins(ips_ber_skip); diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index dd4d45aa8..0ae4fd0a3 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -490,9 +490,6 @@ bool SnortConfig::verify() const if (!policy_map->setup_network_policies()) ReloadError("Network policy user ids must be unique\n"); - if ( sc->asn1_mem != asn1_mem ) - ReloadError("Changing detection.asn1_mem requires a restart.\n"); - else if ( sc->bpf_filter != bpf_filter ) ReloadError("Changing packets.bfp_filter requires a restart.\n"); diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 3d20cd31c..16017df68 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -222,7 +222,6 @@ public: int pcre_ovector_size = 0; bool pcre_override = true; - int asn1_mem = 0; uint32_t run_flags = 0; unsigned offload_limit = 99999; // disabled diff --git a/tools/snort2lua/config_states/config_api.cc b/tools/snort2lua/config_states/config_api.cc index 3abf5574e..e9dea4a64 100644 --- a/tools/snort2lua/config_states/config_api.cc +++ b/tools/snort2lua/config_states/config_api.cc @@ -27,7 +27,6 @@ namespace config extern const ConvertMap* addressspace_agnostic_map; extern const ConvertMap* alert_with_interface_name_map; extern const ConvertMap* alertfile_map; -extern const ConvertMap* asn1_map; extern const ConvertMap* autogenerate_preprocessor_decoder_rules_map; extern const ConvertMap* binding_map; extern const ConvertMap* bpf_file_map; @@ -147,7 +146,6 @@ const std::vector config_api = addressspace_agnostic_map, alert_with_interface_name_map, alertfile_map, - asn1_map, autogenerate_preprocessor_decoder_rules_map, binding_map, bpf_file_map, diff --git a/tools/snort2lua/config_states/config_one_int_option.cc b/tools/snort2lua/config_states/config_one_int_option.cc index 64eb86e02..833b9abe5 100644 --- a/tools/snort2lua/config_states/config_one_int_option.cc +++ b/tools/snort2lua/config_states/config_one_int_option.cc @@ -119,19 +119,6 @@ static ConversionState* config_int_ctor(Converter& c) } } // namespace -/************************************************* - ********************* asn1 ******************** - *************************************************/ - -static const std::string asn1 = "asn1"; -static const ConvertMap asn1_api = -{ - asn1, - config_int_ctor<& asn1, & detection>, -}; - -const ConvertMap* asn1_map = &asn1_api; - /************************************************* ************* max_attribute_hosts ************* *************************************************/ diff --git a/tools/snort2lua/rule_states/rule_unchanged.cc b/tools/snort2lua/rule_states/rule_unchanged.cc index b8ae9ca35..1b636e4e1 100644 --- a/tools/snort2lua/rule_states/rule_unchanged.cc +++ b/tools/snort2lua/rule_states/rule_unchanged.cc @@ -524,19 +524,6 @@ static const ConvertMap rule_base64_data = const ConvertMap* base64_data_map = &rule_base64_data; -/************************************ - ************* ASN1 *************** - ************************************/ - -static const std::string asn1 = "asn1"; -static const ConvertMap rule_asn1 = -{ - asn1, - unchanged_rule_ctor<& asn1>, -}; - -const ConvertMap* asn1_map = &rule_asn1; - /************************************ *********** PRIORITY ************* ************************************/ diff --git a/tools/snort2lua/rule_states/rule_unsupported.cc b/tools/snort2lua/rule_states/rule_unsupported.cc index 58f74ca71..4c1a154b4 100644 --- a/tools/snort2lua/rule_states/rule_unsupported.cc +++ b/tools/snort2lua/rule_states/rule_unsupported.cc @@ -59,6 +59,7 @@ static const std::string count = "count"; static const std::string ftpbounce = "ftpbounce"; static const std::string logto = "logto"; static const std::string sameip = "sameip"; +static const std::string asn1 = "asn1"; static const ConvertMap activated_by_api = { activated_by, unsupported_rule_ctor<&activated_by, true>}; static const ConvertMap activates_api = { activates, unsupported_rule_ctor<&activates, true>}; @@ -66,6 +67,7 @@ static const ConvertMap count_api = { count, unsupported_rule_ctor<&count, true> static const ConvertMap ftpbounce_api = { ftpbounce, unsupported_rule_ctor<&ftpbounce, false>}; static const ConvertMap logto_api = { logto, unsupported_rule_ctor<&logto, false>}; static const ConvertMap sameip_api = { sameip, unsupported_rule_ctor<&sameip, false>}; +static const ConvertMap asn1_api = { asn1, unsupported_rule_ctor<&asn1, true>}; const ConvertMap* activated_by_map = &activated_by_api; const ConvertMap* activates_map = &activates_api; @@ -73,4 +75,5 @@ const ConvertMap* count_map = &count_api; const ConvertMap* ftpbounce_map = &ftpbounce_api; const ConvertMap* logto_map = &logto_api; const ConvertMap* sameip_map = &sameip_api; +const ConvertMap* asn1_map = &asn1_api; } // namespace rules