CVE-2019-9482: Missing Authorization (CWE-862)
value: In MISP 2.4.102, an authenticated user can view sightings that they should not be eligible for. Exploiting this requires access to the event that has received the sighting. The issue affects instances with restrictive sighting settings (event only / sighting reported only).
CWE description: The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
CVSS v3 base score: 5.3
Published: 2019-03-01T05:29Z
Repository: https://github.com/MISP/MISP
Language: PHP
Files changed: app/Controller/SightingsController.php
Commit date: 2019-02-28 20:27:36 +0100
Commit message: fix: [vulnerability] Fixes a vulnerability where a user can view sightings that they should not be eligible for

- requires access to the event that has received the sighting
- affects instances with restrictive sighting settings (event only / sighting reported only)

- as reported by Tyler McLellan of CanCyber.org

Diff: diff --git a/app/Controller/SightingsController.php b/app/Controller/SightingsController.php
index 94537e4212e..ecee462b50f 100644
--- a/app/Controller/SightingsController.php
+++ b/app/Controller/SightingsController.php
@@ -339,26 +339,76 @@ class SightingsController extends AppController
             'conditions' => $conditions,
             'recursive' => -1,
             'contain' => array('Organisation.name'),
             'order' => array('Sighting.date_sighting DESC')
         ));
