Re: Options for mitigating CVE-2023-44487 with HAProxy

2023-10-10 Thread Willy Tarreau
On Tue, Oct 10, 2023 at 10:03:32PM +, Lukas Tribus wrote:
> On Tue, 10 Oct 2023 at 20:22, Willy Tarreau  wrote:
> >
> > So at this point I'm still failing to find any case where this attack
> > hurts haproxy more than any of the benchmarks we're routinely inflicting
> > it, given that it acts exactly like a client configured with a short
> > timeout (e.g. if you configure haproxy with "timeout server 1" and
> > have an h2 server, you will basically get the same traffic pattern).
> 
> This is pretty much the situation with nginx as well:
> 
> https://mailman.nginx.org/pipermail/nginx-devel/2023-October/S36Q5HBXR7CAIMPLLPRSSSYR4PCMWILK.html

Thanks for the pointer Lukas. I'm not surprized at all, and Maxim has
all my sympathy on this when he speaks about FUD. Stacks like haproxy
and nginx which have been exposed for a long time to amazing amounts
of garbage (and even to their own bugs sometimes) naturally had to be
made more robust against this type of misbehavior.

I'm noticing that they're counting resets and fixing some limits, but
this can very easily be triggered by a legit client clicking stop a
few times while loading many objects in parallel. Stefan Eissing said
somewhere that in Apache they implement a "mood" on a connection
indicating how apache feels about that connection and that as bad stuff
happens its mood degrades and it progressively reduces the processing
on that connection. I find this quite interesting because instead of
taking many parameters into account, any event can say "that peer is
not very nice with us". And we could count a ratio of number of streams
that are reset before the response to the the total number of streams,
as this is a normal behavior for a client clicking stop, but it should
not represent high ratios. I was thinking that we could imagine sending
settings with a reduced SETTINGS_MAX_CONCURRENT_STREAMS when bad stuff
like this happens.

I remember that we mentioned a while ago that it could be useful to
implement a total stream limit per connection to force to reconnect,
but my primary use case was to force h2load to disconnect/reconnect
in tests. It could also increase the cost a little bit for the client
here, though it would also increase the cost for the proxy by forcing
new SSL connections more often.

Amaury told me that H3/QUIC was not affected by this thanks to the
way streams are flow-controlled, since the server must send a frame
to allow the client to create new streams. And it turns out that
Martin Thomson of the IETF HTTP WG proposed something very similar
which could improve the situation:

  
https://martinthomson.github.io/h2-stream-limits/draft-thomson-httpbis-h2-stream-limits.html

So we can expect improvements in that area in the foreseable future.

Willy



Re: Options for mitigating CVE-2023-44487 with HAProxy

2023-10-10 Thread Lukas Tribus
On Tue, 10 Oct 2023 at 20:22, Willy Tarreau  wrote:
>
> So at this point I'm still failing to find any case where this attack
> hurts haproxy more than any of the benchmarks we're routinely inflicting
> it, given that it acts exactly like a client configured with a short
> timeout (e.g. if you configure haproxy with "timeout server 1" and
> have an h2 server, you will basically get the same traffic pattern).

This is pretty much the situation with nginx as well:

https://mailman.nginx.org/pipermail/nginx-devel/2023-October/S36Q5HBXR7CAIMPLLPRSSSYR4PCMWILK.html



Lukas



Re: Options for mitigating CVE-2023-44487 with HAProxy

2023-10-10 Thread Willy Tarreau
On Tue, Oct 10, 2023 at 07:23:25PM +, Tristan wrote:
> Thanks for looking into it, Willy :-)

You're welcome. Actually last week I ran some tests *exactly* on this,
thinking that it was the same principle as leaving orphaned sockets
when you're limited on FDs. That's how I discovered the pool bug I
mentioned the other day related to my recent change in -dev (that I
still need to fix). I thought that it would be interesting to run a
similar test on other stacks, but being busy on other more serious
stuff and not being good at installing and testing software, I went
back to my usual activities. I was aware that something was going to
be announced without knowing what the problem was so I thought it was
really not worth wasting more time on an issue if one was going to
appear anyway, likely in the same area. I wouldn't have imagined it
was exactly that one, though as it didn't look harmful enough
(otherwise I would have fixed it last week and it could have looked
like a leak for those working on theirs). But you can now understand
better why I was particularly interested in having a deeper look into
it now that we had the details ;-)

