VSV00001 - DoS vulnerability in Varnish Cache
Poul-Henning Kamp
phk at phk.freebsd.dk
Wed Aug 2 11:55:29 CEST 2017
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
VSV00001 DoS vulnerability
==========================
CVE-<to be assigned, we couldn't get one under embargo>
Date: 2017-08-02
A wrong if statement in the varnishd source code means that
particular invalid requests from the client can trigger an assert.
This causes the varnishd worker process to abort and restart, loosing
the cached contents in the process.
An attacker can therefore crash the varnishd worker process on
demand and effectively keep it from serving content - a Denial-of-Service
attack.
Mitigation is possible from VCL or by updating to a fixed version
of Varnish Cache.
Versions affected
- -----------------
* 4.0.1 to 4.0.4
* 4.1.0 to 4.1.7
* 5.0.0
* 5.1.0 to 5.1.2
Users of the Varnish Cache Plus product
from Varnish Software: See the email you received from V-S.
Versions not affected
- ---------------------
* All releases up to and including 4.0.0
Fixed in
- --------
* 4.0.5 and forward
* 4.1.8 and forward
* 5.1.3 and forward
Users of the Varnish Cache Plus product
from Varnish Software: See the email you received from V-S.
Mitigation from VCL
- -------------------
Note that there are subtle differences on the VCL workarounds,
depending on which version of Varnish you are running, make sure
to use the right one.
These VCL snippets work by failing all client requests which attempt
to use `Transfer-encoding: chunked`.
Normally browsers will not issue such requests, but we know there
are cases where B2B applications, APIs and special webservices
will use client requests with chunked encoding.
You can use this command to see if you have client traffic with
chunked encoding::
varnishlog -cq ReqHeader:Transfer-Encoding -i ReqMethod -i ReqURL
If you need some requests with chunked encoding to work, you will
have to write VCL code to white-list these clients based on IP/
authentication/cookies or other criteria, and then only call the
`exploit_workaround_xxx` function for the malicios clients.
Varnish 4.0.x (and Varnish Cache Plus 4.0.x)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set the `vcc_allow_inline` parameter to `true`, either by passing::
-pvcc_allow_inline_c=true
on the command line or by issuing the CLI command::
param.set vcc_allow_inline_c true
Then add this to the front of your VCL::
sub exploit_workaround_4_0 {
# This needs to come before your vcl_recv function
# The following code is only valid for Varnish Cache and
# Varnish Cache Plus versions 4.0.x
if (req.http.transfer-encoding ~ "(?i)chunked") {
C{
struct dummy_req {
unsigned magic;
int restarts;
int esi_level;
int disable_esi;
char hash_ignore_busy;
char hash_always_miss;
void *sp;
void *wrk;
int req_step;
struct {
void *a;
void *b;
};
int req_body_status;
};
((struct dummy_req *)ctx->req)->req_body_status = 6;
}C
return (synth(503, "Bad request"));
}
}
sub vcl_recv {
# Call this early in your vcl_recv function
call exploit_workaround_4_0;
}
Varnish 4.1.x and 5.0 (and Varnish Cache Plus 4.1.x)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set the `vcc_allow_inline` parameter to `true`, either by passing::
-pvcc_allow_inline_c=true
on the command line or by issuing the CLI command::
param.set vcc_allow_inline_c true
Then add this to the front of your VCL::
sub exploit_workaround_4_1 {
# This needs to come before your vcl_recv function
# The following code is only valid for Varnish Cache and
# Varnish Cache Plus versions 4.1.x and 5.0.0
if (req.http.transfer-encoding ~ "(?i)chunked") {
C{
struct dummy_req {
unsigned magic;
int step;
int req_body_status;
};
((struct dummy_req *)ctx->req)->req_body_status = 5;
}C
return (synth(503, "Bad request"));
}
}
sub vcl_recv {
# Call this early in your vcl_recv function
call exploit_workaround_4_1;
}
Varnish 5.1.x
~~~~~~~~~~~~~
Add this to the front of your VCL::
sub vcl_recv {
if (req.http.transfer-encoding ~ "(?i)chunked") {
return (fail);
}
}
Source code fix
~~~~~~~~~~~~~~~
The source code fix is this one-liner::
if (q == NULL || *q != '\0')
ERR("chunked header number syntax");
cl = (ssize_t)cll;
- if((uintmax_t)cl != cll)
+ if (cl < 0 || (uintmax_t)cl != cll)
ERR("bogusly large chunk size");
*priv = cl;
On varnish 4.0.x this change goes into `bin/varnishd/cache/cache_http1_proto.c`
on anything later it goes into `bin/varnishd/http1/cache_http1_vfp.c`.
Thankyous and credits
~~~~~~~~~~~~~~~~~~~~~
This issue was first noticed by StackPath.com, who contacted their vendor,
Varnish Software, who in turn notified the Varnish Cache project.
Varnish Software staff did most of the heavy lifting, and Martin in particular
gets a hat-tip for trawling the source-code for any similar issues.
And yes, I apologize for writing that buggy line of code.
*phk*
PS: See also: http://varnish-cache.org/docs/trunk/phk/VSV00001.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQJ8BAEBCgBmBQJZgZ9DXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w
ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXQ0MzU3NTkyM0I4RTExRDcwM0M2NjU1NDA4
RTVGNDRCQTY4RTY4OUM1AAoJEI5fRLpo5onF9m4P/jc4VXspvDevih9VTtvwJsZC
VWPclO7vA19JC2tKfDXRlsnlvezr0FzT25AbCWvXATV+cGkwYZ1ZV8uNVZ2yOU9j
7DXy4aBSgHdpfw2QiIn/5zUocCcebVvuzIJb41Tcpd7RWRSSb3LQbpP51qyYxDbn
ziPCM5QsyHk4CoNzSsUf2AK87AklwcNFEY2/yFXcTMUTvEt+IrKZidgNEDYmns0q
31vSQo68sXg69GNxrXtTL7EnF+GiFxd4lM40STJDgGnzc/d8O0CwgYvuPRD9SdXk
//3Xv2rfou5gw+4fXpEQ3EQm9eNjbAF1AuhI4uhf+/giwp+pJ7iJ3v5WBGHqirI0
KR6M6jz2DNQP5ZrztuaSl5alGVII01LnIOJMUYuIo4I8AU2xI8vm2ihXaOnl0D4b
Kf4FeQLd71ppAtnb1N6Ck0aLXcIKgfSzE/76fHXdGhnwyqP4cqbIucC4+vFE9DsG
u89mTeo++2cUliv19+250St3O/AEJfp58JOkX4wEFBWzc5mWsYDny/aG3Bl7+kKG
t/ammjMcscN+iQQaujoIxYVlFOCP3otcVjLGYeH+J9QLTItDgDBuPHSxpKuSB7L0
8vLbh330HlPiwZQy4yt+oSgiXKd/tmBhbBJCNCPWeGImSj7wwZNrOhKAqUzgU8o5
yeQ7p5fwKTlZqXjOiShT
=8PhG
-----END PGP SIGNATURE-----
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
phk at FreeBSD.ORG | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.
More information about the varnish-announce
mailing list