Bad sanitization of uploaded file's content, type and extension in the Asset Edition feature allows an authenticated attacker to write arbitrary PHP code inside the web directory and locate where said file is written. This results in Remote Code Execution.
A path traversal also allows to exploit this functionality to recursively delete any directory on the filesystem that the web-user has permission to modify.
When editing an Asset via the route /assets/view/{assetID}
, possibility is given to change the file of the asset.
Uploading a new file ultimately calls the following function inside app/Bundles/AssetBundle/Controller/AssetController.php
:
public function editAction(Request $request, UploaderHelper $uploaderHelper, AssetModel $model, $objectId, $ignorePost = false)
The upload logic can be found here:
if (!$ignorePost && 'POST' == $method) {
$valid = false;
if (!$cancelled = $this->isFormCancelled($form)) {
if ($valid = $this->isFormValid($form)) {
$entity->setUploadDir($this->coreParametersHelper->get('upload_dir'));
$entity->preUpload();
$entity->upload();
More particularly, we are interested in the preUpload()
and upload()
methods, as they handle the actual file write on disk.
The first defect lies in preUpload()
in app/Bundles/AssetBundle/Entity/Asset.php
, as the implementation allows us to specify an arbitray file extension (thus bypassing the protection normally provided by the allowed_extensions array):
$filename = sha1(uniqid(mt_rand(), true));
$extension = $this->getFile()->guessExtension();
if (empty($extension)) {
// get it from the original name
$extension = pathinfo($this->originalFileName, PATHINFO_EXTENSION);
}
$this->path = $filename.'.'.$extension;
The line $extension = $this->getFile()->guessExtension();
will return NULL if we a provide a filename ending with .php
and content starting with <?php
tag.
The empty($extension) check will therefore evaluate to true, and file extension will then be extracted through pathinfo()
call, thus allowing us to upload temporary files with arbitrary content and extension. We can't control the actual name of the file as it is generated with sha1().
Then, inside the subsequent upload() method, the file will actually be written to disk inside the web directory through the following call:
$this->getFile()->move($this->getUploadDir(), $this->path);
It is using our arbitrary extension (contained in $this->path var). Name of the file can then be retrieved by refreshing the Asset details page (/assets/view/{assetId}), under the Local filename table entry.
NB : This also works by altering the requests sent when creating a new Asset. This will call the newAction() function, but the logic is identical, and defects still lie in preUpload() and upload() methods.
The PoC will not published for another month or so.
This is to give time for the organisations that rely on this software to patch it without fearing script kiddies wrecking their stuff.
After that, this repo will be updated with the full exploitation script and proofs. There is already enough info on this page anyway.
When validating a temporary upload (via /s/assets/new or /s/assets/edit/{assetId}), the directory storing the temporary file is recursively deleted at the end of the request. The parameter responsible to hold the name of the temporary directory is susceptible to path traversal attacks, allowing an authenticated attacker to delete any directory on the system, provided that web user has permission to do so. This can result in loss of data, or even destruction of the entire filesystem if server happens to be executed by the root user.
Specify any file that exists on the system through the endpoint used below. If the file exists, the server will attempt to delete the directory it is stored in.
Server takeover Denial of Service Loss of Data
- Oct 14th 2024 : First reach out and advisory sent to Mautic team
- Nov 12th 2024 : Exploitation script and remediation suggestions sent to development team
- Dec 13th 2024 : Second reach out
- Jan 21st 2025 : Patch ready for deployment
- Feb 25th 2025 : CVE assigned and published