CVE-2021-3817: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: wbce_cms is vulnerable to Improper Neutralization of Special Elements used in an SQL Command
CWE description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
CVSS v3 base score: 9.8
Published: 2021-12-09T11:15Z
Repository: https://github.com/wbce/wbce_cms
Language: PHP
Files changed: wbce/admin/login/forgot/index.php, wbce/modules/tool_account_settings/account/form_forgot.php, wbce/modules/tool_account_settings/templates/form_forgot.twig, wbce/templates/argos_theme_reloaded/css/login.css, wbce/templates/argos_theme_reloaded/info.php, wbce/templates/argos_theme_reloaded/templates/login_forgot.htt, wbce/templates/wbce_flat_theme/css/login.css, wbce/templates/wbce_flat_theme/info.php, wbce/templates/wbce_flat_theme/templates/login_forgot.htt
Commit date: 2021-11-28 16:16:13 +0100
Commit message: add captcha for login forgot

Diff: diff --git a/wbce/admin/login/forgot/index.php b/wbce/admin/login/forgot/index.php
index e1ca95f4..4a4a9281 100644
--- a/wbce/admin/login/forgot/index.php
+++ b/wbce/admin/login/forgot/index.php
@@ -15,103 +15,121 @@ require realpath('../../../config.php');
 // Include the language file
 require WB_PATH . '/languages/' . DEFAULT_LANGUAGE . '.php';
 // Include the database class file and initiate an object
 require WB_PATH . '/framework/class.admin.php';
 $admin = new admin('Start', 'start', false, false);
+require_once(WB_PATH.'/include/captcha/captcha.php');
 
 $oMsgBox = new MessageBox();
 $oMsgBox->closeBtn = '';
 
 // Check if the user has already submitted the form, otherwise show it
