"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/preprocessors/HttpInspect/client/hi_client_norm.c" (16 Oct 2020, 13836 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "hi_client_norm.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /****************************************************************************
    2  *
    3  * Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    4  * Copyright (C) 2003-2013 Sourcefire, Inc.
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License Version 2 as
    8  * published by the Free Software Foundation.  You may not use, modify or
    9  * distribute this program under any other version of the GNU General
   10  * Public License.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   20  *
   21  ****************************************************************************/
   22 
   23 /**
   24 **  @file       hi_client_norm.c
   25 **
   26 **  @author     Daniel Roelker <droelker@sourcefire.com>
   27 **
   28 **  @brief      HTTP client normalization routines
   29 **
   30 **  We deal with the normalization of HTTP client requests headers and
   31 **  URI.
   32 **
   33 **  In this file, we handle all the different HTTP request URI evasions.  The
   34 **  list is:
   35 **      - ASCII decoding
   36 **      - UTF-8 decoding
   37 **      - IIS Unicode decoding
   38 **      - Directory traversals (self-referential and traversal)
   39 **      - Multiple Slashes
   40 **      - Double decoding
   41 **      - %U decoding
   42 **      - Bare Byte Unicode decoding
   43 **
   44 **      Base 36 is deprecated and essentially a noop
   45 **      - Base36 decoding
   46 **
   47 **  NOTES:
   48 **      - Initial development.  DJR
   49 */
   50 #include <stdlib.h>
   51 #include <stdio.h>
   52 #include <sys/types.h>
   53 #include <ctype.h>
   54 
   55 #ifdef HAVE_CONFIG_H
   56 #include "config.h"
   57 #endif
   58 
   59 #include "hi_norm.h"
   60 #include "hi_util.h"
   61 #include "hi_return_codes.h"
   62 
   63 #include "snort_bounds.h"
   64 
   65 
   66 int hi_split_header_cookie(HI_SESSION *Session, u_char *header, int *i_header_len,
   67                            u_char *cookie_header, int *i_cookie_len,
   68                            const u_char *raw_header, int i_raw_header_len,
   69                            COOKIE_PTR *cookie)
   70 {
   71     int iRet = HI_SUCCESS;
   72     COOKIE_PTR *last_cookie = NULL;
   73     COOKIE_PTR *first_cookie = cookie;
   74     const u_char *raw_header_end = raw_header + i_raw_header_len;
   75     int this_cookie_len = 0;
   76     const u_char *this_header_start = raw_header;
   77     const u_char *this_header_end;
   78     int this_header_len = 0;
   79     const u_char *header_end;
   80     const u_char *cookie_end;
   81 
   82     if (!cookie || !i_header_len || !i_cookie_len)
   83         return HI_INVALID_ARG;
   84 
   85     /* Can't use hi_util_in_bounds header because == is okay */
   86     if (cookie->cookie_end > raw_header + i_raw_header_len)
   87         return HI_OUT_OF_BOUNDS;
   88 
   89     header_end = (const u_char *)(header + *i_header_len);
   90     *i_header_len = 0;
   91     cookie_end = (const u_char *)(cookie_header + *i_cookie_len);
   92     *i_cookie_len = 0;
   93 
   94     do
   95     {
   96         this_cookie_len = cookie->cookie_end - cookie->cookie;
   97         this_header_end = cookie->cookie;
   98         this_header_len = this_header_end - this_header_start;
   99 
  100         /* Trim the header and only copy what we can store in the buf */
  101         if (*i_header_len + this_header_len > MAX_URI)
  102         {
  103             this_header_len = MAX_URI - *i_header_len;
  104         }
  105         /* Copy out the headers from start to beginning of the cookie */
  106         if (this_header_len > 0)
  107         {
  108             if (SafeMemcpy(header + *i_header_len, this_header_start, this_header_len, header, header_end) == SAFEMEM_SUCCESS)
  109             {
  110                 *i_header_len += this_header_len;
  111             }
  112         }
  113         else
  114         {
  115             DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "HttpInspect: no leading header: %d to %d\n",
  116                 this_header_end - this_header_start, this_header_len););
  117         }
  118 
  119         /* Trim the cookie and only copy what we can store in the buf */
  120         if (*i_cookie_len + this_cookie_len > MAX_URI)
  121         {
  122             this_cookie_len = MAX_URI - *i_cookie_len;
  123         }
  124         /* And copy the cookie */
  125         if (this_cookie_len > 0)
  126         {
  127             if (SafeMemcpy(cookie_header + *i_cookie_len, cookie->cookie, this_cookie_len, cookie_header, cookie_end) == SAFEMEM_SUCCESS)
  128             {
  129                 *i_cookie_len += this_cookie_len;
  130             }
  131         }
  132         else
  133         {
  134             DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "HttpInspect: trimming cookie: %d to %d\n",
  135                 cookie->cookie_end - cookie->cookie, this_cookie_len););
  136         }
  137 
  138         /* update for the next one */
  139         this_header_start = cookie->cookie_end;
  140         cookie = cookie->next;
  141         if (last_cookie && (last_cookie != first_cookie))
  142         {
  143             free(last_cookie);
  144             hi_stats.mem_used -= sizeof(COOKIE_PTR);
  145         }
  146         last_cookie = cookie;
  147         if (!cookie)
  148         {
  149             this_header_len = raw_header + i_raw_header_len - this_header_start;
  150         }
  151         else
  152         {
  153             this_header_len = cookie->cookie - this_header_start;
  154         }
  155         this_header_end = this_header_start + this_header_len;
  156 
  157         if ((*i_header_len == MAX_URI) ||
  158             (*i_cookie_len == MAX_URI))
  159         {
  160             last_cookie = NULL;
  161         }
  162     }
  163     while (last_cookie);
  164 
  165     /* Clear out the 'first' cookie since we're done with it */
  166     /* Eliminates unexptected 'reuse' in the case of pipeline'd requests. */
  167     memset(first_cookie, 0, sizeof(COOKIE_PTR));
  168 
  169     if (this_header_len && hi_util_in_bounds(raw_header, raw_header_end, this_header_start))
  170     {
  171         /* Trim the header and only copy what we can store in the buf */
  172         if (*i_header_len + this_header_len > MAX_URI)
  173         {
  174             this_header_len = MAX_URI - *i_header_len;
  175         }
  176 
  177         /* Copy the remaining headers after the last cookie */
  178         if (this_header_len > 0)
  179         {
  180             if (SafeMemcpy(header + *i_header_len, this_header_start, this_header_len, header, header_end) == SAFEMEM_SUCCESS)
  181             {
  182                 *i_header_len += this_header_len;
  183             }
  184         }
  185         else
  186         {
  187             DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "HttpInspect: no leading header: %d to %d\n",
  188                 this_header_end - this_header_start, this_header_len););
  189 
  190         }
  191     }
  192 
  193     return iRet;
  194 }
  195 
  196 int hi_client_norm(HI_SESSION *Session)
  197 {
  198     static u_char UriBuf[MAX_URI];
  199     static u_char HeaderBuf[MAX_URI];
  200     static u_char CookieBuf[MAX_URI];
  201     static u_char RawHeaderBuf[MAX_URI];
  202     static u_char RawCookieBuf[MAX_URI];
  203     static u_char PostBuf[MAX_URI];
  204     HI_CLIENT_REQ    *ClientReq;
  205     int iRet;
  206     int iUriBufSize = MAX_URI;
  207     int iRawHeaderBufSize = MAX_URI;
  208     int iRawCookieBufSize = MAX_URI;
  209     int iHeaderBufSize = MAX_URI;
  210     int iCookieBufSize = MAX_URI;
  211     int iPostBufSize = MAX_URI;
  212     uint16_t encodeType = 0;
  213     u_int updated_uri_size = 0;
  214     const u_char *updated_uri_start = NULL;
  215 
  216     if(!Session || !Session->server_conf)
  217     {
  218         return HI_INVALID_ARG;
  219     }
  220 
  221     ClientReq = &Session->client.request;
  222     ClientReq->uri_encode_type = 0;
  223     ClientReq->header_encode_type = 0;
  224     ClientReq->cookie_encode_type = 0;
  225     ClientReq->post_encode_type = 0;
  226 
  227     /* Handle URI normalization */
  228     if(ClientReq->uri_norm)
  229     {
  230         updated_uri_start = ClientReq->uri;
  231         updated_uri_size = ClientReq->uri_size;
  232         Session->norm_flags &= ~HI_BODY;
  233         if(proxy_start && (ClientReq->uri == proxy_start))
  234         {
  235             if(hi_util_in_bounds(ClientReq->uri, (ClientReq->uri + ClientReq->uri_size), proxy_end))
  236             {
  237                 updated_uri_start = proxy_end;
  238                 updated_uri_size = (ClientReq->uri_size) - (proxy_end - proxy_start);
  239             }
  240 
  241         }
  242         proxy_start = proxy_end = NULL;
  243         iRet = hi_norm_uri(Session, UriBuf, &iUriBufSize,
  244                            updated_uri_start, updated_uri_size, &encodeType);
  245         if (iRet == HI_NONFATAL_ERR)
  246         {
  247             /* There was a non-fatal problem normalizing */
  248             ClientReq->uri_norm = NULL;
  249             ClientReq->uri_norm_size = 0;
  250             ClientReq->uri_encode_type = 0;
  251         }
  252         else
  253         {
  254             /* Client code is expecting these to be set to non-NULL if
  255              * normalization occurred. */
  256             ClientReq->uri_norm      = UriBuf;
  257             ClientReq->uri_norm_size = iUriBufSize;
  258             ClientReq->uri_encode_type = encodeType;
  259         }
  260         encodeType = 0;
  261     }
  262     else
  263     {
  264         if(proxy_start && (ClientReq->uri == proxy_start))
  265         {
  266             if(hi_util_in_bounds(ClientReq->uri, (ClientReq->uri + ClientReq->uri_size), proxy_end))
  267             {
  268                 ClientReq->uri_norm = proxy_end;
  269                 ClientReq->uri_norm_size = (ClientReq->uri_size) - (proxy_end - proxy_start);
  270             }
  271         }
  272         proxy_start = proxy_end = NULL;
  273     }
  274 
  275     if (ClientReq->cookie.cookie)
  276     {
  277         /* There is an HTTP header with a cookie, look for the cookie &
  278          * separate the two buffers */
  279         iRet = hi_split_header_cookie(Session,
  280             RawHeaderBuf, &iRawHeaderBufSize,
  281             RawCookieBuf, &iRawCookieBufSize,
  282             ClientReq->header_raw, ClientReq->header_raw_size,
  283             &ClientReq->cookie);
  284         if( iRet == HI_SUCCESS )
  285         {
  286             ClientReq->cookie.cookie = RawCookieBuf;
  287             ClientReq->cookie.cookie_end = RawCookieBuf + iRawCookieBufSize;
  288 
  289         }
  290     }
  291     else
  292     {
  293         if (ClientReq->header_raw_size)
  294         {
  295             if (ClientReq->header_raw_size > MAX_URI)
  296             {
  297                 ClientReq->header_raw_size = MAX_URI;
  298             }
  299             /* Limiting to MAX_URI above should cause this to always return SAFEMEM_SUCCESS */
  300             SafeMemcpy(RawHeaderBuf, ClientReq->header_raw, ClientReq->header_raw_size,
  301                     &RawHeaderBuf[0], &RawHeaderBuf[0] + iRawHeaderBufSize);
  302         }
  303         iRawHeaderBufSize = ClientReq->header_raw_size;
  304         iRawCookieBufSize = 0;
  305     }
  306 
  307     if(ClientReq->header_norm && Session->server_conf->normalize_headers)
  308     {
  309         Session->norm_flags &= ~HI_BODY;
  310         iRet = hi_norm_uri(Session, HeaderBuf, &iHeaderBufSize,
  311                        RawHeaderBuf, iRawHeaderBufSize, &encodeType);
  312         if (iRet == HI_NONFATAL_ERR)
  313         {
  314             /* There was a non-fatal problem normalizing */
  315             ClientReq->header_norm = NULL;
  316             ClientReq->header_norm_size = 0;
  317             ClientReq->header_encode_type = 0;
  318         }
  319         else
  320         {
  321             /* Client code is expecting these to be set to non-NULL if
  322              * normalization occurred. */
  323             ClientReq->header_norm      = HeaderBuf;
  324             ClientReq->header_norm_size = iHeaderBufSize;
  325             ClientReq->header_encode_type = encodeType;
  326         }
  327         encodeType = 0;
  328     }
  329     else
  330     {
  331         /* Client code is expecting these to be set to non-NULL if
  332          * normalization occurred. */
  333         if (iRawHeaderBufSize)
  334         {
  335             ClientReq->header_norm      = RawHeaderBuf;
  336             ClientReq->header_norm_size = iRawHeaderBufSize;
  337             ClientReq->header_encode_type = 0;
  338         }
  339     }
  340 
  341     if(ClientReq->cookie.cookie && Session->server_conf->normalize_cookies)
  342     {
  343         Session->norm_flags &= ~HI_BODY;
  344         iRet = hi_norm_uri(Session, CookieBuf, &iCookieBufSize,
  345                        RawCookieBuf, iRawCookieBufSize, &encodeType);
  346         if (iRet == HI_NONFATAL_ERR)
  347         {
  348             /* There was a non-fatal problem normalizing */
  349             ClientReq->cookie_norm = NULL;
  350             ClientReq->cookie_norm_size = 0;
  351             ClientReq->cookie_encode_type = 0;
  352         }
  353         else
  354         {
  355             /* Client code is expecting these to be set to non-NULL if
  356              * normalization occurred. */
  357             ClientReq->cookie_norm      = CookieBuf;
  358             ClientReq->cookie_norm_size = iCookieBufSize;
  359             ClientReq->cookie_encode_type = encodeType;
  360         }
  361         encodeType = 0;
  362     }
  363     else
  364     {
  365         /* Client code is expecting these to be set to non-NULL if
  366          * normalization occurred. */
  367         if (iRawCookieBufSize)
  368         {
  369             ClientReq->cookie_norm      = RawCookieBuf;
  370             ClientReq->cookie_norm_size = iRawCookieBufSize;
  371             ClientReq->cookie_encode_type = 0;
  372         }
  373     }
  374 
  375     /* Handle normalization of post methods.
  376      * Note: posts go into a different buffer. */
  377     if(ClientReq->post_norm)
  378     {
  379         Session->norm_flags |= HI_BODY;
  380         iRet = hi_norm_uri(Session, PostBuf, &iPostBufSize,
  381                            ClientReq->post_raw, ClientReq->post_raw_size, &encodeType);
  382         if (iRet == HI_NONFATAL_ERR)
  383         {
  384             ClientReq->post_norm = NULL;
  385             ClientReq->post_norm_size = 0;
  386             ClientReq->post_encode_type = 0;
  387         }
  388         else
  389         {
  390             ClientReq->post_norm      = PostBuf;
  391             ClientReq->post_norm_size = iPostBufSize;
  392             ClientReq->post_encode_type = encodeType;
  393         }
  394         encodeType = 0;
  395     }
  396 
  397     /*
  398     printf("** uri_norm = |");
  399     for(iCtr = 0; iCtr < ClientReq->uri_norm_size; iCtr++)
  400     {
  401         if(!isascii((int)ClientReq->uri_norm[iCtr]) ||
  402            !isprint((int)ClientReq->uri_norm[iCtr]))
  403         {
  404             printf(".[%.2x]", ClientReq->uri_norm[iCtr]);
  405             continue;
  406         }
  407         printf("%c", ClientReq->uri_norm[iCtr]);
  408     }
  409     printf("| size = %u\n", ClientReq->uri_norm_size);
  410     */
  411 
  412     return HI_SUCCESS;
  413 }