Просмотр исходного кода

Merge pull request #2115 from jaapmarcus/feature/reset-pw-f2b

Improve securtity against csfr/bruteforce
Jaap Marcus 4 лет назад
Родитель
Сommit
9e37a5128a

+ 9 - 1
bin/v-log-user-login

@@ -8,6 +8,9 @@ ip=$2
 status=$3
 session_id=$4
 user_agent=$5
+authlog="${6-no}"
+reason="${7}"
+
 
 active="yes"
 if [ "$status" = "failed" ]; then
@@ -24,7 +27,7 @@ source $HESTIA/conf/hestia.conf
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '2' "$#" 'USER IP SESSION_ID USER_AGENT'
+check_args '2' "$#" 'USER IP SESSION_ID USER_AGENT [AUTHLOG] [REASON]'
 is_format_valid 'user' 'ip'
 is_object_valid 'user' 'USER' "$user"
 
@@ -43,8 +46,13 @@ fi
 
 echo "DATE='$date' TIME='$time' IP='$ip' ACTION='login' STATUS='$status' USER_AGENT='$user_agent' SESSION='$session_id' ACTIVE='$active'" >> $USER_DATA/auth.log
 
+if [ "$authlog" = "yes" ]; then
+    echo "$date $time $user $ip failed to login ($reason)" >> $HESTIA/log/auth.log    
+fi
+
 #----------------------------------------------------------#
 #                       Hestia                             #
 #----------------------------------------------------------#
 
+echo "Test" >> $HESTIA/log/system.log
 exit

+ 61 - 53
web/login/index.php

@@ -1,6 +1,6 @@
 <?php
 
-define('NO_AUTH_REQUIRED',true);
+define('NO_AUTH_REQUIRED', true);
 // Main include
 include($_SERVER['DOCUMENT_ROOT'] . '/inc/main.php');
 