-if (isset($_POST['email']) and $_POST['email'] != "") {
+if (isset($_POST['email']) && $_POST['email'] != "" ) {
     $email = strip_tags($wb->get_post('email'));
-    if ($admin->validate_email($email) == false) {
-        $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);
+    if(isset($_POST['captcha']) AND $_POST['captcha'] != ''){
+        $ccheck = time(); $ccheck1 = time();
+        if(isset($_SESSION['captchaloginforgot'])) $ccheck1 = $_SESSION['captchaloginforgot'];
+        if(isset($_SESSION['captcha'])) $ccheck = $_SESSION['captcha'];
+        if($_POST['captcha'] != $ccheck && $_POST['captcha'] != $ccheck1) {
+            $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
+            $email = '';
+        }
+    } else {
+        $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
         $email = '';
     }
-
-    // Check if the email exists in the database
-    $sSql = "SELECT * FROM `{TP}users` WHERE `email` = '" . $email . "'";
-    $rRow = $database->query($sSql);
-    if ($rRow->numRows() > 0) {
-
-        // Get the id, username, email, and last_reset from the above db query
-        $aUser = $rRow->fetchRow();
-        if (strlen($aUser['signup_confirmcode']) > 25) {
-            header("Location: " . WB_URL . "/account/signup_continue_page.php?switch=wrong_inputs");
-            exit(0); // break up the script here
-        }
-
-
-        // Check if the password has been reset in the last 2 hours
-        if ((time() - intval($aUser['last_reset'])) < (2 * 3600)) {
-            // Tell the user that their password cannot be reset more than once per hour
-            $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
-        } else {
-            $sCurrentPw = $aUser['password'];
-
-            // Generate a random password then update the database with it
-            $sNewPw = '';
-            $salt = "abchefghjkmnpqrstuvwxyz0123456789";
-            srand((double)microtime() * 1000000);
-            $i = 0;
-            while ($i <= 7) {
-                $num = rand() % 33;
-                $tmp = substr($salt, $num, 1);
-                $sNewPw = $sNewPw . $tmp;
-                $i++;
+    
+   
+    
+    if ($email != '') {
+         
+            if ($admin->validate_email($email) == false) {
+                $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);
+            }
+        
+        // Check if the email exists in the database
+        $sSql = "SELECT * FROM `{TP}users` WHERE `email`='".$database->escapeString($email)."'";
+        $rRow = $database->query($sSql);
+        if ($rRow->numRows() > 0) {
+
+            // Get the id, username, email, and last_reset from the above db query
+            $aUser = $rRow->fetchRow();
+            if (strlen($aUser['signup_confirmcode']) > 25) {
+                header("Location: " . WB_URL . "/account/signup_continue_page.php?switch=wrong_inputs");
+                exit(0); // break up the script here
             }
 
-            // update the new password in the database
-            $aUpdateUser = array(
-                'user_id' => $aUser['user_id'],
-                'password' => $wb->doPasswordEncode($sNewPw),
-                'last_reset' => time(),
-            );
-            $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
-
-            if ($database->is_error()) {
-                // Error updating database
-                $oMsgBox->error($database->get_error());
-            } else {
-                // Setup email to send
-                $mail_to = $email;
-                $mail_subject = $MESSAGE['SIGNUP2_SUBJECT_LOGIN_INFO'];
-
-                // Replace placeholders from language variable with values
-                $search = array('{LOGIN_DISPLAY_NAME}', '{LOGIN_WEBSITE_TITLE}', '{LOGIN_NAME}', '{LOGIN_PASSWORD}');
-                $replace = array($aUser['display_name'], WEBSITE_TITLE, $aUser['username'], $sNewPw);
-
-                $aTokenReplace = array(
-                    '{LOGIN_DISPLAY_NAME}' => $aUser['display_name'],
-                    '{LOGIN_NAME}' => $aUser['username'],
-                    '{LOGIN_WEBSITE_TITLE}' => WEBSITE_TITLE,
-                    '{LOGIN_PASSWORD}' => $sNewPw
-                );
 
+            // Check if the password has been reset in the last 2 hours
+            if ((time() - intval($aUser['last_reset'])) < (2 * 3600)) {
+                // Tell the user that their password cannot be reset more than once per hour
+                $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
+            } else {
+                $sCurrentPw = $aUser['password'];
+
+                // Generate a random password then update the database with it
+                $sNewPw = '';
+                $salt = "abchefghjkmnpqrstuvwxyz0123456789";
+                srand((double)microtime() * 1000000);
+                $i = 0;
+                while ($i <= 7) {
+                    $num = rand() % 33;
+                    $tmp = substr($salt, $num, 1);
+                    $sNewPw = $sNewPw . $tmp;
+                    $i++;
+                }
 
-                $mail_message = strtr($MESSAGE['SIGNUP2_BODY_LOGIN_FORGOT'], $aTokenReplace);
+                // update the new password in the database
+                $aUpdateUser = array(
+                    'user_id' => $aUser['user_id'],
+                    'password' => $wb->doPasswordEncode($sNewPw),
+                    'last_reset' => time(),
+                );
+                $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
 
-                // Try sending the email
-                if ($admin->mail(SERVER_EMAIL, $mail_to, $mail_subject, $mail_message)) {
-                    $oMsgBox->error($MESSAGE['FORGOT_PASS_PASSWORD_RESET']);
-                    $display_form = false;
+                if ($database->is_error()) {
+                    // Error updating database
+                    $oMsgBox->error($database->get_error());
                 } else {
-                    $aUpdateUser = array(
-                        'user_id' => $aUser['user_id'],
-                        'password' => $sCurrentPw
+                    // Setup email to send
+                    $mail_to = $email;
+                    $mail_subject = $MESSAGE['SIGNUP2_SUBJECT_LOGIN_INFO'];
+
+                    // Replace placeholders from language variable with values
+                    $search = array('{LOGIN_DISPLAY_NAME}', '{LOGIN_WEBSITE_TITLE}', '{LOGIN_NAME}', '{LOGIN_PASSWORD}');
+                    $replace = array($aUser['display_name'], WEBSITE_TITLE, $aUser['username'], $sNewPw);
+
+                    $aTokenReplace = array(
+                        '{LOGIN_DISPLAY_NAME}' => $aUser['display_name'],
+                        '{LOGIN_NAME}' => $aUser['username'],
+                        '{LOGIN_WEBSITE_TITLE}' => WEBSITE_TITLE,
+                        '{LOGIN_PASSWORD}' => $sNewPw
                     );
-                    $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
-                    $oMsgBox->error($MESSAGE['FORGOT_PASS_CANNOT_EMAIL']);
+
+
+                    $mail_message = strtr($MESSAGE['SIGNUP2_BODY_LOGIN_FORGOT'], $aTokenReplace);
+
+                    // Try sending the email
+                    if ($admin->mail(SERVER_EMAIL, $mail_to, $mail_subject, $mail_message)) {
+                        $oMsgBox->error($MESSAGE['FORGOT_PASS_PASSWORD_RESET']);
+                        $display_form = false;
+                    } else {
+                        $aUpdateUser = array(
+                            'user_id' => $aUser['user_id'],
+                            'password' => $sCurrentPw
+                        );
+                        $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
+                        $oMsgBox->error($MESSAGE['FORGOT_PASS_CANNOT_EMAIL']);
+                    }
                 }
             }
+        } else {
+            // Email doesn't exist, so tell the user
+            $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
+            // and delete the wrong Email
+            $email = '';
         }
-    } else {
-        // Email doesn't exist, so tell the user
-        $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
-        // and delete the wrong Email
-        $email = '';
     }
 } else {
     $email = '';
 }
 
@@ -122,10 +140,17 @@ if ($oMsgBox->hasErrors() == false) {
 // Create new phpLib Template object
 $template = new Template(dirname($admin->correct_theme_source('login_forgot.htt')));
 $template->set_file('page', 'login_forgot.htt');
 $template->set_block('page', 'main_block', 'main');
 
+ob_start();
+call_captcha("all","",'loginforgot');
+$captcha = ob_get_contents();
+ob_end_clean();
+
+
+
 $aTemplateVars = array(
     'SECTION_FORGOT' => $MENU['FORGOT'],
     'MESSAGE_COLOR' => '', //$message_color,
     'MESSAGE' => $oMsgBox->fetchDisplay(),
     'WB_URL' => WB_URL,
@@ -141,10 +166,11 @@ $aTemplateVars = array(
     'ACTION_URL' => defined('FRONTEND') ? 'forgot.php' : 'index.php',
     'LOGIN_URL' => defined('FRONTEND') ? WB_URL . '/account/login.php' : ADMIN_URL,
     'INTERFACE_URL' => ADMIN_URL . '/interface',
     'DEFAULT_CHARSET' => defined('DEFAULT_CHARSET') ? DEFAULT_CHARSET : 'utf-8',
     'CHARSET' => isset($charset) ? $charset : 'utf-8',
+    'CAPTCHA' => $captcha
 );
 $template->set_var($aTemplateVars);
 
 $template->parse('main', 'main_block', false);
 $template->pparse('output', 'page');
diff --git a/wbce/modules/tool_account_settings/account/form_forgot.php b/wbce/modules/tool_account_settings/account/form_forgot.php
index d821ec91..37c630fe 100644
--- a/wbce/modules/tool_account_settings/account/form_forgot.php
+++ b/wbce/modules/tool_account_settings/account/form_forgot.php
@@ -9,111 +9,134 @@
  * @copyright WBCE Project (since 2015)
  * @license GNU GPL2 (or any later version)
  */
 
 defined('WB_PATH') or die("Cannot access this file directly");
+require_once(WB_PATH.'/include/captcha/captcha.php');
 
 $oAccounts = new Accounts();
 $oMsgBox   = new MessageBox();
 
 $sLC       = defined('LANGUAGE') ? LANGUAGE : (defined('DEFAULT_LANGUAGE') ? DEFAULT_LANGUAGE : 'EN');
 $sEmail    = '';
 
 if(isset($_POST['email']) && $_POST['email'] != "" ) {
     $sEmail = strip_tags($oAccounts->get_post('email'));
-    if($admin->validate_email($sEmail) == false) {
-        $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);
-        $sEmail  = '';
+    
+    if(isset($_POST['captcha']) AND $_POST['captcha'] != ''){
+        $ccheck = time(); $ccheck1 = time();
+        if(isset($_SESSION['captchaaccountforgot'])) $ccheck1 = $_SESSION['captchaaccountforgot'];
+        if(isset($_SESSION['captcha'])) $ccheck = $_SESSION['captcha'];
+        if($_POST['captcha'] != $ccheck && $_POST['captcha'] != $ccheck1) {
+            $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
+            $sEmail = '';
+        }
     } else {
-        // Check if the email exists in the database
-        $sSql  = "SELECT * FROM `{TP}users` WHERE `email`='".$sEmail."'";
+        $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
+        $sEmail = '';
+    }
+    
+    if ($sEmail != '') {
+    
+        if($admin->validate_email($sEmail) == false) {
+            $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);
+            $sEmail  = '';
+        } else {
+            // Check if the email exists in the database
+            $sSql = "SELECT * FROM `{TP}users` WHERE `email`='".$database->escapeString($sEmail)."'";
 
-        if(($rRow = $database->query($sSql))){
-            if($aUser = $rRow->fetchRow(MYSQLI_ASSOC)) {
-                if(strlen($aUser['signup_confirmcode']) > 25){
-                    header("Location: ".ACCOUNT_URL."/signup_continue_page.php?switch=wrong_inputs");
-                    exit(0); // break up the script here
-                }
-                $iUserID = (int) $aUser['user_id'];
-                // Get the id, username, email, and last_reset from the above db query
+            if(($rRow = $database->query($sSql))){
+                if($aUser = $rRow->fetchRow(MYSQLI_ASSOC)) {
+                    if(strlen($aUser['signup_confirmcode']) > 25){
+                        header("Location: ".ACCOUNT_URL."/signup_continue_page.php?switch=wrong_inputs");
+                        exit(0); // break up the script here
+                    }
+                    $iUserID = (int) $aUser['user_id'];
+                    // Get the id, username, email, and last_reset from the above db query
 
-                // Check if the password has been reset in the last 2 hours
-                if( ( time() - intval($aUser['last_reset']) ) < (2 * 3600) ) {
-                    // Tell the user that their password cannot be reset more than once per hour
-                    $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
-                } else {
-                    // current password
-                    $sCurrentPw = $aUser['password'];
+                    // Check if the password has been reset in the last 2 hours
+                    if( ( time() - intval($aUser['last_reset']) ) < (2 * 3600) ) {
+                        // Tell the user that their password cannot be reset more than once per hour
+                        $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
+                    } else {
+                        // current password
+                        $sCurrentPw = $aUser['password'];
 
-                    // generate new password
-                    $sNewPasswordRaw = $oAccounts->GenerateRandomPassword();
-                    $sNewPasswordEnc = $oAccounts->doPasswordEncode($sNewPasswordRaw);
+                        // generate new password
+                        $sNewPasswordRaw = $oAccounts->GenerateRandomPassword();
+                        $sNewPasswordEnc = $oAccounts->doPasswordEncode($sNewPasswordRaw);
 
-                    // prepare E-Mail with login details to send to the user via email
-                    $aTokenReplace = array(
-                        'LOGIN_DISPLAY_NAME'  => $aUser['display_name'],
-                        'LOGIN_NAME'          => $aUser['username'],
-                        'LOGIN_WEBSITE_TITLE' => WEBSITE_TITLE,
-                        'LOGIN_PASSWORD'      => $sNewPasswordRaw,
-                        'LOGIN_URL'           => ACCOUNT_URL . '/login.php'
-                    );
+                        // prepare E-Mail with login details to send to the user via email
+                        $aTokenReplace = array(
+                            'LOGIN_DISPLAY_NAME'  => $aUser['display_name'],
+                            'LOGIN_NAME'          => $aUser['username'],
+                            'LOGIN_WEBSITE_TITLE' => WEBSITE_TITLE,
+                            'LOGIN_PASSWORD'      => $sNewPasswordRaw,
+                            'LOGIN_URL'           => ACCOUNT_URL . '/login.php'
+                        );
 
-                    $sOnScreenSwitch    = 'forgot_login_details_sent';
-                    $sEmailTemplateName = 'password_recovery_mail';
-                    $sEmailSubject      = '';
-                    $sMailTo            = $sEmail;
+                        $sOnScreenSwitch    = 'forgot_login_details_sent';
+                        $sEmailTemplateName = 'password_recovery_mail';
+                        $sEmailSubject      = '';
+                        $sMailTo            = $sEmail;
 
-                    $checkSend = $oAccounts->sendEmail($sMailTo, $aTokenReplace, $sEmailTemplateName, $sEmailSubject);
-                    if ($checkSend === true) {
-                        // update the new password in the database
-                        $aUpdateUser = array(
-                            'user_id'    => $iUserID,
-                            'password'   => $sNewPasswordEnc,
-                            'last_reset' => time(),
-                        );
+                        $checkSend = $oAccounts->sendEmail($sMailTo, $aTokenReplace, $sEmailTemplateName, $sEmailSubject);
+                        if ($checkSend === true) {
+                            // update the new password in the database
+                            $aUpdateUser = array(
+                                'user_id'    => $iUserID,
+                                'password'   => $sNewPasswordEnc,
+                                'last_reset' => time(),
+                            );
 
-                        if($database->updateRow('{TP}users', 'user_id', $aUpdateUser)){
-                            header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=".$sOnScreenSwitch."&email=".$sMailTo);
-                            exit(0);
-                        } else {
-                            // Error updating database
-                            $oMsgBox->error($MESSAGE['RECORD_MODIFIED_FAILED']);
-                            if(WB_DEBUG) {
-                                $oMsgBox->error($database->get_error().'<br />'.$sSql);
+                            if($database->updateRow('{TP}users', 'user_id', $aUpdateUser)){
+                                header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=".$sOnScreenSwitch."&email=".$sMailTo);
+                                exit(0);
+                            } else {
+                                // Error updating database
+                                $oMsgBox->error($MESSAGE['RECORD_MODIFIED_FAILED']);
+                                if(WB_DEBUG) {
+                                    $oMsgBox->error($database->get_error().'<br />'.$sSql);
+                                }
                             }
-                        }
 
-                    } else {
-                        // tell user: WRONG INPUTS
-                        $aUpdateUser = array(
-                            'user_id'    => $aUser['user_id'],
-                            'password'   => $sCurrentPw
-                        );
-                        $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
-                        header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=wrong_inputs&from=resend_forgot_pass&mail_err=".$checkSend);
-                        exit(0);
+                        } else {
+                            // tell user: WRONG INPUTS
+                            $aUpdateUser = array(
+                                'user_id'    => $aUser['user_id'],
+                                'password'   => $sCurrentPw
+                            );
+                            $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
+                            header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=wrong_inputs&from=resend_forgot_pass&mail_err=".$checkSend);
+                            exit(0);
+                        }
                     }
+                } else { // no record found - Email doesn't exist, so tell the user
+                    $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
+                }
+            } else {
+                // Query failed
+                if(WB_DEBUG) {
+                    $oMsgBox->error('SystemError:: Database query failed!');
+                    $oMsgBox->error($database->get_error().'<br />'.$sSql);
                 }
-            } else { // no record found - Email doesn't exist, so tell the user
-                $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
-            }
-        } else {
-            // Query failed
-            if(WB_DEBUG) {
-                $oMsgBox->error('SystemError:: Database query failed!');
-                $oMsgBox->error($database->get_error().'<br />'.$sSql);
             }
         }
     }
 }
 if($oMsgBox->hasErrors() == false ) {
     $oMsgBox->info($MESSAGE['FORGOT_PASS_NO_DATA'], 0, 1);
 }
 $email = $sEmail;
 $sHttpReferer = isset($_SESSION['HTTP_REFERER']) ? $_SESSION['HTTP_REFERER'] : $_SERVER['SCRIPT_NAME'];
+ob_start();
+call_captcha("all","","accountforgot");
+$captcha = ob_get_contents();
+ob_end_clean();
 
 // Get the template file for forgot_login_details
 $aToTwig = array(
     'EMAIL'         => $email,
+    'CAPTCHA'       => $captcha,
     'MESSAGE_BOX'   => $oMsgBox->fetchDisplay(),
 );
 $oAccounts->useTwigTemplate('form_forgot.twig', $aToTwig);
diff --git a/wbce/modules/tool_account_settings/templates/form_forgot.twig b/wbce/modules/tool_account_settings/templates/form_forgot.twig
index e064ef98..170c8c04 100644
--- a/wbce/modules/tool_account_settings/templates/form_forgot.twig
+++ b/wbce/modules/tool_account_settings/templates/form_forgot.twig
@@ -1,19 +1,21 @@
 {{ insertCssFile( CURRENT_DIR ~ '/forms.css') }}
+
+<p>{{ L_('MENU:FORGOT') }}</p>
 {{ MESSAGE_BOX }}
-<h2>{{ L_('MENU:FORGOT') }}</h2>
-<br />
 
 <form  class="login-box" name="forgot_pass" action="{{ constant("FORGOT_URL") }}" method="post">
     <div class="cpForm">
         <div class="formRow">
             <label class="settingName" for="display_name">{{ L_('TEXT:EMAIL') }}</label>
             <div class="settingValue">
                 <input type="text" maxlength="255" name="email" id="email" value="{{ EMAIL }}" />
             </div>
         </div>
-
+		<div class="formRow">
+		{{CAPTCHA}}
+		</div>
         <div class="buttonsRow">
             <button type="submit" name="submit" class="button pos-right">{{ L_('TEXT:SEND_DETAILS') }}</button>
         </div>		
     </div>		
 </form>
diff --git a/wbce/templates/argos_theme_reloaded/css/login.css b/wbce/templates/argos_theme_reloaded/css/login.css
index 7f6c082c..1411fd96 100644
--- a/wbce/templates/argos_theme_reloaded/css/login.css
+++ b/wbce/templates/argos_theme_reloaded/css/login.css
@@ -119,10 +119,19 @@ a:hover {
 
 .center {
     text-align: center;
 }
 
+.captcha_table {
+	display:inline-block;
+	margin:auto;
+}
+
+.error {
+	color:firebrick;
+}
+
 @media screen and (max-width: 36.5em) {
     .label {
         text-align: left;
         padding-top: 0;
     }
diff --git a/wbce/templates/argos_theme_reloaded/info.php b/wbce/templates/argos_theme_reloaded/info.php
index eea08c73..659efa2b 100644
--- a/wbce/templates/argos_theme_reloaded/info.php
+++ b/wbce/templates/argos_theme_reloaded/info.php
@@ -12,11 +12,11 @@
 
 // OBLIGATORY WBCE VARIABLES
 $template_directory = 'argos_theme_reloaded';
 $template_name = 'Argos Theme Reloaded';
 $template_function = 'theme';
-$template_version = '2.1.3';
-$template_platform = '1.4.0';
+$template_version = '2.1.4';
+$template_platform = '1.5.0';
 $template_author = 'Bernd Michna (BerndJM / WWnW) based on the work by Jurgen Nijhuis (Argos Media) & Ruud Eisinga';
 $template_license = '<a href="http://www.wtfpl.net/">WTFPL</a>';
 $template_license_terms = '-';
 $template_description = 'Enhanced backend theme for WBCE 1.x';
\ No newline at end of file
diff --git a/wbce/templates/argos_theme_reloaded/templates/login_forgot.htt b/wbce/templates/argos_theme_reloaded/templates/login_forgot.htt
index b9563271..165c6126 100644
--- a/wbce/templates/argos_theme_reloaded/templates/login_forgot.htt
+++ b/wbce/templates/argos_theme_reloaded/templates/login_forgot.htt
@@ -9,11 +9,11 @@
     <link href="{THEME_URL}/css/normalize.css" rel="stylesheet" type="text/css">
     <link href="{THEME_URL}/css/fitgrid.css" rel="stylesheet" type="text/css">
 	<link href="{THEME_URL}/css/login.css" rel="stylesheet" type="text/css">
 </head>
 
-<body onload="document.forgot_pass.email.focus();">
+<body onload="document.login.email.focus();">
 
 	<div id="container">
 		<header class="fg-center">
 			<div class="fg-row">
 				<h1 class="fg12 center">{SECTION_FORGOT}</h1>
@@ -25,20 +25,24 @@
 				<div class="fg12 content-box">
 					<form name="login" class="login" action="{ACTION_URL}" method="post" autocomplete="off">
 						<input type="hidden" name="url" value="{URL}">
 
 						<div class="fg12 center">
-							<p>{MESSAGE}:</p>
+							<div class="error">{MESSAGE}</div>
 						</div>
 
 						<hr class="fg12" style="margin-bottom: 15px;">
 
 						<div class="fg12 center">
 							<span>{TEXT_EMAIL}:</span>
 							<input type="text" name="email" value="{EMAIL}">
 						</div>
 
+						<div class="fg12 center">
+							{CAPTCHA}
+						</div>
+
 						<div class="fg12 center">
 							<button type="submit" name="submit" style="width:200px;">{TEXT_SEND_DETAILS}</button>
 						</div>
 					</form>
 
diff --git a/wbce/templates/wbce_flat_theme/css/login.css b/wbce/templates/wbce_flat_theme/css/login.css
index 448ee59f..b8746cd4 100644
--- a/wbce/templates/wbce_flat_theme/css/login.css
+++ b/wbce/templates/wbce_flat_theme/css/login.css
@@ -85,17 +85,23 @@ a:hover {
 .page_login input[type="submit"]:hover {
     background-color: #225183;
 }
 
 .page_login_link {
-    font-size: 13px;
+    display: block;
+    margin: 50px 0;
 }
 
 .login_license {
     font-size: 11px;
 }
 
+.captcha_table {
+    display: inline-block;
+    margin: auto;
+}
+
 @media (max-width: 550px) {
     .page_login_logo {
         background: none;
         padding-right: 0;
         right: 10px;
diff --git a/wbce/templates/wbce_flat_theme/info.php b/wbce/templates/wbce_flat_theme/info.php
index c739ba36..f2e774e6 100644
--- a/wbce/templates/wbce_flat_theme/info.php
+++ b/wbce/templates/wbce_flat_theme/info.php
@@ -12,11 +12,11 @@
 
 // OBLIGATORY WBCE VARIABLES
 $template_directory = 'wbce_flat_theme';
 $template_name = 'WBCE Flat Theme';
 $template_function = 'theme';
-$template_version = '1.7.5';
-$template_platform = '1.4';
+$template_version = '1.7.6';
+$template_platform = '1.5.0';
 $template_author = 'Colinax based on the work by Yetiie, BerndJM and rjgamer';
 $template_license = 'GNU General Public License';
 $template_license_terms = '-';
 $template_description = 'Flat theme for WBCE 1.x';
diff --git a/wbce/templates/wbce_flat_theme/templates/login_forgot.htt b/wbce/templates/wbce_flat_theme/templates/login_forgot.htt
index 0cbaaa6b..db7c4dcc 100644
--- a/wbce/templates/wbce_flat_theme/templates/login_forgot.htt
+++ b/wbce/templates/wbce_flat_theme/templates/login_forgot.htt
@@ -26,10 +26,11 @@
     <p>{MESSAGE}</p>
     <form name="forgot_pass" action="{ACTION_URL}" method="post">
         <div class="page_login-fields">
             <span class="page_login_fieldelement"><input placeholder="E-Mail" type="text" maxlength="255" name="email" value="{EMAIL}" /></span>
             <br/>
+            {CAPTCHA}
             <p><input type="submit" name="submit" value="{TEXT_SEND_DETAILS}" /></p>
             <p><a class="page_login_link" href="{LOGIN_URL}">{TEXT_NEED_TO_LOGIN}</a></p>
         </div>
     </form>
     <p class="login_license"><!-- Please note: the below reference to the GNU GPL should not be removed, as it provides a link for users to read about warranty, etc. --><a href="http://www.wbce.org/" title="Visit wbce.org">WBCE</a> is released under the <a href="http://www.gnu.org/licenses/gpl.html" title="GNU General Public License">GNU General Public License</a></p>

Vulnerable code: if (isset($_POST['email']) and $_POST['email'] != "") {
    if ($admin->validate_email($email) == false) {
        $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);

    // Check if the email exists in the database
    $sSql = "SELECT * FROM `{TP}users` WHERE `email` = '" . $email . "'";
    $rRow = $database->query($sSql);
    if ($rRow->numRows() > 0) {

        // Get the id, username, email, and last_reset from the above db query
        $aUser = $rRow->fetchRow();
        if (strlen($aUser['signup_confirmcode']) > 25) {
            header("Location: " . WB_URL . "/account/signup_continue_page.php?switch=wrong_inputs");
            exit(0); // break up the script here
        }


        // Check if the password has been reset in the last 2 hours
        if ((time() - intval($aUser['last_reset'])) < (2 * 3600)) {
            // Tell the user that their password cannot be reset more than once per hour
            $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
        } else {
            $sCurrentPw = $aUser['password'];

            // Generate a random password then update the database with it
            $sNewPw = '';
            $salt = "abchefghjkmnpqrstuvwxyz0123456789";
            srand((double)microtime() * 1000000);
            $i = 0;
            while ($i <= 7) {
                $num = rand() % 33;
                $tmp = substr($salt, $num, 1);
                $sNewPw = $sNewPw . $tmp;
                $i++;
            // update the new password in the database
            $aUpdateUser = array(
                'user_id' => $aUser['user_id'],
                'password' => $wb->doPasswordEncode($sNewPw),
                'last_reset' => time(),
            );
            $database->updateRow('{TP}users', 'user_id', $aUpdateUser);

            if ($database->is_error()) {
                // Error updating database
                $oMsgBox->error($database->get_error());
            } else {
                // Setup email to send
                $mail_to = $email;
                $mail_subject = $MESSAGE['SIGNUP2_SUBJECT_LOGIN_INFO'];

                // Replace placeholders from language variable with values
                $search = array('{LOGIN_DISPLAY_NAME}', '{LOGIN_WEBSITE_TITLE}', '{LOGIN_NAME}', '{LOGIN_PASSWORD}');
                $replace = array($aUser['display_name'], WEBSITE_TITLE, $aUser['username'], $sNewPw);

                $aTokenReplace = array(
                    '{LOGIN_DISPLAY_NAME}' => $aUser['display_name'],
                    '{LOGIN_NAME}' => $aUser['username'],
                    '{LOGIN_WEBSITE_TITLE}' => WEBSITE_TITLE,
                    '{LOGIN_PASSWORD}' => $sNewPw
                );
                $mail_message = strtr($MESSAGE['SIGNUP2_BODY_LOGIN_FORGOT'], $aTokenReplace);
                // Try sending the email
                if ($admin->mail(SERVER_EMAIL, $mail_to, $mail_subject, $mail_message)) {
                    $oMsgBox->error($MESSAGE['FORGOT_PASS_PASSWORD_RESET']);
                    $display_form = false;
                    $aUpdateUser = array(
                        'user_id' => $aUser['user_id'],
                        'password' => $sCurrentPw
                    $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
                    $oMsgBox->error($MESSAGE['FORGOT_PASS_CANNOT_EMAIL']);
    } else {
        // Email doesn't exist, so tell the user
        $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
        // and delete the wrong Email
        $email = '';
    if($admin->validate_email($sEmail) == false) {
        $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);
        $sEmail  = '';
        // Check if the email exists in the database
        $sSql  = "SELECT * FROM `{TP}users` WHERE `email`='".$sEmail."'";
        if(($rRow = $database->query($sSql))){
            if($aUser = $rRow->fetchRow(MYSQLI_ASSOC)) {
                if(strlen($aUser['signup_confirmcode']) > 25){
                    header("Location: ".ACCOUNT_URL."/signup_continue_page.php?switch=wrong_inputs");
                    exit(0); // break up the script here
                }
                $iUserID = (int) $aUser['user_id'];
                // Get the id, username, email, and last_reset from the above db query
                // Check if the password has been reset in the last 2 hours
                if( ( time() - intval($aUser['last_reset']) ) < (2 * 3600) ) {
                    // Tell the user that their password cannot be reset more than once per hour
                    $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
                } else {
                    // current password
                    $sCurrentPw = $aUser['password'];
                    // generate new password
                    $sNewPasswordRaw = $oAccounts->GenerateRandomPassword();
                    $sNewPasswordEnc = $oAccounts->doPasswordEncode($sNewPasswordRaw);
                    // prepare E-Mail with login details to send to the user via email
                    $aTokenReplace = array(
                        'LOGIN_DISPLAY_NAME'  => $aUser['display_name'],
                        'LOGIN_NAME'          => $aUser['username'],
                        'LOGIN_WEBSITE_TITLE' => WEBSITE_TITLE,
                        'LOGIN_PASSWORD'      => $sNewPasswordRaw,
                        'LOGIN_URL'           => ACCOUNT_URL . '/login.php'
                    );
                    $sOnScreenSwitch    = 'forgot_login_details_sent';
                    $sEmailTemplateName = 'password_recovery_mail';
                    $sEmailSubject      = '';
                    $sMailTo            = $sEmail;
                    $checkSend = $oAccounts->sendEmail($sMailTo, $aTokenReplace, $sEmailTemplateName, $sEmailSubject);
                    if ($checkSend === true) {
                        // update the new password in the database
                        $aUpdateUser = array(
                            'user_id'    => $iUserID,
                            'password'   => $sNewPasswordEnc,
                            'last_reset' => time(),
                        );
                        if($database->updateRow('{TP}users', 'user_id', $aUpdateUser)){
                            header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=".$sOnScreenSwitch."&email=".$sMailTo);
                            exit(0);
                        } else {
                            // Error updating database
                            $oMsgBox->error($MESSAGE['RECORD_MODIFIED_FAILED']);
                            if(WB_DEBUG) {
                                $oMsgBox->error($database->get_error().'<br />'.$sSql);
                        }
                    } else {
                        // tell user: WRONG INPUTS
                        $aUpdateUser = array(
                            'user_id'    => $aUser['user_id'],
                            'password'   => $sCurrentPw
                        );
                        $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
                        header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=wrong_inputs&from=resend_forgot_pass&mail_err=".$checkSend);
                        exit(0);
            } else { // no record found - Email doesn't exist, so tell the user
                $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
            }
        } else {
            // Query failed
            if(WB_DEBUG) {
                $oMsgBox->error('SystemError:: Database query failed!');
                $oMsgBox->error($database->get_error().'<br />'.$sSql);
<h2>{{ L_('MENU:FORGOT') }}</h2>
<br />

$template_version = '2.1.3';
$template_platform = '1.4.0';
<body onload="document.forgot_pass.email.focus();">
							<p>{MESSAGE}:</p>
    font-size: 13px;
$template_version = '1.7.5';
$template_platform = '1.4';
Fixed code: require_once(WB_PATH.'/include/captcha/captcha.php');
if (isset($_POST['email']) && $_POST['email'] != "" ) {
    if(isset($_POST['captcha']) AND $_POST['captcha'] != ''){
        $ccheck = time(); $ccheck1 = time();
        if(isset($_SESSION['captchaloginforgot'])) $ccheck1 = $_SESSION['captchaloginforgot'];
        if(isset($_SESSION['captcha'])) $ccheck = $_SESSION['captcha'];
        if($_POST['captcha'] != $ccheck && $_POST['captcha'] != $ccheck1) {
            $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
            $email = '';
        }
    } else {
        $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
    
   
    
    if ($email != '') {
         
            if ($admin->validate_email($email) == false) {
                $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);
            }
        
        // Check if the email exists in the database
        $sSql = "SELECT * FROM `{TP}users` WHERE `email`='".$database->escapeString($email)."'";
        $rRow = $database->query($sSql);
        if ($rRow->numRows() > 0) {

            // Get the id, username, email, and last_reset from the above db query
            $aUser = $rRow->fetchRow();
            if (strlen($aUser['signup_confirmcode']) > 25) {
                header("Location: " . WB_URL . "/account/signup_continue_page.php?switch=wrong_inputs");
                exit(0); // break up the script here
            // Check if the password has been reset in the last 2 hours
            if ((time() - intval($aUser['last_reset'])) < (2 * 3600)) {
                // Tell the user that their password cannot be reset more than once per hour
                $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
            } else {
                $sCurrentPw = $aUser['password'];

                // Generate a random password then update the database with it
                $sNewPw = '';
                $salt = "abchefghjkmnpqrstuvwxyz0123456789";
                srand((double)microtime() * 1000000);
                $i = 0;
                while ($i <= 7) {
                    $num = rand() % 33;
                    $tmp = substr($salt, $num, 1);
                    $sNewPw = $sNewPw . $tmp;
                    $i++;
                }
                // update the new password in the database
                $aUpdateUser = array(
                    'user_id' => $aUser['user_id'],
                    'password' => $wb->doPasswordEncode($sNewPw),
                    'last_reset' => time(),
                );
                $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
                if ($database->is_error()) {
                    // Error updating database
                    $oMsgBox->error($database->get_error());
                    // Setup email to send
                    $mail_to = $email;
                    $mail_subject = $MESSAGE['SIGNUP2_SUBJECT_LOGIN_INFO'];

                    // Replace placeholders from language variable with values
                    $search = array('{LOGIN_DISPLAY_NAME}', '{LOGIN_WEBSITE_TITLE}', '{LOGIN_NAME}', '{LOGIN_PASSWORD}');
                    $replace = array($aUser['display_name'], WEBSITE_TITLE, $aUser['username'], $sNewPw);

                    $aTokenReplace = array(
                        '{LOGIN_DISPLAY_NAME}' => $aUser['display_name'],
                        '{LOGIN_NAME}' => $aUser['username'],
                        '{LOGIN_WEBSITE_TITLE}' => WEBSITE_TITLE,
                        '{LOGIN_PASSWORD}' => $sNewPw


                    $mail_message = strtr($MESSAGE['SIGNUP2_BODY_LOGIN_FORGOT'], $aTokenReplace);

                    // Try sending the email
                    if ($admin->mail(SERVER_EMAIL, $mail_to, $mail_subject, $mail_message)) {
                        $oMsgBox->error($MESSAGE['FORGOT_PASS_PASSWORD_RESET']);
                        $display_form = false;
                    } else {
                        $aUpdateUser = array(
                            'user_id' => $aUser['user_id'],
                            'password' => $sCurrentPw
                        );
                        $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
                        $oMsgBox->error($MESSAGE['FORGOT_PASS_CANNOT_EMAIL']);
                    }
        } else {
            // Email doesn't exist, so tell the user
            $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
            // and delete the wrong Email
            $email = '';
ob_start();
call_captcha("all","",'loginforgot');
$captcha = ob_get_contents();
ob_end_clean();



    'CAPTCHA' => $captcha
require_once(WB_PATH.'/include/captcha/captcha.php');
    
    if(isset($_POST['captcha']) AND $_POST['captcha'] != ''){
        $ccheck = time(); $ccheck1 = time();
        if(isset($_SESSION['captchaaccountforgot'])) $ccheck1 = $_SESSION['captchaaccountforgot'];
        if(isset($_SESSION['captcha'])) $ccheck = $_SESSION['captcha'];
        if($_POST['captcha'] != $ccheck && $_POST['captcha'] != $ccheck1) {
            $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
            $sEmail = '';
        }
        $oMsgBox->error($MESSAGE['MOD_FORM_INCORRECT_CAPTCHA']);
        $sEmail = '';
    }
    
    if ($sEmail != '') {
    
        if($admin->validate_email($sEmail) == false) {
            $oMsgBox->error($MESSAGE['USERS_INVALID_EMAIL']);
            $sEmail  = '';
        } else {
            // Check if the email exists in the database
            $sSql = "SELECT * FROM `{TP}users` WHERE `email`='".$database->escapeString($sEmail)."'";
            if(($rRow = $database->query($sSql))){
                if($aUser = $rRow->fetchRow(MYSQLI_ASSOC)) {
                    if(strlen($aUser['signup_confirmcode']) > 25){
                        header("Location: ".ACCOUNT_URL."/signup_continue_page.php?switch=wrong_inputs");
                        exit(0); // break up the script here
                    }
                    $iUserID = (int) $aUser['user_id'];
                    // Get the id, username, email, and last_reset from the above db query
                    // Check if the password has been reset in the last 2 hours
                    if( ( time() - intval($aUser['last_reset']) ) < (2 * 3600) ) {
                        // Tell the user that their password cannot be reset more than once per hour
                        $oMsgBox->error($MESSAGE['FORGOT_PASS_ALREADY_RESET']);
                    } else {
                        // current password
                        $sCurrentPw = $aUser['password'];
                        // generate new password
                        $sNewPasswordRaw = $oAccounts->GenerateRandomPassword();
                        $sNewPasswordEnc = $oAccounts->doPasswordEncode($sNewPasswordRaw);
                        // prepare E-Mail with login details to send to the user via email
                        $aTokenReplace = array(
                            'LOGIN_DISPLAY_NAME'  => $aUser['display_name'],
                            'LOGIN_NAME'          => $aUser['username'],
                            'LOGIN_WEBSITE_TITLE' => WEBSITE_TITLE,
                            'LOGIN_PASSWORD'      => $sNewPasswordRaw,
                            'LOGIN_URL'           => ACCOUNT_URL . '/login.php'
                        );
                        $sOnScreenSwitch    = 'forgot_login_details_sent';
                        $sEmailTemplateName = 'password_recovery_mail';
                        $sEmailSubject      = '';
                        $sMailTo            = $sEmail;
                        $checkSend = $oAccounts->sendEmail($sMailTo, $aTokenReplace, $sEmailTemplateName, $sEmailSubject);
                        if ($checkSend === true) {
                            // update the new password in the database
                            $aUpdateUser = array(
                                'user_id'    => $iUserID,
                                'password'   => $sNewPasswordEnc,
                                'last_reset' => time(),
                            );
                            if($database->updateRow('{TP}users', 'user_id', $aUpdateUser)){
                                header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=".$sOnScreenSwitch."&email=".$sMailTo);
                                exit(0);
                            } else {
                                // Error updating database
                                $oMsgBox->error($MESSAGE['RECORD_MODIFIED_FAILED']);
                                if(WB_DEBUG) {
                                    $oMsgBox->error($database->get_error().'<br />'.$sSql);
                                }
                        } else {
                            // tell user: WRONG INPUTS
                            $aUpdateUser = array(
                                'user_id'    => $aUser['user_id'],
                                'password'   => $sCurrentPw
                            );
                            $database->updateRow('{TP}users', 'user_id', $aUpdateUser);
                            header("Location: ".ACCOUNT_URL."/signup_continue_page.php?lc=".$sLC."&switch=wrong_inputs&from=resend_forgot_pass&mail_err=".$checkSend);
                            exit(0);
                        }
                } else { // no record found - Email doesn't exist, so tell the user
                    $oMsgBox->error($MESSAGE['FORGOT_PASS_EMAIL_NOT_FOUND']);
                }
            } else {
                // Query failed
                if(WB_DEBUG) {
                    $oMsgBox->error('SystemError:: Database query failed!');
                    $oMsgBox->error($database->get_error().'<br />'.$sSql);
ob_start();
call_captcha("all","","accountforgot");
$captcha = ob_get_contents();
ob_end_clean();
    'CAPTCHA'       => $captcha,

<p>{{ L_('MENU:FORGOT') }}</p>
		<div class="formRow">
		{{CAPTCHA}}
		</div>
.captcha_table {
	display:inline-block;
	margin:auto;
}

.error {
	color:firebrick;
}

$template_version = '2.1.4';
$template_platform = '1.5.0';
<body onload="document.login.email.focus();">
							<div class="error">{MESSAGE}</div>
						<div class="fg12 center">
							{CAPTCHA}
						</div>

    display: block;
    margin: 50px 0;
.captcha_table {
    display: inline-block;
    margin: auto;
}

$template_version = '1.7.6';
$template_platform = '1.5.0';
            {CAPTCHA}