CVE-2019-12794 (published 2019-06-11T17:29Z)

An issue was discovered in MISP 2.4.108. Organization admins could reset credentials for site admins (organization admins have the inherent ability to reset passwords for all of their organization's users). This, however, could be abused in a situation where the host organization of an instance creates organization admins. An organization admin could set a password manually for the site admin or simply use the API key of the site admin to impersonate them. The potential for abuse only occurs when the host organization creates lower-privilege organization admins instead of the usual site admins. Also, only organization admins of the same organization as the site admin could abuse this.

Severity: MEDIUM
CVSS v2 base score: 6.0 (AV:N/AC:M/Au:S/C:P/I:P/A:P)
CVSS v3 base score: 6.6, MEDIUM (CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-269
cwe_name: Improper Privilege Management
description: The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor.
extended_description: 
            
         
         

Fix information:
repo_url: https://github.com/MISP/MISP
commit_details: repo_url: https://github.com/MISP/MISP
author: iglocska
author_date: 2019-06-11 11:05:34+02:00
msg: fix: [security] Org admins could reset credentials for site admins

- org admins have the inherent ability to reset passwords for all of their org's users
- this however could be abused if for some reason the host org of an instance would create org admins
  - the org admin could set a password manually for the site admin or simply use the API key of the site admin to impersonate them
- the potential for abuse is very circumstancial as it requires the host org to create lower privilege org admins instead of the usual site admins
- only org admins of the same organisation as the site admin could abuse this

- as reported by Raymond Schippers
repository: repo_url: https://github.com/MISP/MISP
repo_name: MISP/MISP
description: MISP (core software) - Open Source Threat Intelligence and Sharing Platform
repo_language: PHP
owner: MISP
file_changes: filename: LogsController.php
change_type: ModificationType.MODIFY
diff: @@ -343,7 +343,11 @@ class LogsController extends AppController
                     'conditions' => $conditions,
                     'order' => array('Log.id' => 'DESC')
                 );
-                $this->set('list', $this->paginate());
+                $list = $this->paginate();
+                if (empty($this->Auth->user('Role')['perm_site_admin'])) {
+                    $list = $this->Log->filterSiteAdminSensitiveLogs($list);
+                }
+                $this->set('list', $list);
 
                 // and store into session
                 $this->Session->write('paginate_conditions_log', $this->paginate);
@@ -394,7 +398,11 @@ class LogsController extends AppController
                 }
                 $conditions = $this->__buildSearchConditions($filters);
                 $this->paginate['conditions'] = $conditions;
-                $this->set('list', $this->paginate());
+                $list = $this->paginate();
+                if (empty($this->Auth->user('Role')['perm_site_admin'])) {
+                    $list = $this->Log->filterSiteAdminSensitiveLogs($list);
+                }
+                $this->set('list', $list);
 
                 // set the same view as the index page
                 $this->render('admin_index');

programming_language: PHP
filename: UsersController.php
change_type: ModificationType.MODIFY
diff: @@ -19,7 +19,7 @@ class UsersController extends AppController
             ),
             'contain' => array(
                 'Organisation' => array('id', 'name'),
-                'Role' => array('id', 'name', 'perm_auth')
+                'Role' => array('id', 'name', 'perm_auth', 'perm_site_admin')
             )
     );
 
