CVE-2021-21255 (PHP, published 2021-03-02T20:15Z)
Description: value: GLPI is an open-source asset and IT management software package that provides ITIL Service Desk features, licenses tracking and software auditing. In GLPI version 9.5.3, it was possible to switch entities with IDOR from a logged in user. This is fixed in version 9.5.4.
Severity: LOW (CVSS v3 base score: 5.7)
Weakness: CWE-639 \u2014 Authorization Bypass Through User-Controlled Key
The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.
Repository: https://github.com/glpi-project/glpi
Files changed:
ajax/dropdownTrackingDeviceType.php
inc/computer_item.class.php
inc/dropdown.class.php
inc/user.class.php
tests/functionnal/Dropdown.php
tests/functionnal/Session.php
Commit message: validate entity_restrict when available with idor tokens


Vulnerable code:
      '_idor_token'         => Session::getNewIDORToken($itemtype),
         '_idor_token'     => Session::getNewIDORToken($itemtype),
            'entity_restrict'      => (is_array($params['entity']) ? json_encode(array_values($params['entity'])) : $params['entity']),
            '_idor_token'          => Session::getNewIDORToken($itemtype),
      // check if asked itemtype is the one originaly requested by the form
      if (!Session::validateIDOR($post)) {
         return;
      }

         'entity_restrict'     => (is_array($p['entity']) ? json_encode(array_values($p['entity'])) : $p['entity']),
         '_idor_token'         => Session::getNewIDORToken(__CLASS__, ['right' => $p['right']]),
      $params['_idor_token'] = \Session::getNewIDORToken($params['itemtype'] ?? '');
      $params['_idor_token'] = \Session::getNewIDORToken($params['itemtype'] ?? '');

Fixed code:
      '_idor_token'         => Session::getNewIDORToken($itemtype, [
         'entity_restrict' => $_POST['entity_restrict'],
      ]),
         '_idor_token'     => Session::getNewIDORToken($itemtype, [
            'entity_restrict' => $entity_restrict,
         ]),
            'entity_restrict'      => ($entity_restrict = (is_array($params['entity']) ? json_encode(array_values($params['entity'])) : $params['entity'])),
            '_idor_token'          => Session::getNewIDORToken($itemtype, [
               'entity_restrict' => $entity_restrict,
            ]),
      // check if asked itemtype is the one originaly requested by the form
      if (!Session::validateIDOR($post)) {
         return;
      }

         'entity_restrict'     => ($entity_restrict = (is_array($p['entity']) ? json_encode(array_values($p['entity'])) : $p['entity'])),
         '_idor_token'         => Session::getNewIDORToken(__CLASS__, [
            'right'           => $p['right'],
            'entity_restrict' => $entity_restrict,
         ]),
      $params['_idor_token'] = $this->generateIdor($params);
      $params['_idor_token'] = $this->generateIdor($params);

   private function generateIdor(array $params = []) {
      $idor_add_params = [];
      if (isset($params['entity_restrict'])) {
         $idor_add_params['entity_restrict'] = $params['entity_restrict'];
      }
      return \Session::getNewIDORToken(($params['itemtype'] ?? ''), $idor_add_params);
   }
         ['itemtype' => 'User', 'add_params' => ['entity_restrict' => 0]],