Skip to content

Unsafe attributes merge when parsing `use` tag

High
bsweeney published GHSA-jq98-9543-m4cr Dec 12, 2023

Package

composer dompdf/php-svg-lib (Composer)

Affected versions

<=0.5.0

Patched versions

0.5.1

Description

Summary

When handling <use> tag that references an <image> tag, it merges the attributes from the <use> tag to the <image> tag. The problem pops up especially when the href attribute from the <use> tag has not been sanitized. This can lead to an unsafe file read that can cause PHAR Deserialization vulnerability in PHP < 8.

Details

When parsing an <use> tag, it will try to find the referenced object refered by the href attribute. If it is found, it will save it on the $referenced property.

When UseTag::handle is called, the attributes of the <use> tag will be merged with the attributes of the referenced tag:

$mergedAttributes = $this->reference->attributes;
$attributesToNotMerge = ['x', 'y', 'width', 'height'];
foreach ($attributes as $attrKey => $attrVal) {
    if (!in_array($attrKey, $attributesToNotMerge) && !isset($mergedAttributes[$attrKey])) {
        $mergedAttributes[$attrKey] = $attrVal;
    }
}

As shown by the above code, the href attribute is included in the merging process, overiding the href attributes of the referenced tag.

The problem comes if the referenced object is an <image> tag, because the href of the original <image> tag will be overiden, thus bypasing any validation that has occured before for the <image> tag (this is the case in dompdf, as dompdf will sanitize the href attribute in svg file).

Now, after the merging process has finished, the referenced object's handle method is called:

$this->reference->handle($mergedAttributes);

When the <image> tag handle method is called, it will try to draw the image but with the href coming from the <use> tag:

// ImageTag::start
$this->document->getSurface()->drawImage($this->href, $this->x, $this->y, $this->width, $this->height);

Before drawing the image, it will use file_get_contents to load the image based on the href attribute

If this href is pointing to a phar file, it can lead to dangerous deserialization problem ini php <8.

PoC

This is the svg used in this research:

<svg width="200" height="200"
  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <image id="phar:///poc.phar" xlink:href="file:///existing/safe/image.png" />
  <use href="phar:///poc.phar" width="500" height="500"/>
</svg>

When the above code is parsed, the library will load the file via file_get_contents:

$data = file_get_contents("phar:///poc.phar");

Impact

In PHP < 8, the above vulnerability could lead to dangerous deserialization from the phar file. This could lead to file deletion (thus causing denial of service), and even RCE, depending on the classes available in the system.

Mitigation

Systems utilizing php-svg-lib can implement input validation using logic similar to the following:

$parser = xml_parser_create("utf-8");
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
xml_set_element_handler(
    $parser,
    function ($parser, $name, $attributes) {
        if (strtolower($name) === "image" || strtolower($name) === "use") {
            $attributes = array_change_key_case($attributes, CASE_LOWER);
            $urls = [];
            $urls[] = $attributes["xlink:href"] ?? "";
            $urls[] = $attributes["href"] ?? "";
            foreach ($urls as $url) {
                if (!empty($url)) {
                    // perform validation here
                }
            }
        }

        // include other tag/attribute validation
    },
    false
);

if (($fp = fopen($url, "r")) !== false) {
    while ($line = fread($fp, 8192)) {
        xml_parse($parser, $line, false);
    }
    fclose($fp);
    xml_parse($parser, "", true);
}
xml_parser_free($parser);

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Changed
Confidentiality
Low
Integrity
Low
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L

CVE ID

CVE-2023-50252

Weaknesses

Credits