> > On 10 Oct 2023, at 19:24, Willy Tarreau  wrote:
> >  [...]
> > But for now if you site requires any of this, I can't see how it has not
> > experienced weekly outages from standard attacks.
> 
> Funny that you mention this; bit out of topic but we had enjoyed a relatively
> peaceful 2023 for the most part, after some law enforcement operations last
> December/January. [1]
> 
> But things are picking up pace again since mid-summer, and this is indeed
> just one of what feels like a new attack method a week that we hear of or
> have the displeasure to receive...
> Though most seem to be either L4 or non-HTTP L7.

One important thing when you're sure you're dealing with targetted attacks
is that you must not discuss them publicly, or you're giving a lot of info
to your attackers about what you identify and how you're going to mitigate
them. Sometimes you may even have to manually switch between an efficient
config and a more robust one (the ".if" in the config sometimes help for
this). I just hope you won't need that as it's quite annoying when it
happens.

> > As Tristan mentioned, lowering tune.h2.be.max-concurrent-streams may
> > also slow them down but it will also slow down some sites with many
> > objects (think shops with many images). For a long time the high
> > parallelism of H2 was sold as a huge differentiator, I don't feel like
> > starting to advertise lowering it now.
> 
> For others that may be tempted to copypaste it and seeing errors, I think you
> meant tune.h2.fe.max-... (emphasis on « fe »)

Hehe indeed, I copy-pasted it from the doc but picked the wrong one! Thanks
for correcting me!

> > There are lots of other interesting attacks on the H2 protocol, that
> > can be triggered just with a regular client with low timeouts, with low
> > stream windows (use h2load -w 1 to have fun), zero-window during transfers,
> > and even playing with one-byte continuation frames that may force some
> > components to perform reallocations and copies.
> 
> Are protections for these baked into the defaults/protocol or is there some
> reading+tweaking one could consider for hardening purposes? As in even at the
> cost of compatibility with « odd » clients.

A bit of everything I would say. The implementation, the protocol, the
timeouts, some possibilities with some rules when dealing with specific
attacks, etc. The one about the small windows is more annoying. I've
been thinking several times about whether we should implement a setting
to reject connections with too small initial windows, but such approaches
can also easily be worked around by the attacker accepting to download
the initial data. What matters is always what it costs to the attacker
to take you down. With small windows, the impact is only higher CPU
usage and it still requires high bandwidth and low latency with the
attacker. And when bandwidth and low latency are present, then attacks
can switch to SSL keying which is quite cheap for a client. The H2 small
windows attacks are not very different from L4 attacks advertising very
small TCP MSS actually. Sometimes it's also when facing such corner
cases that are difficult to address in one or another context that we
decide that we need to add a new tunable. I just prefer to refrain from
doing so until really necessary, in order to limit the complexity of
counter-measures when they're needed!

Cheers,
Willy



Re: Options for mitigating CVE-2023-44487 with HAProxy

2023-10-10 Thread Tristan
Thanks for looking into it, Willy :-)

> On 10 Oct 2023, at 19:24, Willy Tarreau  wrote:
>  […]
> But for now if you site requires any of this, I can't see how it has not
> experienced weekly outages from standard attacks.

Funny that you mention this; bit out of topic but we had enjoyed a relatively 
peaceful 2023 for the most part, after some law enforcement operations last 
December/January. [1]

But things are picking up pace again since mid-summer, and this is indeed just 
one of what feels like a new attack method a week that we hear of or have the 
displeasure to receive…
Though most seem to be either L4 or non-HTTP L7.

> As Tristan mentioned, lowering tune.h2.be.max-concurrent-streams may
> also slow them down but it will also slow down some sites with many
> objects (think shops with many images). For a long time the high
> parallelism of H2 was sold as a huge differentiator, I don't feel like
> starting to advertise lowering it now.

For others that may be tempted to copypaste it and seeing errors, I think you 
meant tune.h2.fe.max-… (emphasis on « fe »)

> There are lots of other interesting attacks on the H2 protocol, that
> can be triggered just with a regular client with low timeouts, with low
> stream windows (use h2load -w 1 to have fun), zero-window during transfers,
> and even playing with one-byte continuation frames that may force some
> components to perform reallocations and copies.

