1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
From: ahacker1 <ahacker1@securesaml.com>
Date: Tue, 10 Sep 2024 13:12:09 -0400
Subject: Fix for critical vulnerability CVE-2024-45409: SAML authentication bypass via Incorrect XPath selector
Origin: https://github.com/SAML-Toolkits/ruby-saml/commit/4865d030cae9705ee5cdb12415c654c634093ae7,
https://github.com/SAML-Toolkits/ruby-saml/commit/1bc447f297b769d1a9abeb619ce074bd9c410a72
Bug-Debian: https://bugs.debian.org/1081560
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2024-45409
* Use correct XPaths and resolve to correct elements
* Update xml_security.rb
* Block references that resolve to multiple nodes to prevent signature wrapping attacks
[Salvatore Bonaccorso: Cherry-pick from upstream 1bc447f297b769d1a9abeb619ce074bd9c410a72 the
final append_error string used]
---
lib/xml_security.rb | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/lib/xml_security.rb b/lib/xml_security.rb
index 1b1b32284e05..f731d4642d73 100644
--- a/lib/xml_security.rb
+++ b/lib/xml_security.rb
@@ -310,17 +310,29 @@ module XMLSecurity
canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
noko_sig_element.remove
+ # get signed info
+ signed_info_element = REXML::XPath.first(
+ sig_element,
+ "./ds:SignedInfo",
+ { "ds" => DSIG }
+ )
# get inclusive namespaces
inclusive_namespaces = extract_inclusive_namespaces
# check digests
- ref = REXML::XPath.first(sig_element, "//ds:Reference", {"ds"=>DSIG})
+ ref = REXML::XPath.first(signed_info_element, "./ds:Reference", {"ds"=>DSIG})
- hashed_element = document.at_xpath("//*[@ID=$id]", nil, { 'id' => extract_signed_element_id })
+ reference_nodes = document.xpath("//*[@ID=$id]", nil, { 'id' => extract_signed_element_id })
+
+ if reference_nodes.length > 1 # ensures no elements with same ID to prevent signature wrapping attack.
+ return append_error("Digest mismatch. Duplicated ID found", soft)
+ end
+
+ hashed_element = reference_nodes[0]
canon_algorithm = canon_algorithm REXML::XPath.first(
- ref,
- '//ds:CanonicalizationMethod',
+ signed_info_element,
+ './ds:CanonicalizationMethod',
{ "ds" => DSIG }
)
@@ -330,13 +342,13 @@ module XMLSecurity
digest_algorithm = algorithm(REXML::XPath.first(
ref,
- "//ds:DigestMethod",
+ "./ds:DigestMethod",
{ "ds" => DSIG }
))
hash = digest_algorithm.digest(canon_hashed_element)
encoded_digest_value = REXML::XPath.first(
ref,
- "//ds:DigestValue",
+ "./ds:DigestValue",
{ "ds" => DSIG }
)
digest_value = Base64.decode64(OneLogin::RubySaml::Utils.element_text(encoded_digest_value))
@@ -362,7 +374,7 @@ module XMLSecurity
def process_transforms(ref, canon_algorithm)
transforms = REXML::XPath.match(
ref,
- "//ds:Transforms/ds:Transform",
+ "./ds:Transforms/ds:Transform",
{ "ds" => DSIG }
)
--
2.45.2
|