Threat Intelligence and Security Incidents
Vulnerability Analysis | GitLab Password Reset Vulnerability for Arbitrary Users (CVE-2023-7028)

GitLab is a web-based Git repository management tool. It provides a complete set of code management tools, including version control, code review, issue tracking, continuous integration, and other functions. Through GitLab, teams can collaborate and manage code on a unified platform.
On January 11, 2024, Gitlab officially disclosed the CVE-2023-7028 GitLab arbitrary user password reset vulnerability, which was officially rated as critical. Attackers can exploit the forgot password feature to construct malicious requests to obtain password reset links and thus reset passwords.
The official security update has been released, and it is recommended to upgrade to the latest version. If upgrading is not possible, it is recommended to use the security group function to set Gitlab to only be open to trusted addresses.
▌Vulnerability Replication
1. Target Environment Construction
1) Use docker to execute the following commands.

2) Configure SMTP mail sending function.
Enter the docker container, modify the /etc/gitlab/gitlab.rb file, and add the following content to the end of the file. Note to replace it with your own email configuration.

Reload the configuration file.
gitlab-ctl reconfigure
3) Test whether the mailbox configuration is correct.

Check your email to see if you received the email.
4) Gitlab sets the default root user account and password.

5) Gitlab sets the default root user's email.
Use the account and password set above to log in on the browser.

Enter the profile settings page, set the root user's email address, then scroll down to the bottom of the page, click Update profile settings, enter password and save.

Here, burpsuite is used to generate the domain name and form the address: root@wwwm3saic0gloubgkfl2p989208uwkk9.oastify.com (Note that the admin user cannot be used, otherwise the email will not be received).

Copy the link in the email and fill it into the browser to access and confirm the email address.
▌Vulnerability Exploitation
Tools:
Browser
BurpSuite
Specific Steps:
1) Use BurpSuite to start packet capturing, click "Forgot your password?" on the Gitlab login page to access the password reset page.

2) Enable intercept in BurpSuite, enter a user's email address on the page: root@wwwm3saic0gloubgkfl2p989208uwkk9.oastify.com, and click Reset password.
3) After BurpSuite intercepts the packet, decode the request body.

4) Use the Dnslog function to generate a temporary email address: hacker@086qfwmmo4sp0ynkwjx61dkde4kz8pwe.oastify.com, and modify the packet as follows:

5) URL-encode the modified content and send it.

6) Observe the dnslog. It can be seen that root@wwwm3saic0gloubgkfl2p989208uwkk9.oastify.com and hacker@086qfwmmo4sp0ynkwjx61dkde4kz8pwe.oastify.com received the email at the same time.
Email received by the root user:

Email received by the hacker:

7) The password reset links received by both are the same. Now open the link in the browser and enter the new password.

Click "Change your password" to redirect to the home page with a message showing that the modification is successful.

▌Vulnerability Analysis
Through traffic capturing, we found that when the email address is filled in and the "Reset password" button is clicked, the browser will call the /users/password interface using the POST method.

According to GitLab's official advisory, we know that this feature was introduced in version 16.1.0. Therefore, we can use the above information to find the source code and specific implementation of this interface. First, we switch the branch to v16.1.0-ee in the gitlab repository and search for /users/password to find the routing rules for this interface.

Through routing rules, we found app/controllers/passwords_controller.rb, but we did not find the specific implementation of the create method in the controller, but we did find the following key information.

In the key information above, we found that PasswordsController inherits from Devise::PasswordsController. Devise is an open-source authentication and authorization library for Ruby on Rails applications. It simplifies development tasks such as user authentication and management, registration, and session management.
The version number of the dependent Devise is recorded in Gemfile.lock.

We found the implementation of the create method in the PasswordsController module in the Devise repository on Github.

There is a line of code like this in the create method.

From the method name called in this code, it can be seen that it means sending instructions to set the password, specifically sending an email containing a password reset link. And resource_params is our request parameter, which is the email address. We found the implementation of the send_reset_password_instructions method in both the Devise library and the Gitlab source code respectively.
In the Devise library lib/devise/models/recoverable.rb:

In the Gitlab source code app/models/concerns/recoverable_by_any_email.rb:

From the code comments, we can see that Gitlab overrides the send_reset_password_instructions method in the Devise library.
Moreover, there are actually two send_reset_password_instructions methods in Gitlab's recoverable_by_any_email.rb. The method wrapped in "class_methods do … end" belongs to the class method of the module, which is called through the class (i.e. resource_class mentioned above). This method is mainly used to handle the logic of sending password reset instructions when a user requests a password reset.
In this method, the user instance is obtained through the by_email_with_errors method, and then the instance method of the same name outside the class is called through the user instance.
The cause of this vulnerability lies in the by_email_with_errors method, which is used to check whether the user corresponding to the email exists and whether the user has confirmed the email address. If confirmed, the user instance is returned. This method calls find_by_any_email(email, confirmed: true) to get the user corresponding to the email parameter. We found the definition of this function in the app/models/user.rb file:

It can be seen that the find_by_any_email method calls the by_any_email method, and the by_any_email method supports passing in an array of emails. Therefore, passing an array into the email variable of the find_by_any_email method, and this array contains a verified email, the method can return a valid user record.
Finally, send the password reset email through recoverable.send_reset_password_instructions(to: email).
▌SecVerify Validation Rules
The attack simulation for this vulnerability has been integrated into the SecVerify Security Metric Validation Platform. You can search for the keywords "CVE-2023-7028" or "GitLab" on the platform to obtain the relevant attack simulation validation actions. This allows you to verify whether your security defense system can effectively handle this vulnerability. The platform ensures that your validation process is secure and harmless in an industry-unique manner.

References:
https://about.gitlab.com/releases/2024/01/11/critical-security-release-gitlab-16-7-2-released/ https://gitlab.com/gitlab-org/gitlab https://github.com/heartcombo/devise


