CVE-2019-18985: Improper Restriction of Excessive Authentication Attempts (CWE-307)
value: Pimcore before 6.2.2 lacks brute force protection for the 2FA token.
CWE description: The product does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame, making it more susceptible to brute force attacks.
CVSS v3 base score: 9.8
Published: 2019-11-15T05:15Z
Repository: https://github.com/pimcore/pimcore
Language: PHP
Files changed: bundles/AdminBundle/Controller/Admin/LoginController.php, bundles/AdminBundle/Controller/Admin/UserController.php
Commit date: 2019-10-22 16:26:06 +0200
Commit message: Brute-force attack protection for 2fa codes

Diff: diff --git a/bundles/AdminBundle/Controller/Admin/LoginController.php b/bundles/AdminBundle/Controller/Admin/LoginController.php
index fc211623e32..69a9e6e8320 100644
--- a/bundles/AdminBundle/Controller/Admin/LoginController.php
+++ b/bundles/AdminBundle/Controller/Admin/LoginController.php
@@ -223,26 +223,29 @@ class LoginController extends AdminController implements BruteforceProtectedCont
         return $view;
     }
 
     /**
      * @Route("/login/2fa", name="pimcore_admin_2fa")
-     *
-     * @param Request $request
-     *
      * @TemplatePhp()
      */
-    public function twoFactorAuthenticationAction(Request $request)
+    public function twoFactorAuthenticationAction(Request $request, BruteforceProtectionHandler $bruteforceProtectionHandler)
     {
         $view = $this->buildLoginPageViewModel();
 
         if ($request->hasSession()) {
+
+            // we have to call the check here manually, because BruteforceProtectionListener uses the 'username' from the request
+            $bruteforceProtectionHandler->checkProtection($this->getAdminUser()->getName(), $request);
+
             $session = $request->getSession();
             $authException = $session->get(Security::AUTHENTICATION_ERROR);
             if ($authException instanceof AuthenticationException) {
                 $session->remove(Security::AUTHENTICATION_ERROR);
 
                 $view->error = $authException->getMessage();
+
+                $bruteforceProtectionHandler->addEntry($this->getAdminUser()->getName(), $request);
             }
         } else {
             $view->error = 'No session available, it either timed out or cookies are not enabled.';
         }
 
diff --git a/bundles/AdminBundle/Controller/Admin/UserController.php b/bundles/AdminBundle/Controller/Admin/UserController.php
index 830af8a48fa..e8a4c5f8031 100644
--- a/bundles/AdminBundle/Controller/Admin/UserController.php
+++ b/bundles/AdminBundle/Controller/Admin/UserController.php
@@ -797,12 +797,10 @@ class UserController extends AdminController implements EventedControllerInterfa
      *
      * @param Request $request
      */
     public function renew2FaSecretAction(Request $request)
     {
-        $this->checkCsrfToken($request);
-
         $user = $this->getAdminUser();
         $proxyUser = $this->getAdminUser(true);
 
         $twoFactorService = $this->get('scheb_two_factor.security.google_authenticator');
         $newSecret = $twoFactorService->generateSecret();

Vulnerable code:      *
     * @param Request $request
     *
    public function twoFactorAuthenticationAction(Request $request)
        $this->checkCsrfToken($request);

Fixed code:     public function twoFactorAuthenticationAction(Request $request, BruteforceProtectionHandler $bruteforceProtectionHandler)

            // we have to call the check here manually, because BruteforceProtectionListener uses the 'username' from the request
            $bruteforceProtectionHandler->checkProtection($this->getAdminUser()->getName(), $request);


                $bruteforceProtectionHandler->addEntry($this->getAdminUser()->getName(), $request);