CVE-2020-8890 (published 2020-02-12T00:15Z)

An issue was discovered in MISP before 2.4.121. It mishandled time skew (between the machine hosting the web server and the machine hosting the database) when trying to block a brute-force series of invalid requests.

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

Weakness information:
cwe_id: CWE-367
cwe_name: Time-of-check Time-of-use (TOCTOU) Race Condition
description: The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check. This can cause the product to perform invalid actions when the resource is in an unexpected state.
extended_description: This weakness can be security-relevant when an attacker can influence the state of the resource between check and use. This can happen with shared resources such as files, memory, or even variables in multithreaded programs.
         

Fix information:
repo_url: https://github.com/MISP/MISP
commit_details: repo_url: https://github.com/MISP/MISP
author: iglocska
author_date: 2020-02-10 11:41:54+01:00
msg: fix: [security] Further fixes to the bruteforce handling

- resolved a potential failure of the subsystem when the MySQL and the webserver time settings are diverged
  - as reported by Dawid Czarnecki
- several tightenings of the checks to avoid potential foul play
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: UsersController.php
change_type: ModificationType.MODIFY
diff: @@ -1066,6 +1066,7 @@ class UsersController extends AppController
             $this->Bruteforce = ClassRegistry::init('Bruteforce');
             if (!empty($this->request->data['User']['email'])) {
                 if ($this->Bruteforce->isBlacklisted($_SERVER['REMOTE_ADDR'], $this->request->data['User']['email'])) {
+                    $expire = Configure::check('SecureAuth.expire') ? Configure::read('SecureAuth.expire') : 300;
                     throw new ForbiddenException('You have reached the maximum number of login attempts. Please wait ' . Configure::read('SecureAuth.expire') . ' seconds and try again.');
                 }
             }
@@ -1116,7 +1117,7 @@ class UsersController extends AppController
                 $this->Session->delete('Message.auth');
             }
             // don't display "invalid user" before first login attempt
-            if ($this->request->is('post')) {
+            if ($this->request->is('post') || $this->request->is('put')) {
                 $this->Flash->error(__('Invalid username or password, try again'));
                 if (isset($this->request->data['User']['email'])) {
                     $this->Bruteforce->insert($_SERVER['REMOTE_ADDR'], $this->request->data['User']['email']);

programming_language: PHP
filename: Bruteforce.php
change_type: ModificationType.MODIFY
diff: @@ -9,17 +9,19 @@ class Bruteforce extends AppModel
     {
         $this->Log = ClassRegistry::init('Log');
         $this->Log->create();
-        $expire = time() + Configure::read('SecureAuth.expire');
+        $expire = Configure::check('SecureAuth.expire') ? Configure::read('SecureAuth.expire') : 300;
+        $amount = Configure::check('SecureAuth.amount') ? Configure::read('SecureAuth.amount') : 5;
+        $expire = time() + $expire;
         $expire = date('Y-m-d H:i:s', $expire);
         $bruteforceEntry = array(
             'ip' => $ip,
-            'username' => $username,
+            'username' => trim(strtolower($username)),
             'expire' => $expire
         );
         $this->save($bruteforceEntry);
         $title = 'Failed login attempt using username ' . $username . ' from IP: ' . $_SERVER['REMOTE_ADDR'] . '.';
         if ($this->isBlacklisted($ip, $username)) {
-            $title .= 'This has tripped the bruteforce protection after  ' . Configure::read('SecureAuth.amount') . ' failed attempts. The user is now blacklisted for ' . Configure::read('SecureAuth.expire') . ' seconds.';
+            $title .= 'This has tripped the bruteforce protection after  ' . $amount . ' failed attempts. The user is now blacklisted for ' . $expire . ' seconds.';
         }
         $log = array(
                 'org' => 'SYSTEM',
@@ -36,10 +38,11 @@ class Bruteforce extends AppModel
     {
         $dataSourceConfig = ConnectionManager::getDataSource('default')->config;
         $dataSource = $dataSourceConfig['datasource'];
+        $expire = date('Y-m-d H:i:s', time());
         if ($dataSource == 'Database/Mysql') {
-            $sql = 'DELETE FROM bruteforces WHERE `expire` <= NOW();';
+            $sql = 'DELETE FROM bruteforces WHERE `expire` <= "' . $expire . '";';
         } elseif ($dataSource == 'Database/Postgres') {
-            $sql = 'DELETE FROM bruteforces WHERE expire <= NOW();';
+            $sql = 'DELETE FROM bruteforces WHERE expire <= "' . $expire . '";';
         }
         $this->query($sql);
     }

programming_language: PHP
repo_url: https://github.com/MISP/MISP
commit_details: repo_url: https://github.com/MISP/MISP
author: iglocska
author_date: 2020-02-08 09:35:37+01:00
msg: fix: [security] brutefoce protection rules tightened

- as reported by Dawid Czarnecki
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: Bruteforce.php
change_type: ModificationType.MODIFY
diff: @@ -49,11 +49,14 @@ class Bruteforce extends AppModel
         // first remove old expired rows
         $this->clean();
         // count
-        $params = array('conditions' => array(
-                        'Bruteforce.ip' => $ip,
-                        'Bruteforce.username' => $username),);
+        $params = array(
+            'conditions' => array(
+            'Bruteforce.ip' => $ip,
+            'LOWER(Bruteforce.username)' => trim(strtolower($username)))
+        );
         $count = $this->find('count', $params);
-        if ($count >= Configure::read('SecureAuth.amount')) {
+        $amount = Configure::check('SecureAuth.amount') ? Configure::read('SecureAuth.amount') : 5;
+        if ($count >= $amount) {
             return true;
         } else {
             return false;

programming_language: PHP