CVE-2020-15175 (published 2020-10-07T19:15Z)

In GLPI before version 9.5.2, the `?pluginimage.send.php?` endpoint allows a user to specify an image from a plugin. The parameters can be maliciously crafted to instead delete the .htaccess file for the files directory. Any user becomes able to read all the files and folders contained in “/files/”. Some of the sensitive information that is compromised are the user sessions, logs, and more. An attacker would be able to get the Administrators session token and use that to authenticate. The issue is patched in version 9.5.2.

Severity: MEDIUM
CVSS v2 base score: 6.4 (AV:N/AC:L/Au:N/C:P/I:P/A:N)
CVSS v3 base score: 9.1, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N)

Weakness information:
cwe_id: CWE-552
cwe_name: Files or Directories Accessible to External Parties
description: The product makes files or directories accessible to unauthorized actors, even though they should not be.
extended_description: 
	   Web servers, FTP servers, and similar servers may store a set of files underneath a "root" directory that is accessible to the server's users.  Applications may store sensitive files underneath this root without also using access control to limit which users may request those files, if any.  Alternately, an application might package multiple files or directories into an archive file (e.g., ZIP or tar), but the application might not exclude sensitive files that are underneath those directories.
	   In cloud technologies and containers, this weakness might present itself in the form of misconfigured storage accounts that can be read or written by a public or anonymous user.
	 
         

Fix information:
repo_url: https://github.com/glpi-project/glpi
commit_details: repo_url: https://github.com/glpi-project/glpi
author: Cédric Anne
author_date: 2020-10-06 13:57:20+02:00
msg: Merge pull request from GHSA-rm52-jx9h-rwcp

- Prevent removal of any plugin file from unauthenticated user
- Prevent access to files outside plugins directories
- Prevent access to files from inactive plugins
- Limit access to images and fix content-type
- Add changelog entry
repository: repo_url: https://github.com/glpi-project/glpi
repo_name: glpi-project/glpi
description: GLPI is a Free Asset and IT Management Software package, Data center management, ITIL Service Desk, licenses tracking and software auditing.
repo_language: PHP
owner: glpi-project
file_changes: filename: CHANGELOG.md
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,7 @@ The present file will list all changes made to the project; according to the
 #### Removed
 
 - Ability to use SQL expressions as string in criterion values in SQL iterator (replaced by usage of `QueryExpression`).
+- Ability to delete a plugin image using `/front/pluginimage.send.php` script.
 
 ## [9.5.1] 2020-07-16
 

programming_language: Markdown
filename: pluginimage.send.php
change_type: ModificationType.MODIFY
diff: @@ -43,34 +43,36 @@ use Glpi\Event;
 
 include ('../inc/includes.php');
 
-if (!isset($_GET["name"]) || !isset($_GET["plugin"])) {
+if (!isset($_GET["name"]) || !isset($_GET["plugin"]) || !Plugin::isPluginActive($_GET["plugin"])) {
    Event::log("-1", "system", 2, "security",
               //TRANS: %s is user name
               sprintf(__('%s makes a bad usage.'), $_SESSION["glpiname"]));
    die("security");
 }
 
+$dir = GLPI_PLUGIN_DOC_DIR."/".$_GET["plugin"]."/";
+$filepath = $dir.$_GET["name"];
+
 if ((basename($_GET["name"]) != $_GET["name"])
-    || (basename($_GET["plugin"]) != $_GET["plugin"])) {
+    || (basename($_GET["plugin"]) != $_GET["plugin"])
+    || !Toolbox::startsWith(realpath($filepath), realpath(GLPI_PLUGIN_DOC_DIR))
+    || !Document::isImage($filepath)) {
 
    Event::log("-1", "system", 1, "security",
               sprintf(__('%s tries to use a non standard path.'), $_SESSION["glpiname"]));
    die("security");
 }
-$Path = GLPI_PLUGIN_DOC_DIR."/".$_GET["plugin"]."/";
 
 // Now send the file with header() magic
 header("Expires: Sun, 30 Jan 1966 06:30:00 GMT");
 header('Pragma: private'); /// IE BUG + SSL
 header('Cache-control: private, must-revalidate'); /// IE BUG + SSL
 header('Content-disposition: filename="' . $_GET["name"] . '"');
-header("Content-type: image/png");
 
-if (file_exists($Path.$_GET["name"])) {
-   readfile($Path.$_GET["name"]);
-   if (isset($_GET["clean"])) {
-      unlink($Path.$_GET["name"]);
-   }
+if (file_exists($filepath)) {
+   header("Content-type: " . Toolbox::getMime($filepath));
+   readfile($filepath);
 } else {
+   header("Content-type: image/png");
    readfile($CFG_GLPI['root_doc'] . "/pics/warning.png");
 }

programming_language: PHP