@@ -27,14 +27,14 @@ if (isset($_SESSION['user'])) {
         } else {
             $v_user = escapeshellarg($_GET['loginas']);
             $v_impersonator = escapeshellarg($_SESSION['user']);
-            exec (HESTIA_CMD . "v-list-user ".$v_user." json", $output, $return_var);
-            if ( $return_var == 0 ) {
+            exec(HESTIA_CMD . "v-list-user ".$v_user." json", $output, $return_var);
+            if ($return_var == 0) {
                 $data = json_decode(implode('', $output), true);
                 reset($data);
                 $_SESSION['look'] = key($data);
                 // Log impersonation events
-                exec (HESTIA_CMD . 'v-log-action ' . $v_impersonator . " 'Info' 'Security' 'Logged in as another user (User: $v_user)'", $output, $return_var);
-                exec (HESTIA_CMD . "v-log-action system 'Warning' 'Security' 'User impersonation session started (User: $v_user, Administrator: $v_impersonator)'", $output, $return_var);
+                exec(HESTIA_CMD . 'v-log-action ' . $v_impersonator . " 'Info' 'Security' 'Logged in as another user (User: $v_user)'", $output, $return_var);
+                exec(HESTIA_CMD . "v-log-action system 'Warning' 'Security' 'User impersonation session started (User: $v_user, Administrator: $v_impersonator)'", $output, $return_var);
                 // Reset account details for File Manager to impersonated user
                 unset($_SESSION['_sf2_attributes']);
                 unset($_SESSION['_sf2_meta']);
@@ -51,14 +51,14 @@ if (isset($_SESSION['user'])) {
             header('Location: /list/user/');
             exit;
         }
-        
+
         // Obtain account properties
         $v_user = escapeshellarg($_SESSION[(($_SESSION['userContext'] === 'admin') && (isset($_SESSION['look']))) ? 'look' : 'user']);
 
-        exec (HESTIA_CMD . 'v-list-user ' . $v_user . ' json', $output, $return_var);
+        exec(HESTIA_CMD . 'v-list-user ' . $v_user . ' json', $output, $return_var);
         $data = json_decode(implode('', $output), true);
-        unset($output); 
-        
+        unset($output);
+
         // Determine package features and land user at the first available page
         if ($data[$user]['WEB_DOMAINS'] !== '0') {
             header('Location: /list/web/');
@@ -87,40 +87,41 @@ if (isset($_SESSION['user'])) {
     exit;
 }
 
-function authenticate_user($user, $password, $twofa = ''){
+function authenticate_user($user, $password, $twofa = '')
+{
     unset($_SESSION['login']);
-    if(isset($_SESSION['token']) && isset($_POST['token']) && $_POST['token'] == $_SESSION['token']) {
-    $v_user = escapeshellarg($user);
-    $ip = $_SERVER['REMOTE_ADDR'];
-    $user_agent = $_SERVER['HTTP_USER_AGENT'];
-    if(isset($_SERVER['HTTP_CF_CONNECTING_IP'])){
-        if(!empty($_SERVER['HTTP_CF_CONNECTING_IP'])){
-            $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
+    if (isset($_SESSION['token']) && isset($_POST['token']) && $_POST['token'] == $_SESSION['token']) {
+        $v_user = escapeshellarg($user);
+        $ip = $_SERVER['REMOTE_ADDR'];
+        $user_agent = $_SERVER['HTTP_USER_AGENT'];
+        if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
+            if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
+                $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
+            }
         }
-    }
-    $v_ip = escapeshellarg($ip);
-    $v_user_agent = escapeshellarg($user_agent);
+        $v_ip = escapeshellarg($ip);
+        $v_user_agent = escapeshellarg($user_agent);
 
-     // Get user's salt
-    $output = '';
-    exec (HESTIA_CMD . 'v-get-user-salt ' . $v_user . ' ' . $v_ip . ' json' , $output, $return_var);
-    $pam = json_decode(implode('', $output), true);
-    if ( $return_var > 0 ) {
-        sleep(2);
-        $error = '<a class="error">' . _('Invalid username or password') . '</a>';
-        return $error;
+        // Get user's salt
+        $output = '';
+        exec(HESTIA_CMD . 'v-get-user-salt ' . $v_user . ' ' . $v_ip . ' json', $output, $return_var);
+        $pam = json_decode(implode('', $output), true);
+        if ($return_var > 0) {
+            sleep(2);
+            $error = '<a class="error">' . _('Invalid username or password') . '</a>';
+            return $error;
         } else {
             $salt = $pam[$user]['SALT'];
             $method = $pam[$user]['METHOD'];
 
-            if ($method == 'md5' ) {
+            if ($method == 'md5') {
                 $hash = crypt($password, '$1$' . $salt . '$');
             }
-            if ($method == 'sha-512' ) {
+            if ($method == 'sha-512') {
                 $hash = crypt($password, '$6$rounds=5000$' . $salt . '$');
                 $hash = str_replace('$rounds=5000', '', $hash);
             }
-            if ($method == 'des' ) {
+            if ($method == 'des') {
                 $hash = crypt($password, $salt);
             }
 
@@ -137,7 +138,7 @@ function authenticate_user($user, $password, $twofa = ''){
             // Remove tmp file
             unlink($v_hash);
             // Check API answer
-            if ( $return_var > 0 ) {
+            if ($return_var > 0) {
                 sleep(2);
                 $error = '<a class="error">' . _('Invalid username or password') . '</a>';
                 $v_session_id = escapeshellarg($_POST['token']);
@@ -146,14 +147,14 @@ function authenticate_user($user, $password, $twofa = ''){
             } else {
 
                 // Get user specific parameters
-                exec (HESTIA_CMD . 'v-list-user ' . $v_user . ' json', $output, $return_var);
+                exec(HESTIA_CMD . 'v-list-user ' . $v_user . ' json', $output, $return_var);
                 $data = json_decode(implode('', $output), true);
-                unset($output); 
+                unset($output);
                 if ($data[$user]['LOGIN_DISABLED'] === 'yes') {
                     sleep(2);
                     $error = '<a class="error">' . _('Invalid username or password') . '</a>';
                     $v_session_id = escapeshellarg($_POST['token']);
-                    exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent, $output, $return_var);
+                    exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Login disabled for this user"', $output, $return_var);
                     return $error;
                 }
 
@@ -164,35 +165,43 @@ function authenticate_user($user, $password, $twofa = ''){
                         sleep(2);
                         $error = '<a class="error">' . _('Invalid username or password') . '</a>';
                         $v_session_id = escapeshellarg($_POST['token']);
-                        exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent, $output, $return_var);
+                        exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Ip not in allowed list"', $output, $return_var);
                         return $error;
                     }
                 }
 
                 if ($data[$user]['TWOFA'] != '') {
-                        exec(HESTIA_CMD . "v-check-user-2fa " . $v_user . " " . $v_twofa, $output, $return_var);
-                            $error = "<a class=\"error\">" . _('Invalid or missing 2FA token') . "</a>";
-                    if(empty($twofa)){
+                    exec(HESTIA_CMD . "v-check-user-2fa " . $v_user . " " . $v_twofa, $output, $return_var);
+                    $error = "<a class=\"error\">" . _('Invalid or missing 2FA token') . "</a>";
+                    if (empty($twofa)) {
                         $_SESSION['login']['username'] = $user;
                         $_SESSION['login']['password'] = $password;
                         return false;
-                    }else{
+                    } else {
                         $v_twofa = escapeshellarg($twofa);
                         exec(HESTIA_CMD .'v-check-user-2fa '.$v_user.' '.$v_twofa, $output, $return_var);
                         unset($output);
-                        if ( $return_var > 0 ) {
+                        if ($return_var > 0) {
                             sleep(2);
-                            $error = '<a class="error">' ._ ('Invalid or missing 2FA token') . '</a>';
+                            $error = '<a class="error">' ._('Invalid or missing 2FA token') . '</a>';
                             $_SESSION['login']['username'] = $user;
                             $_SESSION['login']['password'] = $password;
                             $v_session_id = escapeshellarg($_POST['token']);
-                            exec(HESTIA_CMD.'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent, $output, $return_var);
+                            if (isset($_SESSION['failed_twofa'])) {
+                                //allow a few failed attemps before start of logging.
+                                if ($_SESSION['failed_twofa']  > 2) {
+                                    exec(HESTIA_CMD.'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Invalid or missing 2FA token"', $output, $return_var);
+                                }
+                                $_SESSION['failed_twofa']++;
+                            } else {
+                                $_SESSION['failed_twofa'] = 1;
+                            }
                             unset($_POST['twofa']);
                             return $error;
                         }
                     }
                 }
-                
+
                 // Define session user
                 $_SESSION['user'] = key($data);
                 $v_user = $_SESSION['user'];
@@ -216,10 +225,10 @@ function authenticate_user($user, $password, $twofa = ''){
 
                 // Define language
                 $output = '';
-                exec (HESTIA_CMD . 'v-list-sys-languages json', $output, $return_var);
+                exec(HESTIA_CMD . 'v-list-sys-languages json', $output, $return_var);
                 $languages = json_decode(implode('', $output), true);
                 $_SESSION['language'] = (in_array($data[$v_user]['LANGUAGE'], $languages)) ? $data[$user]['LANGUAGE'] : 'en';
-                
+
                 // Regenerate session id to prevent session fixation
                 session_regenerate_id(true);
 
@@ -232,7 +241,7 @@ function authenticate_user($user, $password, $twofa = ''){
                     if ($_SESSION['userContext'] === 'admin') {
                         header('Location: /list/user/');
                     } else {
-                        if($data[$user]['WEB_DOMAINS'] != '0') {
+                        if ($data[$user]['WEB_DOMAINS'] != '0') {
                             header('Location: /list/web/');
                         } elseif ($data[$user]['DNS_DOMAINS'] != '0') {
                             header('Location: /list/dns/');
@@ -264,10 +273,10 @@ function authenticate_user($user, $password, $twofa = ''){
         return false;
     }
 }
-if (preg_match('/^[[:alnum:]][-|\.|_[:alnum:]]{0,28}[[:alnum:]]$/',$_POST['user'])) {
+if (preg_match('/^[[:alnum:]][-|\.|_[:alnum:]]{0,28}[[:alnum:]]$/', $_POST['user'])) {
     $_SESSION['login']['username'] = $_POST['user'];
-}else{
-    $user = ''; 
+} else {
+    $user = '';
 }
 if (!empty($_SESSION['login']['username']) && !empty($_SESSION['login']['password']) && !empty($_POST['twofa'])) {
     $error = authenticate_user($_SESSION['login']['username'], $_SESSION['login']['password'], $_POST['twofa']);
@@ -282,12 +291,12 @@ load_hestia_config();
 // Detect language
 if (empty($_SESSION['language'])) {
     $output = '';
-    exec (HESTIA_CMD . 'v-list-sys-config json', $output, $return_var);
+    exec(HESTIA_CMD . 'v-list-sys-config json', $output, $return_var);
     $config = json_decode(implode('', $output), true);
     $lang = $config['config']['LANGUAGE'];
 
     $output = '';
-    exec (HESTIA_CMD . 'v-list-sys-languages json', $output, $return_var);
+    exec(HESTIA_CMD . 'v-list-sys-languages json', $output, $return_var);
     $languages = json_decode(implode('', $output), true);
     $_SESSION['language'] = (in_array($lang, $languages)) ? $lang : 'en';
 }
@@ -302,7 +311,6 @@ if (!empty($_SESSION['login']['password'])) {
 } elseif (empty($_SESSION['login']['username'])) {
     require_once('../templates/pages/login/login' . (($_SESSION['LOGIN_STYLE'] != 'old') ? '' : '_a') . '.html');
 } elseif (empty($_POST['password'])) {
-    
     require_once('../templates/pages/login/login_1.html');
 } else {
     require_once('../templates/pages/login/login' . (($_SESSION['LOGIN_STYLE'] != 'old') ? '' : '_a') . '.html');

+ 37 - 27
web/reset/index.php

@@ -1,6 +1,7 @@
 <?php
+
 session_start();
-define('NO_AUTH_REQUIRED',true);
+define('NO_AUTH_REQUIRED', true);
 $TAB = 'RESET PASSWORD';
 
 if (isset($_SESSION['user'])) {
@@ -11,70 +12,78 @@ if (isset($_SESSION['user'])) {
 include($_SERVER['DOCUMENT_ROOT']."/inc/main.php");
 
 if ((!empty($_POST['user'])) && (empty($_POST['code']))) {
+    if ($_POST['token'] != $_SESSION['token']) {
+        header('Location: /');
+    }
     $v_user = escapeshellarg($_POST['user']);
     $user = $_POST['user'];
     $email = $_POST['email'];
     $cmd="/usr/bin/sudo /usr/local/hestia/bin/v-list-user";
-    exec ($cmd." ".$v_user." json", $output, $return_var);
-    if ( $return_var == 0 ) {
+    exec($cmd." ".$v_user." json", $output, $return_var);
+    if ($return_var == 0) {
         $data = json_decode(implode('', $output), true);
-        if($email == $data[$user]['CONTACT']){
+        if ($email == $data[$user]['CONTACT']) {
             //genrate new rkey
-            $rkey = substr( password_hash( rand(0,10), PASSWORD_DEFAULT ), 5, 12 );
+            $rkey = substr(password_hash(rand(0, 10), PASSWORD_DEFAULT), 5, 12);
             $hash = password_hash($rkey, PASSWORD_DEFAULT);
-            $v_rkey = tempnam("/tmp","vst");
+            $v_rkey = tempnam("/tmp", "vst");
             $fp = fopen($v_rkey, "w");
             fwrite($fp, $hash."\n");
             fclose($fp);
-            exec ("/usr/bin/sudo /usr/local/hestia/bin/v-change-user-rkey ".$v_user." ".$v_rkey."", $output, $return_var);
+            exec("/usr/bin/sudo /usr/local/hestia/bin/v-change-user-rkey ".$v_user." ".$v_rkey."", $output, $return_var);
             unset($output);
             unlink($v_rkey);
             $name = $data[$user]['NAME'];
             $contact = $data[$user]['CONTACT'];
             $to = $data[$user]['CONTACT'];
-            $subject = sprintf(_('MAIL_RESET_SUBJECT'),date("Y-m-d H:i:s"));
+            $subject = sprintf(_('MAIL_RESET_SUBJECT'), date("Y-m-d H:i:s"));
             $hostname = exec('hostname');
             $from = "noreply@".$hostname;
             $from_name = _('Hestia Control Panel');
             if (!empty($name)) {
-                $mailtext = sprintf(_('GREETINGS_GORDON'),$name);
+                $mailtext = sprintf(_('GREETINGS_GORDON'), $name);
             } else {
                 $mailtext = _('GREETINGS');
             }
-            if (in_array(str_replace(':'.$_SERVER['SERVER_PORT'],'.conf',$_SERVER['HTTP_HOST']), array_merge(scandir('/etc/nginx/conf.d'),scandir('/etc/nginx/conf.d/domains'),scandir('/etc/apache2/conf.d/domains'),scandir('/etc/apache2/conf.d')))){
-                $mailtext .= sprintf(_('PASSWORD_RESET_REQUEST'),$_SERVER['HTTP_HOST'],$user,$rkey,$_SERVER['HTTP_HOST'],$user,$rkey);
-                if (!empty($rkey)) send_email($to, $subject, $mailtext, $from, $from_name, $data[$user]['NAME']);
+            if (in_array(str_replace(':'.$_SERVER['SERVER_PORT'], '.conf', $_SERVER['HTTP_HOST']), array_merge(scandir('/etc/nginx/conf.d'), scandir('/etc/nginx/conf.d/domains'), scandir('/etc/apache2/conf.d/domains'), scandir('/etc/apache2/conf.d')))) {
+                $mailtext .= sprintf(_('PASSWORD_RESET_REQUEST'), $_SERVER['HTTP_HOST'], $user, $rkey, $_SERVER['HTTP_HOST'], $user, $rkey);
+                if (!empty($rkey)) {
+                    send_email($to, $subject, $mailtext, $from, $from_name, $data[$user]['NAME']);
+                }
                 header("Location: /reset/?action=code&user=".$_POST['user']);
                 exit;
             } else {
                 $ERROR = "<a class=\"error\">"._('Invalid host domain')."</a>";
             }
-        }     
+        }
     }
     unset($output);
 }
 
-if ((!empty($_POST['user'])) && (!empty($_POST['code'])) && (!empty($_POST['password'])) ) {
-    if ( $_POST['password'] == $_POST['password_confirm'] ) {
+if ((!empty($_POST['user'])) && (!empty($_POST['code'])) && (!empty($_POST['password']))) {
+    if ($_POST['token'] != $_SESSION['token']) {
+        header('Location: /');
+    }
+    if ($_POST['password'] == $_POST['password_confirm']) {
         $v_user = escapeshellarg($_POST['user']);
         $user = $_POST['user'];
         $cmd="/usr/bin/sudo /usr/local/hestia/bin/v-list-user";
-        exec ($cmd." ".$v_user." json", $output, $return_var);
-        if ( $return_var == 0 ) {
+        exec($cmd." ".$v_user." json", $output, $return_var);
+        if ($return_var == 0) {
             $data = json_decode(implode('', $output), true);
             $rkey = $data[$user]['RKEY'];
             if (password_verify($_POST['code'], $rkey)) {
                 unset($output);
-                exec("/usr/bin/sudo /usr/local/hestia/bin/v-get-user-value ".$v_user." RKEYEXP", $output,$return_var);
-                if($output[0] > time() - 900){
-                    $v_password = tempnam("/tmp","vst");
+                exec("/usr/bin/sudo /usr/local/hestia/bin/v-get-user-value ".$v_user." RKEYEXP", $output, $return_var);
+                if ($output[0] > time() - 900) {
+                    $v_password = tempnam("/tmp", "vst");
                     $fp = fopen($v_password, "w");
                     fwrite($fp, $_POST['password']."\n");
                     fclose($fp);
                     $cmd="/usr/bin/sudo /usr/local/hestia/bin/v-change-user-password";
-                    exec ($cmd." ".$v_user." ".$v_password, $output, $return_var);
+                    exec($cmd." ".$v_user." ".$v_password, $output, $return_var);
                     unlink($v_password);
-                    if ( $return_var > 0 ) {
+                    if ($return_var > 0) {
                         sleep(5);
                         $ERROR = "<a class=\"error\">"._('An internal error occurred')."</a>";
                     } else {
@@ -82,17 +91,20 @@ if ((!empty($_POST['user'])) && (!empty($_POST['code'])) && (!empty($_POST['pass
                         header("Location: /");
                         exit;
                     }
-                }else{
+                } else {
                     sleep(5);
                     $ERROR = "<a class=\"error\">"._('Code has been expired')."</a>";
+                    exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Reset code has been expired"', $output, $return_var);
                 }
             } else {
                 sleep(5);
                 $ERROR = "<a class=\"error\">"._('Invalid username or code')."</a>";
+                exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Invalid Username or Code"', $output, $return_var);
             }
         } else {
             sleep(5);
             $ERROR = "<a class=\"error\">"._('Invalid username or code')."</a>";
+            exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Invalid Username or Code"', $output, $return_var);
         }
     } else {
         $ERROR = "<a class=\"error\">"._('Passwords not match')."</a>";
@@ -104,12 +116,10 @@ if (empty($_GET['action'])) {
     require_once '../templates/pages/login/reset_1.html';
 } else {
     require_once '../templates/header.html';
-    if ($_GET['action'] == 'code' ) {
+    if ($_GET['action'] == 'code') {
         require_once '../templates/pages/login/reset_2.html';
     }
-    if (($_GET['action'] == 'confirm' ) && (!empty($_GET['code']))) {
+    if (($_GET['action'] == 'confirm') && (!empty($_GET['code']))) {
         require_once '../templates/pages/login/reset_3.html';
     }
 }
-
-?>

+ 16 - 14
web/reset2fa/index.php

@@ -1,6 +1,7 @@
 <?php
+
 session_start();
-define('NO_AUTH_REQUIRED',true);
+define('NO_AUTH_REQUIRED', true);
 $TAB = 'RESET PASSWORD';
 
 if (isset($_SESSION['user'])) {
@@ -11,29 +12,30 @@ if (isset($_SESSION['user'])) {
 include($_SERVER['DOCUMENT_ROOT']."/inc/main.php");
 
 //Check values
-if(!empty($_POST['user']) && !empty($_POST['twofa'])){
+if (!empty($_POST['user']) && !empty($_POST['twofa'])) {
+    if ($_POST['token'] != $_SESSION['token']) {
+        header('Location: /');
+    }
     $error = true;
     $v_user = escapeshellarg($_POST['user']);
     $user = $_POST['user'];
     $twofa = $_POST['twofa'];
-    $cmd="/usr/bin/sudo /usr/local/hestia/bin/v-list-user";
-    exec ($cmd." ".$v_user." json", $output, $return_var);
-    if ( $return_var == 0 ) {
+    exec(HESTIA_CMD . "v-list-user ".$v_user .' json', $output, $return_var);
+    if ($return_var == 0) {
         $data = json_decode(implode('', $output), true);
-        if($data[$user]['TWOFA'] == $twofa){
+        if ($data[$user]['TWOFA'] == $twofa) {
             $success = true;
-            $cmd="/usr/bin/sudo /usr/local/hestia/bin/v-delete-user-2fa";
-            exec ($cmd." ".$v_user." json", $output, $return_var);
-        }else{
-            sleep(5);   
+            exec(HESTIA_CMD . "v-delete-user-2fa ".$v_user, $output, $return_var);
+            session_destroy();
+        } else {
+            exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Failed to enter correct 2FA reset key"', $output, $return_var);
+            sleep(5);
         }
-    }else{
+    } else {
+        exec(HESTIA_CMD . 'v-log-user-login ' . $v_user . ' ' . $v_ip . ' failed ' . $v_session_id . ' ' . $v_user_agent .' yes "Failed to enter correct 2FA reset key"', $output, $return_var);
         sleep(5);
     }
-    
 }
 
 require_once '../templates/header.html';
 require_once '../templates/pages/login/reset2fa.html';
-
-?>

+ 1 - 0
web/templates/pages/login/reset2fa.html

@@ -23,6 +23,7 @@
 								</table>
 							<?php } else { ?>
 								<form method="post" action="/reset2fa/">
+									<input type="hidden" name="token" value="<?=$_SESSION['token'];?>"/>
 									<table class="login-box">
 										<tr>
 											<td style="padding: 12px 0 0 2px;" class="login-welcome">

+ 1 - 0
web/templates/pages/login/reset_1.html

@@ -9,6 +9,7 @@
 						</td>
 						<td style="padding: 40px 60px 0 0;" class="animated fadeIn">
 							<form method="post" action="/reset/">
+								<input type="hidden" name="token" value="<?=$_SESSION['token'];?>"/>
 								<table class="login-box">
 									<tr>
 										<td style="padding: 12px 0 0 2px;" class="login-welcome">

+ 1 - 0
web/templates/pages/login/reset_2.html

@@ -26,6 +26,7 @@
 									<tr>
 										<td>
 											<input type="hidden" name="action" value="confirm">
+											<input type="hidden" name="token" value="<?=$_SESSION['token'];?>"/>
 											<input type="hidden" name="user" value="<?=htmlentities($_GET['user'], ENT_QUOTES|ENT_HTML5)?>">
 											<input tabindex="1" type="text" size="20px" style="width:240px" name="code" class="vst-input">
 										</td>

+ 1 - 0
web/templates/pages/login/reset_3.html

@@ -18,6 +18,7 @@
 									<tr>
 										<td style="padding: 12px 0 0 2px;">
 											<input type="hidden" name="action" value="confirm">
+											<input type="hidden" name="token" value="<?=$_SESSION['token'];?>"/>
 											<input type="hidden" name="user" value="<?=htmlentities($_GET['user'], ENT_QUOTES|ENT_HTML5)?>">
 											<input type="hidden" name="code" value="<?=htmlentities($_GET['code'], ENT_QUOTES|ENT_HTML5)?>">
 											<?=_('New Password');?>