@@ -350,11 +350,16 @@ class UsersController extends AppController
                     ),
                     'contain' => array(
                             'Organisation' => array('id', 'name'),
-                            'Role' => array('id', 'name', 'perm_auth')
+                            'Role' => array('id', 'name', 'perm_auth', 'perm_site_admin')
                     )
             ));
             foreach ($users as $key => $value) {
-                unset($users['User']['password']);
+                if (empty($this->Auth->user('Role')['perm_site_admin'])) {
+                    if ($value['Role']['perm_site_admin']) {
+                        $users[$key]['User']['authkey'] = __('Redacted');
+                    }
+                }
+                unset($users[$key]['User']['password']);
             }
             return $this->RestResponse->viewData($users, $this->response->type());
         } else {
@@ -366,7 +371,13 @@ class UsersController extends AppController
             } else {
                 $conditions['User.org_id'] = $this->Auth->user('org_id');
                 $this->paginate['conditions']['AND'][] = $conditions;
-                $this->set('users', $this->paginate());
+                $users = $this->paginate();
+                foreach ($users as $key => $value) {
+                    if ($value['Role']['perm_site_admin']) {
+                        $users[$key]['User']['authkey'] = __('Redacted');
+                    }
+                }
+                $this->set('users', $users);
             }
             if ($this->request->is('ajax')) {
                 $this->autoRender = false;
@@ -462,6 +473,9 @@ class UsersController extends AppController
             $user['User']['fingerprint'] = !empty($pgpDetails[4]) ? $pgpDetails[4] : 'N/A';
         }
         $user['User']['orgAdmins'] = $this->User->getOrgAdminsForOrg($user['User']['org_id'], $user['User']['id']);
+        if (empty($this->Auth->user('Role')['perm_site_admin']) && !(empty($user['Role']['perm_site_admin']))) {
+            $user['User']['authkey'] = __('Redacted');
+        }
         $this->set('user', $user);
         if (!$this->_isSiteAdmin() && !($this->_isAdmin() && $this->Auth->user('org_id') == $user['User']['org_id'])) {
             throw new MethodNotAllowedException();
@@ -694,9 +708,10 @@ class UsersController extends AppController
         $params = array();
         $allowedRole = '';
         $userToEdit = $this->User->find('first', array(
-                'conditions' => array('id' => $id),
+                'conditions' => array('User.id' => $id),
                 'recursive' => -1,
-                'fields' => array('id', 'role_id', 'email', 'org_id'),
+                'fields' => array('User.id', 'User.role_id', 'User.email', 'User.org_id', 'Role.perm_site_admin'),
+                'contain' => array('Role')
         ));
         if (!$this->_isSiteAdmin()) {
             // Org admins should be able to select the role that is already assigned to an org user when editing them.
@@ -706,8 +721,8 @@ class UsersController extends AppController
             // MISP automatically chooses the first available option for the user as the selected setting (usually user)
             // Org admin is downgraded to a user
             // Now we make an exception for the already assigned role, both in the form and the actual edit.
-            if ($userToEdit['User']['org_id'] != $this->Auth->user('org_id')) {
-                throw new Exception('Invalid user');
+            if ($userToEdit['User']['org_id'] != $this->Auth->user('org_id') || !empty($userToEdit['Role']['perm_site_admin'])) {
+                throw new NotFoundException(__('Invalid user'));
             }
             $allowedRole = $userToEdit['User']['role_id'];
             $params = array('conditions' => array(

programming_language: PHP
filename: Log.php
change_type: ModificationType.MODIFY
diff: @@ -295,4 +295,31 @@ class Log extends AppModel
         }
         return true;
     }
+
+    public function filterSiteAdminSensitiveLogs($list)
+    {
+        $this->User = ClassRegistry::init('User');
+        $site_admin_roles = $this->User->Role->find('list', array(
+            'recursive' => -1,
+            'conditions' => array('Role.perm_site_admin' => 1),
+            'fields' => array('Role.id', 'Role.id')
+        ));
+        $site_admins = $this->User->find('list', array(
+            'recursive' => -1,
+            'conditions' => array(
+                'User.role_id' => array_values($site_admin_roles)
+            ),
+            'fields' => array('User.id', 'User.id')
+        ));
+        foreach ($list as $k => $v) {
+            if (
+                $v['Log']['model'] === 'User' &&
+                in_array($v['Log']['model_id'], array_values($site_admins)) &&
+                in_array($v['Log']['action'], array('add', 'edit', 'reset_auth_key'))
+            ) {
+                $list[$k]['Log']['change'] = __('Redacted');
+            }
+        }
+        return $list;
+    }
 }

programming_language: PHP