CVE-2024-34077 (published 2024-05-14T15:38Z)

MantisBT (Mantis Bug Tracker) is an open source issue tracker. Insufficient access control in the registration and password reset process allows an attacker to reset another user's password and takeover their account, if the victim has an incomplete request pending. The exploit is only possible while the verification token is valid, i.e for 5 minutes after the confirmation URL sent by e-mail has been opened, and the user did not complete the process by updating their password. A brute-force attack calling account_update.php with increasing user IDs is possible. A successful takeover would grant the attacker full access to the compromised account, including sensitive information and functionalities associated with the account, the extent of which depends on its privileges and the data it has access to. Version 2.26.2 contains a patch for the issue. As a workaround, one may mitigate the risk by reducing the verification token's validity (change the value of the `TOKEN_EXPIRY_AUTHENTICATED` constant in `constants_inc.php`).


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/mantisbt/mantisbt
commit_details: repo_url: https://github.com/mantisbt/mantisbt
author: Damien Regad
author_date: 2024-05-06 02:09:03+02:00
msg: Validate confirm hash when updating account

This prevents an attacker from resetting another user's password if they
have an incomplete account validation or password reset request pending.

Fixes #34433, CVE-2024-xxxxx
repository: repo_url: https://github.com/mantisbt/mantisbt
repo_name: mantisbt/mantisbt
description: Mantis Bug Tracker (MantisBT)
repo_language: PHP
owner: mantisbt
file_changes: filename: account_update.php
change_type: ModificationType.MODIFY
diff: @@ -60,19 +60,30 @@ require_api( 'utility_api.php' );
 
 form_security_validate( 'account_update' );
 
-# If token is set, it's a password reset request from verify.php, and if
-# not we need to reauthenticate the user
-$t_verify_user_id = gpc_get( 'verify_user_id', false );
-$t_account_verification = $t_verify_user_id ? token_get_value( TOKEN_ACCOUNT_VERIFY, $t_verify_user_id ) : false;
-if( !$t_account_verification ) {
-	auth_reauthenticate();
-	$t_user_id = auth_get_current_user_id();
-} else {
+$t_verify_user_id = gpc_get_int( 'verify_user_id', 0 );
+$t_account_verification = (bool)$t_verify_user_id;
+if( $t_account_verification ) {
+	# Password reset request from verify.php - validate the confirmation hash
+	$f_confirm_hash = gpc_get_string( 'confirm_hash' );
+	$t_token_confirm_hash = token_get_value( TOKEN_ACCOUNT_ACTIVATION, $t_verify_user_id );
+	if( $t_token_confirm_hash == null || $f_confirm_hash !== $t_token_confirm_hash ) {
+		trigger_error( ERROR_LOST_PASSWORD_CONFIRM_HASH_INVALID, ERROR );
+	}
+
+	# Make sure the token is not expired
+	if( null === token_get_value( TOKEN_ACCOUNT_VERIFY, $t_verify_user_id ) ) {
+		trigger_error( ERROR_SESSION_NOT_VALID, ERROR );
+	}
+
 	# set a temporary cookie so the login information is passed between pages.
 	auth_set_cookies( $t_verify_user_id );
 	# fake login so the user can set their password
 	auth_attempt_script_login( user_get_username( $t_verify_user_id ) );
 	$t_user_id = $t_verify_user_id;
+} else {
+	# Normal account update - authenticate the user
+	auth_reauthenticate();
+	$t_user_id = auth_get_current_user_id();
 }
 
 auth_ensure_user_authenticated();

programming_language: PHP
filename: verify.php
change_type: ModificationType.MODIFY
diff: @@ -131,6 +131,7 @@ layout_login_page_begin();
 					<legend><span><?php echo lang_get( 'edit_account_title' ) . ' - ' . string_display_line( $u_username ) ?></span></legend>
 					<div class="space-10"></div>
 					<input type="hidden" name="verify_user_id" value="<?php echo $u_id ?>">
+					<input type="hidden" name="confirm_hash" value="<?php echo string_html_specialchars( $f_confirm_hash ) ?>">
 					<?php
 					echo form_security_field( 'account_update' );
 					# When verifying account, set a token and don't display current password

programming_language: PHP