?? sp_asn1_detect.c
字號:
/* $Id$ *//* ** Copyright (C) 2002-2006 Sourcefire, Inc. ** Author: Daniel Roelker ** ** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <sys/types.h>#include <stdlib.h>#include <ctype.h>#ifndef SF_SNORT_ENGINE_DLL#include "debug.h"#else/* Ignore debug statements */#include <stdint.h>#define DEBUG_WRAP(x)#endif#include "../sfutil/asn1.h"#include "sp_asn1_detect.h"#define BITSTRING_OPT "bitstring_overflow"#define DOUBLE_OPT "double_overflow"#define LENGTH_OPT "oversize_length"#define DBL_FREE_OPT "double_free"#define ABS_OFFSET_OPT "absolute_offset"#define REL_OFFSET_OPT "relative_offset"#define PRINT_OPT "print"#define ABS_OFFSET 1#define REL_OFFSET 2#define DELIMITERS " ,\t\n"extern const u_int8_t *doe_ptr;/* * Check to make sure that p is less than or equal to the ptr range * pointers * * 1 means it's in bounds, 0 means it's not */static int inBounds(const u_int8_t *start, const u_int8_t *end, const u_int8_t *p){ if(p >= start && p < end) { return 1; } return 0;}/*** NAME** BitStringOverflow::*//**** The neccessary 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 * user){ 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, NULL, 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 *user){ if(!asn1) return 0; /* ** Here's what this does. ** ** There is a vulnerablity 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, NULL, 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, NULL, 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 u_int8_t *data, u_int16_t dsize, ASN1_CTXT *ctxt, const u_int8_t *rel_ptr){ ASN1_TYPE *asn1; int iRet; unsigned int size; const u_int8_t *start; const u_int8_t *end; const u_int8_t *offset = NULL; /* ** Failed if there is no data to decode. */ if(!data) return 0; start = data; end = start + dsize; switch(ctxt->offset_type) { case REL_OFFSET: if(!rel_ptr) { DEBUG_WRAP(DebugMessage(DEBUG_ASN1, "[*] No rel_ptr for " "relative offset, so we are bailing.\n");); return 0; } /* ** Check that it is in bounds first. */ if(!inBounds(start, end, rel_ptr)) { DEBUG_WRAP(DebugMessage(DEBUG_ASN1, "[*] ASN.1 bounds " "check failed for rel_ptr.\n");); return 0; } if(!inBounds(start, end, rel_ptr+ctxt->offset)) { DEBUG_WRAP(DebugMessage(DEBUG_ASN1, "[*] ASN.1 bounds " "check failed rel_ptr+offset.\n");); return 0; } offset = rel_ptr+ctxt->offset; break; case ABS_OFFSET: default: if(!inBounds(start, end, start+ctxt->offset)) { DEBUG_WRAP(DebugMessage(DEBUG_ASN1, "[*] ASN.1 bounds " "check failed.\n");); return 0; } offset = start+ctxt->offset; break; } /* ** Final Check. We are good to go now. */ if(!inBounds(start,end,offset)) { DEBUG_WRAP(DebugMessage(DEBUG_ASN1, "[*] ASN.1 bounds " "check failed.\n");); return 0; } /* ** Set size for asn1_decode(). This should never be -1 since ** we do the previous in bounds check. */ size = end - offset; iRet = asn1_decode(offset, size, &asn1); if(iRet && !asn1) { DEBUG_WRAP(DebugMessage(DEBUG_ASN1, "[*] ASN.1 decode failed " "miserably.\n");); return 0; } /* ** Let's do detection now. */ return Asn1DetectFuncs(asn1, ctxt, iRet);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -