Hello,

A team of security researchers notified me on Thursday evening that they
had found a dirty bug in HAProxy's headers processing, and that, when
properly exploited, this bug allows to build an HTTP content smuggling
attack. HTTP content smuggling attacks consist in passing extra requests
after a first one on a connection to a proxy, and making the subsequent
ones bypass the filtering in place.

Here, a properly crafted HTTP request can make HAProxy drop some important
headers fields such as Connection, Content-length, Transfer-Encoding, Host
etc after having parsed and at least partially processed them. Because of
this, the request that HAProxy forwards doesn't match what it thinks it is
and some parts of a request body can be used to create extra requests to
the server, that will not be filtered nor detected by HAProxy. This can
for example be used to bypass an authentication check that is present on
haproxy for some URLs, or access some restricted area that is normally
access only if some specific checks are validated. The difficulty to
build such attacks and their impact in great part depends on the site's
architecture and what the servers are willing to accept; if there's no
filtering, routing nor caching on HAProxy, at best some connections will
eventually fail and logs will not reflect the extraneous requests. In
general it's not trivial to build such an attack in that it depends on the
site, but it's not terribly difficult either for someone who sufficiently
knows HTTP internals and studies the fix.

The problem affects all versions at different degrees:

  - HTX-aware versions (2.0 in default config and all versions above) are
    impacted in HTTP/1. HTTP/2 and HTTP/3 also suffer from the bug but no
    parsing nor processing happens in the dropped headers so HAProxy stays
    properly synchronized with the server (i.e. there's no request
    smuggling attack there)

  - non-HTX versions (1.9 and before, or 2.0 in legacy mode) will not
    drop the theader, but will nonetheless pass the faulty request as-is
    to a server. This means that, while such versions will not be abused
    to attack a server, if placed at the edge they are not sufficient to
    protect an internal HAProxy instance either.

The issue was fixed in all versions and all modes (HTX and legacy), and all
versions were upgraded. The following status of supported versions is now
the following:

   Branch     Vulnerable               Fixed      Maintained until
   ---------+------------------------+----------+-----------------
   2.8-dev    2.8-dev0 .. 2.8-dev3     2.8-dev4     2028-Q4 (LTS)
   2.7        2.7.0 .. 2.7.2           2.7.3        2024-Q1
   2.6        2.6.0 .. 2.6.8           2.6.9        2027-Q2 (LTS)
   2.5        2.5.0 .. 2.5.11          2.5.12       2023-Q1
   2.4        2.4.0 .. 2.4.21          2.4.12       2026-Q2 (LTS)
   2.2        2.2.0 .. 2.2.28          2.2.29       2025-Q2 (LTS)
   2.0        2.0.0 .. 2.0.30          2.0.31       2024-Q2 (LTS)

Distros were notified (not very long ago admittedly, the delay was quite
short for them) and updated packages will appear soon. If you don't see
yours immediately, please be gentle, it takes time to build many versions.

If for any reason you're not sure where to retrieve an updated package,
as a reminder the list of available packages (both provided by distros
and by the community) is here:

   https://github.com/haproxy/wiki/wiki/Packages

If you're running on an outdated version (a branch that is not listed
above), the best short-term option will be to upgrade to the immediately
next branch, which is the one that will give you the least surprise or
changes. Please do not ask for help upgrading from outdated versions,
if you didn't care about updating in 5 years, it's unlikely that anyone
will care about helping you to catch up.

For those who for some reasons cannot update right now, we could design a
workaround that was tested on all of the versions above and in both modes
(legacy and HTX; only 2.0 has legacy). It consists in adding a rule in
each exposed frontend, preferably before other "http-request" statements,
that detects the internal condition that results from an exploitation
attempt of the bug (warning: it's a single very long line):

   http-request deny if { fc_http_major 1 } !{ req.body_size 0 } !{ 
req.hdr(content-length) -m found } !{ req.hdr(transfer-encoding) -m found } !{ 
method CONNECT }

   Note: versions 2.4 and above may optionally drop the final test on the
         "CONNECT" method as it's only strictly needed for 2.3 and earlier

This will result in rejecting the request with a 403 response if it tries
to abuse this bug in the parser. An increase in 403 in your logs may
indicate attempts to exploit the bug. With the fix deployed, a 400 (bad
request) will be returned and logged instead, and blocked HTTP/1 requests
will appear as usual with the details on the protocol violation in
"show errors". HTTP/2 and HTTP/3 requests are sent in binary format and
are currently not dumped in "show errors", though as mentioned above, they
should be mostly harmless.

As usual, config-based workarounds should only be seen as a fallback
solution in case it is not possible or desirable to deploy an update.
This one was extensively tested to make sure it doesn't block valid
traffic, but it is not possible to be certain it will block any form
of the attack, so it is not a durable solution anyway.

If you believe you face a regression after deploying the updated version,
please do the following:

  1) make sure the symptoms you're observing were not present in the
     last version of the same branch affected by the bug (i.e. the
     regression could come from another of the versions you've skipped)

  2) roll back to the latest known good version with the workaround
     above and report your problem, either on the mailing list or on
     the GitHub-hosted issue tracker after verifying that yours is not
     there yet:  https://github.com/haproxy/haproxy/issues

  3) as usual, please share any relevant info (confs, type of traffic,
     logs, stats, observations etc).

CVE-2023-25725 was assigned to this bug.

I would like to particularly thank the security research team composed
of Bahruz Jabiyev, Anthony Gavazzi, and Engin Kirda from Northeastern
University, Kaan Onarlioglu from Akamai Technologies, Adi Peleg and
Harvey Tuch from Google for their responsible disclosure of the problem
with sufficient details allowing the fix to be issued very quickly.

Big thumbs up as well to distro packagers for being so responsive to the
need of an emergency release, and to Robert Frohl from SuSE for filing and
handling the CVE.

A separate message will be sent for each verison.

Willy

Reply via email to