CVE-2020-15411: Insufficient Information (NVD-CWE-noinfo)
value: An issue was discovered in MISP 2.4.128. app/Controller/AttributesController.php has insufficient ACL checks in the attachment downloader.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 9.8
Published: 2020-06-30T14:15Z
Repository: https://github.com/MISP/MISP
Language: PHP
Files changed: app/Controller/AttributesController.php
Commit date: 2020-06-29 14:10:23 +0200
Commit message: fix: [security] Insufficient ACL checks in the attachment downloader fixed
- Thanks to Jakub Onderka for reporting it

Diff: diff --git a/app/Controller/AttributesController.php b/app/Controller/AttributesController.php
index 8dcc3632410..78a64ca7fd2 100644
--- a/app/Controller/AttributesController.php
+++ b/app/Controller/AttributesController.php
@@ -347,25 +347,23 @@ class AttributesController extends AppController
         $this->set('action', $this->action);
     }
 
     public function download($id = null)
     {
-        $this->Attribute->id = $id;
-        if (!$this->Attribute->exists()) {
-            throw new NotFoundException(__('Invalid attribute'));
+        if (is_numeric($id)) {
+            $conditions = array('Attribute.id' => $id);
+        } elseif (Validation::uuid($id)) {
+            $conditions = array('Attribute.uuid' => $id);
+        } else {
+            throw new NotFoundException(__('Invalid attribute id.'));
+        }
+        $conditions['Attribute.type'] = array('attachment', 'malware-sample');
+        $attributes = $this->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => $conditions, 'flatten' => true));
+        if (empty($attributes)) {
+            throw new UnauthorizedException(__('Attribute does not exists or you do not have the permission to download this attribute.'));
         }
-        $this->Attribute->read();
-        if (!$this->_isSiteAdmin() &&
-            $this->Auth->user('org_id') !=
-            $this->Attribute->data['Event']['org_id'] &&
-            (
-                $this->Attribute->data['Event']['distribution'] == 0 ||
-                $this->Attribute->data['Attribute']['distribution'] == 0
-            )) {
-            throw new UnauthorizedException(__('You do not have the permission to view this event.'));
-        }
-        $this->__downloadAttachment($this->Attribute->data['Attribute']);
+        $this->__downloadAttachment($attributes[0]['Attribute']);
     }
 
     private function __downloadAttachment($attribute)
     {
         $attachments_dir = Configure::read('MISP.attachments_dir');
@@ -2014,24 +2012,23 @@ class AttributesController extends AppController
         // if the user is authorised to use the api key then user will be populated with the user's account
         // in addition we also set a flag indicating whether the user is a site admin or not.
         if (!$user) {
             throw new UnauthorizedException(__('This authentication key is not authorized to be used for exports. Contact your administrator.'));
         }
-        $this->Attribute->id = $id;
-        if (!$this->Attribute->exists()) {
-            throw new NotFoundException(__('Invalid attribute or no authorisation to view it.'));
-        }
-        $this->Attribute->read(null, $id);
-        if (!$user['User']['siteAdmin'] &&
-            $user['User']['org_id'] != $this->Attribute->data['Event']['org_id'] &&
-            (
-                $this->Attribute->data['Event']['distribution'] == 0 ||
-                $this->Attribute->data['Attribute']['distribution'] == 0
-            )) {
-            throw new NotFoundException(__('Invalid attribute or no authorisation to view it.'));
-        }
-        $this->__downloadAttachment($this->Attribute->data['Attribute']);
+        if (is_numeric($id)) {
+            $conditions = array('Attribute.id' => $id);
+        } elseif (Validation::uuid($id)) {
+            $conditions = array('Attribute.uuid' => $id);
+        } else {
+            throw new NotFoundException(__('Invalid attribute id.'));
+        }
+        $conditions['Attribute.type'] = array('attachment', 'malware-sample');
+        $attributes = $this->Attribute->fetchAttributes($user, array('conditions' => $conditions, 'flatten' => true));
+        if (empty($attributes)) {
+            throw new UnauthorizedException(__('Attribute does not exists or you do not have the permission to download this attribute.'));
+        }
+        $this->__downloadAttachment($attributes[0]['Attribute']);
     }
 
     public function text()
     {
         $this->_legacyAPIRemap(array(

Vulnerable code:         $this->Attribute->id = $id;
        if (!$this->Attribute->exists()) {
            throw new NotFoundException(__('Invalid attribute'));
        $this->Attribute->read();
        if (!$this->_isSiteAdmin() &&
            $this->Auth->user('org_id') !=
            $this->Attribute->data['Event']['org_id'] &&
            (
                $this->Attribute->data['Event']['distribution'] == 0 ||
                $this->Attribute->data['Attribute']['distribution'] == 0
            )) {
            throw new UnauthorizedException(__('You do not have the permission to view this event.'));
        }
        $this->__downloadAttachment($this->Attribute->data['Attribute']);
        $this->Attribute->id = $id;
        if (!$this->Attribute->exists()) {
            throw new NotFoundException(__('Invalid attribute or no authorisation to view it.'));
        }
        $this->Attribute->read(null, $id);
        if (!$user['User']['siteAdmin'] &&
            $user['User']['org_id'] != $this->Attribute->data['Event']['org_id'] &&
            (
                $this->Attribute->data['Event']['distribution'] == 0 ||
                $this->Attribute->data['Attribute']['distribution'] == 0
            )) {
            throw new NotFoundException(__('Invalid attribute or no authorisation to view it.'));
        }
        $this->__downloadAttachment($this->Attribute->data['Attribute']);
Fixed code:         if (is_numeric($id)) {
            $conditions = array('Attribute.id' => $id);
        } elseif (Validation::uuid($id)) {
            $conditions = array('Attribute.uuid' => $id);
        } else {
            throw new NotFoundException(__('Invalid attribute id.'));
        }
        $conditions['Attribute.type'] = array('attachment', 'malware-sample');
        $attributes = $this->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => $conditions, 'flatten' => true));
        if (empty($attributes)) {
            throw new UnauthorizedException(__('Attribute does not exists or you do not have the permission to download this attribute.'));
        $this->__downloadAttachment($attributes[0]['Attribute']);
        if (is_numeric($id)) {
            $conditions = array('Attribute.id' => $id);
        } elseif (Validation::uuid($id)) {
            $conditions = array('Attribute.uuid' => $id);
        } else {
            throw new NotFoundException(__('Invalid attribute id.'));
        }
        $conditions['Attribute.type'] = array('attachment', 'malware-sample');
        $attributes = $this->Attribute->fetchAttributes($user, array('conditions' => $conditions, 'flatten' => true));
        if (empty($attributes)) {
            throw new UnauthorizedException(__('Attribute does not exists or you do not have the permission to download this attribute.'));
        }
        $this->__downloadAttachment($attributes[0]['Attribute']);