private static function parseBodyAndUploadedFiles(HttpRequestEvent $event): array
{
$bodyString = $event->getBody();
$files = [];
$parsedBody = null;
$contentType = $event->getContentType();
if ($contentType !== null && $event->getMethod() === 'POST') {
if (str_starts_with($contentType, 'application/x-www-form-urlencoded')) {
parse_str($bodyString, $parsedBody);
} else {
$document = new Part("Content-type: $contentType\r\n\r\n" . $bodyString);
if ($document->isMultiPart()) {
$parsedBody = [];
foreach ($document->getParts() as $part) {
if ($part->isFile()) {
$tmpPath = tempnam(sys_get_temp_dir(), 'bref_upload_');
if ($tmpPath === false) {
throw new RuntimeException('Unable to create a temporary directory');
}
file_put_contents($tmpPath, $part->getBody());
$file = new UploadedFile($tmpPath, filesize($tmpPath), UPLOAD_ERR_OK, $part->getFileName(), $part->getMimeType());
self::parseKeyAndInsertValueInArray($files, $part->getName(), $file);
} else {
self::parseKeyAndInsertValueInArray($parsedBody, $part->getName(), $part->getBody());
}
}
}
}
}
return [$files, $parsedBody];
}
The flow mimics what plain PHP does but it does not delete the temporary files when the request has been processed.
An attacker could fill the Lambda instance disk by performing multiple MultiPart requests containing files.
The attack has the following requirements and limitations:
<?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, [], exec("ls -lah /tmp/bref_upload* | wc -l"));
}
}
return new MyHttpHandler();
POST /upload HTTP/2
Host: <HOST>
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQqDeSZSSvmn2rfjb
Content-Length: 180
------WebKitFormBoundaryQqDeSZSSvmn2rfjb
Content-Disposition: form-data; name="a"; filename="a.txt"
Content-Type: text/plain
test
------WebKitFormBoundaryQqDeSZSSvmn2rfjb--
Delete the temporary files after the request has been processed and the response have been generated.
Impacted Resources
bref/src/Event/Http/Psr7Bridge.php:94-125
Description
When Bref is used with the Event-Driven Function runtime and the handler is a
RequestHandlerInterface
, then the Lambda event is converted to a PSR7 object.During the conversion process, if the request is a MultiPart, each part is parsed and for each which contains a file, it is extracted and saved in
/tmp
with a random filename starting withbref_upload_
.The function implementing the logic follows:
The flow mimics what plain PHP does but it does not delete the temporary files when the request has been processed.
Impact
An attacker could fill the Lambda instance disk by performing multiple MultiPart requests containing files.
The attack has the following requirements and limitations:
RequestHandlerInterface
handler.PoC
index.php
file with the following content:serverless.yml
to deploy the Lambda:<HOST>
placeholder with the deployed Lambda domain:Suggested Remediation
Delete the temporary files after the request has been processed and the response have been generated.
References