* attribute_table.max_hosts
* attribute_table.max_services_per_host
* daq.snaplen
-* detection.asn1
* file_id.max_files_cached
* process.chroot
* process.daemon
}
void DetectionEngine::thread_term()
-{ delete offloader; }
+{
+ delete offloader;
+}
DetectionEngine::DetectionEngine()
{
{ "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)" },
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();
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
)
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)
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <droelker@sourcefire.com>
-**
-** @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);
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <cstdint>
-
-#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
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <droelker@sourcefire.com>
-**
-** @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;
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <droelker@sourcefire.com>
-**
-** @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
-};
-
#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[];
#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);
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");
int pcre_ovector_size = 0;
bool pcre_override = true;
- int asn1_mem = 0;
uint32_t run_flags = 0;
unsigned offload_limit = 99999; // disabled
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;
addressspace_agnostic_map,
alert_with_interface_name_map,
alertfile_map,
- asn1_map,
autogenerate_preprocessor_decoder_rules_map,
binding_map,
bpf_file_map,
}
} // 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 *************
*************************************************/
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 *************
************************************/
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>};
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;
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