Are protections for these baked into the defaults/protocol or is there some 
reading+tweaking one could consider for hardening purposes? As in even at the 
cost of compatibility with « odd » clients.

Regards,
Tristan

[1] 
https://krebsonsecurity.com/2022/12/six-charged-in-mass-takedown-of-ddos-for-hire-sites/

Re: Options for mitigating CVE-2023-44487 with HAProxy

2023-10-10 Thread Willy Tarreau
On Tue, Oct 10, 2023 at 03:57:09PM +0200, Willy Tarreau wrote:
> On Tue, Oct 10, 2023 at 03:49:21PM +0200, Willy Tarreau wrote:
> > > Seems like a clever update to the "good old" h2 multiplexing abuse 
> > > vectors:
> > > 1. client opens a lot of H2 streams on a connection
> > > 2. Spams some requests
> > > 3. immediately sends h2 RST frames for all of them
> > > 4. Go back to 1. repeat.
> > 
> > Yes, precisely one of those I tested last week among the usual approchaes
> > consisting in creating tons of streams while staying within the protocol's
> > validity limits. The only thing it did was to detect the pool issue I
> > mentioned in the dev7 announce.
> > 
> > > The idea being to cause resource exhaustion on the server/proxy at least
> > > when it allocates stream related buffers etc, and the underlying server 
> > > too
> > > since it likely sees the requests before they get cancelled.
> > > 
> > > Looking at HAProxy I'd like to know if someone's aware of a decent
> > > mitigation option?
> > 
> > We first need to check if at all we're affected, since we keep a count
> > of the attached streams for precisely this case and we refrain from
> > processing headers frames when we have too many streams, so normally
> > the mux will pause waiting for the upper layers to close.
> 
> So at first glance we indeed addressed this case in 2018 (1.9-dev)
> with this commit:
> 
>   f210191dc ("BUG/MEDIUM: h2: don't accept new streams if conn_streams are 
> still in excess")
> 
> It was incomplete by then an later refined, but the idea is there.
> But I'll try to stress that area again to see.

So I was bored by wasting my time trying to harm the process from scripts,
I finally wrote a small program that does the same but much faster. For
now it's boring as well. In short:

  - the concurrency issue was addressed 5 years ago with the commit
above so all maintained version are immune to this. The principle
is that each H2 connection knows both the number of protocol-level
streams attached to them but also application-level streams, and
it's that one that enforces the limit, preventing from processing
more requests until the number of active streams is within the limit
again. In the worst case (i.e. if the attacker downloads and its
window updates cannot enter anymore), the streams will simply time
out then the connection, like on a single non-multiplexed connection
so nothing new here. It also means that no more than the configured
limit of streams per connection will reach the hosted application
at once.

  - the risk of CPU usage that was also mentioned is not much relevant
either. These aborted requests actually cost less CPU than completed
ones, and on my laptop I found that I would reach up to 100-150k req/s
per core (depending on CPU thermal throttling) which is perfectly
within what we normally observe with a standard h2load injection.
With less streams I could even reach 1 million requests per second
total, because they were aborted before being turned into a regular
stream, so the load was essentially between haproxy and the client.

So at this point I'm still failing to find any case where this attack
hurts haproxy more than any of the benchmarks we're routinely inflicting
it, given that it acts exactly like a client configured with a short
timeout (e.g. if you configure haproxy with "timeout server 1" and
have an h2 server, you will basically get the same traffic pattern).

If you want to block some annoying testers who would fill your logs
in the next few days, I checked that the following works fine here
(set the limit to the max number of requests per 10 seconds you want
to accept, e.g. 1000 below, or 100/s to keep a large margin):

  tcp-request connection track-sc0 src
  http-request reject if { sc0_http_req_rate gt 1000 }
  stick-table type ip size 1m store http_req_rate(10s)

It's even possible to play with "set-log-level silent" to avoid logging
them, and you may even block new connections at the TCP layer. But
for now if you site requires any of this, I can't see how it has not
experienced weekly outages from standard attacks. Note that when I'm
saying that it's not because your server can process 2 million req/s
that you have to use it at that speed on a single machine, it's exactly
to keep that type of comfortable margin.

I tested the client on an EPYC 74F3 server (24 cores at 3 GHz, the one
that I demoed at haproxyconf) and it handles 800k req/s at saturation,
spending most of its time in the weighted roundrobin lock (it reaches
850k with random so pretty much standard for this machine), and perf
top looks good:

  Samples: 9M of event 'cycles', 4000 Hz, Event count (approx.): 864711451063 
lost: 0/0 drop: 0/0
  Overhead  Shared Object Symbol
 4.11%  haproxy   [.] process_stream
 3.29%  haproxy   [.] srv_add_to_idle_list
 3.02%  haproxy   [.

Re: Options for mitigating CVE-2023-44487 with HAProxy

2023-10-10 Thread Willy Tarreau
On Tue, Oct 10, 2023 at 03:49:21PM +0200, Willy Tarreau wrote:
> > Seems like a clever update to the "good old" h2 multiplexing abuse vectors:
> > 1. client opens a lot of H2 streams on a connection
> > 2. Spams some requests
> > 3. immediately sends h2 RST frames for all of them
> > 4. Go back to 1. repeat.
> 
> Yes, precisely one of those I tested last week among the usual approchaes
> consisting in creating tons of streams while staying within the protocol's
> validity limits. The only thing it did was to detect the pool issue I
> mentioned in the dev7 announce.
> 
> > The idea being to cause resource exhaustion on the server/proxy at least
> > when it allocates stream related buffers etc, and the underlying server too
> > since it likely sees the requests before they get cancelled.
> > 
> > Looking at HAProxy I'd like to know if someone's aware of a decent
> > mitigation option?
> 
> We first need to check if at all we're affected, since we keep a count
> of the attached streams for precisely this case and we refrain from
> processing headers frames when we have too many streams, so normally
> the mux will pause waiting for the upper layers to close.

So at first glance we indeed addressed this case in 2018 (1.9-dev)
with this commit:

  f210191dc ("BUG/MEDIUM: h2: don't accept new streams if conn_streams are 
still in excess")

It was incomplete by then an later refined, but the idea is there.
But I'll try to stress that area again to see.

Willy



Re: Options for mitigating CVE-2023-44487 with HAProxy

2023-10-10 Thread Willy Tarreau
Hi Tristan,

On Tue, Oct 10, 2023 at 12:56:12PM +, Tristan wrote:
> Hi all,
> 
> This just got disclosed:
> - 
> https://cloud.google.com/blog/products/identity-security/google-cloud-mitigated-largest-ddos-attack-peaking-above-398-million-rps/
> - 
> https://cloud.google.com/blog/products/identity-security/how-it-works-the-novel-http2-rapid-reset-ddos-attack

Yes, finally it's public.

> Seems like a clever update to the "good old" h2 multiplexing abuse vectors:
> 1. client opens a lot of H2 streams on a connection
> 2. Spams some requests
> 3. immediately sends h2 RST frames for all of them
> 4. Go back to 1. repeat.

Yes, precisely one of those I tested last week among the usual approchaes
consisting in creating tons of streams while staying within the protocol's
validity limits. The only thing it did was to detect the pool issue I
mentioned in the dev7 announce.

> The idea being to cause resource exhaustion on the server/proxy at least
> when it allocates stream related buffers etc, and the underlying server too
> since it likely sees the requests before they get cancelled.
> 
> Looking at HAProxy I'd like to know if someone's aware of a decent
> mitigation option?

We first need to check if at all we're affected, since we keep a count
of the attached streams for precisely this case and we refrain from
processing headers frames when we have too many streams, so normally
the mux will pause waiting for the upper layers to close.

> My current first guess was to adapt F5's recommendations here
> https://my.f5.com/manage/s/article/K000137106, ie set
> tune.h2.fe.max-concurrent-streams 10

I *tend* to think that just like for H1 with connect+GET+shut(),
"option abortonclose" should be sufficient. But I'll run more tests.

> But I'm not sure if there's a way to apply the suggested measure (by Google
> this time) of catching misbehaving clients (opening more streams that
> advertised, or sending a lot of reset frames).

It's possible that storing http_fail_rate in a stick-table could be
sufficient to flag them as abusing. I don't know yet.

> Finally I'll note that I don't currently have access to a good way to test
> how much it affects HAProxy. And maybe it doesn't due to some peculiar
> implementation detail. But that would be good to know.

I'll run some tests on this, I can forge sequences of frames like this.

Thanks,
Willy