+        if (!empty($sightings) && empty(Configure::read('Plugin.Sightings_policy')) && !$this->_isSiteAdmin()) {
+            $eventOwnerOrgIdList = array();
+            foreach ($sightings as $k => $sighting) {
+                if (empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']])) {
+                    $temp_event = $this->Event->find('first', array(
+                        'recursive' => -1,
+                        'conditions' => array('Event.id' => $sighting['Sighting']['event_id']),
+                        'fields' => array('Event.id', 'Event.orgc_id')
+                    ));
+                    $eventOwnerOrgIdList[$temp_event['Event']['id']] = $temp_event['Event']['orgc_id'];
+                }
+                if (empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']]) || $eventOwnerOrgIdList[$sighting['Sighting']['event_id']] !== $this->Auth->user('org_id')) {
+                    unset($sightings[$k]);
+                }
+            }
+            $sightings = array_values($sightings);
+        } else if (!empty($sightings) && Configure::read('Plugin.Sightings_policy') == 1 && !$this->_isSiteAdmin()) {
+            $eventsWithOwnSightings = array();
+            foreach ($sightings as $k => $sighting) {
+                if (empty($eventsWithOwnSightings[$sighting['Sighting']['event_id']])) {
+                    $eventsWithOwnSightings[$sighting['Sighting']['event_id']] = false;
+                    $sighting_temp = $this->Sighting->find('first', array(
+                        'recursive' => -1,
+                        'conditions' => array(
+                            'Sighting.event_id' => $sighting['Sighting']['event_id'],
+                            'Sighting.org_id' => $this->Auth->user('org_id')
+                        )
+                    ));
+                    if (empty($sighting_temp)) {
+                        $temp_event = $this->Event->find('first', array(
+                            'recursive' => -1,
+                            'conditions' => array(
+                                'Event.id' => $sighting['Sighting']['event_id'],
+                                'Event.orgc_id' => $this->Auth->user('org_id')
+                            ),
+                            'fields' => array('Event.id', 'Event.orgc_id')
+                        ));
+                        $eventsWithOwnSightings[$sighting['Sighting']['event_id']] = !empty($temp_event);
+                    } else {
+                        $eventsWithOwnSightings[$sighting['Sighting']['event_id']] = true;
+                    }
+                }
+                if (!$eventsWithOwnSightings[$sighting['Sighting']['event_id']]) {
+                    unset($sightings[$k]);
+                }
+            }
+            $sightings = array_values($sightings);
+        }
         $this->set('org_id', $org_id);
         $this->set('rawId', $rawId);
         $this->set('context', $context);
         $this->set('types', array('Sighting', 'False-positive', 'Expiration'));
         if (Configure::read('Plugin.Sightings_anonymise') && !$this->_isSiteAdmin()) {
-            foreach ($sightings as $k => $v) {
-                if ($v['Sighting']['org_id'] != $this->Auth->user('org_id')) {
-                    $sightings[$k]['Organisation']['name'] = '';
-                    $sightings[$k]['Sighting']['org_id'] = 0;
+            if (!empty($sightings)) {
+                foreach ($sightings as $k => $v) {
+                    if ($v['Sighting']['org_id'] != $this->Auth->user('org_id')) {
+                        $sightings[$k]['Organisation']['name'] = '';
+                        $sightings[$k]['Sighting']['org_id'] = 0;
+                    }
                 }
             }
         }
         if ($this->_isRest()) {
             return $this->RestResponse->viewData($sightings, $this->response->type());
         }
-        $this->set('sightings', $sightings);
+        $this->set('sightings', empty($sightings) ? array() : $sightings);
         $this->layout = false;
         $this->render('ajax/list_sightings');
     }
 
     public function viewSightings($id, $context = 'attribute')

Vulnerable code:             foreach ($sightings as $k => $v) {
                if ($v['Sighting']['org_id'] != $this->Auth->user('org_id')) {
                    $sightings[$k]['Organisation']['name'] = '';
                    $sightings[$k]['Sighting']['org_id'] = 0;
        $this->set('sightings', $sightings);
Fixed code:         if (!empty($sightings) && empty(Configure::read('Plugin.Sightings_policy')) && !$this->_isSiteAdmin()) {
            $eventOwnerOrgIdList = array();
            foreach ($sightings as $k => $sighting) {
                if (empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']])) {
                    $temp_event = $this->Event->find('first', array(
                        'recursive' => -1,
                        'conditions' => array('Event.id' => $sighting['Sighting']['event_id']),
                        'fields' => array('Event.id', 'Event.orgc_id')
                    ));
                    $eventOwnerOrgIdList[$temp_event['Event']['id']] = $temp_event['Event']['orgc_id'];
                }
                if (empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']]) || $eventOwnerOrgIdList[$sighting['Sighting']['event_id']] !== $this->Auth->user('org_id')) {
                    unset($sightings[$k]);
                }
            }
            $sightings = array_values($sightings);
        } else if (!empty($sightings) && Configure::read('Plugin.Sightings_policy') == 1 && !$this->_isSiteAdmin()) {
            $eventsWithOwnSightings = array();
            foreach ($sightings as $k => $sighting) {
                if (empty($eventsWithOwnSightings[$sighting['Sighting']['event_id']])) {
                    $eventsWithOwnSightings[$sighting['Sighting']['event_id']] = false;
                    $sighting_temp = $this->Sighting->find('first', array(
                        'recursive' => -1,
                        'conditions' => array(
                            'Sighting.event_id' => $sighting['Sighting']['event_id'],
                            'Sighting.org_id' => $this->Auth->user('org_id')
                        )
                    ));
                    if (empty($sighting_temp)) {
                        $temp_event = $this->Event->find('first', array(
                            'recursive' => -1,
                            'conditions' => array(
                                'Event.id' => $sighting['Sighting']['event_id'],
                                'Event.orgc_id' => $this->Auth->user('org_id')
                            ),
                            'fields' => array('Event.id', 'Event.orgc_id')
                        ));
                        $eventsWithOwnSightings[$sighting['Sighting']['event_id']] = !empty($temp_event);
                    } else {
                        $eventsWithOwnSightings[$sighting['Sighting']['event_id']] = true;
                    }
                }
                if (!$eventsWithOwnSightings[$sighting['Sighting']['event_id']]) {
                    unset($sightings[$k]);
                }
            }
            $sightings = array_values($sightings);
        }
            if (!empty($sightings)) {
                foreach ($sightings as $k => $v) {
                    if ($v['Sighting']['org_id'] != $this->Auth->user('org_id')) {
                        $sightings[$k]['Organisation']['name'] = '';
                        $sightings[$k]['Sighting']['org_id'] = 0;
                    }
        $this->set('sightings', empty($sightings) ? array() : $sightings);