Explorer
KNOW-PAT-077

CloudPanel v2.5.2 - FastCGI cross-user RCE, CVE-2024-44765, sudo NOPASSWD

Domaine
cybersecu
Type
pattern
Priorité
P2

Parent : [[INDEX-CYBERSECU]]

CloudPanel v2.5.2 - FastCGI cross-user RCE, CVE-2024-44765, sudo NOPASSWD

Problème

CloudPanel v2.5.2 est vulnérable à CVE-2024-44765 (modification des configs vhost nginx pour fuiter .env, base SQLite, /etc/shadow, clés SSH) et à une escalade PHP-FPM via FastCGI sur 127.0.0.1:8787 sans contrôle d'accès. L'utilisateur clp dispose de sudo NOPASSWD, permettant une escalade de privilèges.

Contexte archive Ygg

  • Source : https://yggleak.top/fr/home/ygg-dossier#phase-13-le-serveur-web-185-132-134-125
  • Phase 13 — Le serveur web (X.X.X.X)
  • CloudPanel : v2.5.2
  • CVE : CVE-2024-44765
  • Port FastCGI : 127.0.0.1:8787 (sans contrôle d'accès)
  • Utilisateur : clp avec sudo NOPASSWD
  • Exploitation : Cross-user (depuis le compte ygg, exécution de code PHP en tant que n'importe quel autre utilisateur)

Technique d'exploitation

1. CVE-2024-44765 — Fuite de fichiers via nginx vhost

Modification des configs vhost nginx pour fuiter :
- .env
- base SQLite
- /etc/shadow
- clés SSH

2. FastCGI cross-user

# CloudPanel expose des ports FastCGI internes sans contrôle d'accès
# Depuis le compte ygg, on peut exécuter du code PHP en tant que n'importe quel autre utilisateur du serveur

# Un script FastCGI minimal suffit pour obtenir l'exécution de code
# dans le contexte de chaque site — et donc l'accès à leurs bases de données respectives

3. sudo NOPASSWD

# Utilisateur clp avec sudo sans mot de passe
clp ALL=(ALL) NOPASSWD: ALL

Conséquences :

  • Accès root sans authentification
  • Exécution de commandes système
  • Modification de tous les fichiers

Solution protectif — Sécurisation de CloudPanel et PHP-FPM

1. Désactiver sudo NOPASSWD

#!/bin/bash
# remove-nopasswd.sh

# Éditer /etc/sudoers ou /etc/sudoers.d/cloudpanel
# Supprimer ou modifier :
# clp ALL=(ALL) NOPASSWD: ALL

# Remplacer par :
# clp ALL=(ALL) ALL
# (requiert un mot de passe)

# OU mieux :
# clp ALL=(root) /usr/sbin/service nginx *, /usr/sbin/service php*
# (commandes spécifiques uniquement)

visudo -c  # Vérifier la syntaxe

2. Sécuriser PHP-FPM — Un pool par utilisateur

; /etc/php/8.1/fpm/pool.d/ygg.conf
[ygg]
user = ygg
group = ygg
listen = /run/php/php8.1-fpm-ygg.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; PAS de TCP (seulement UNIX socket)
; PAS de listen = 127.0.0.1:8787

; Chroot pour isoler le site
chroot = /home/ygg/htdocs

; Restrictions de sécurité
php_admin_value[open_basedir] = /home/ygg/htdocs:/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
php_admin_flag[allow_url_fopen] = off
php_admin_flag[allow_url_include] = off

3. Isolation FastCGI via AppArmor/SELinux

# AppArmor profile pour PHP-FPM
cat << 'EOF' > /etc/apparmor.d/usr.sbin.php-fpm8.1
#include <tunables/global>

/usr/sbin/php-fpm8.1 {
  #include <abstractions/base>
  
  # Uniquement les sockets UNIX (pas de TCP)
  /run/php/*.sock rw,
  
  # Pas d'accès aux fichiers d'autres utilisateurs
  /home/*/htdocs/** r,
  deny /home/*/htdocs/** w,
  
  # Pas d'accès aux fichiers système sensibles
  deny /etc/shadow r,
  deny /etc/passwd r,
  deny /root/** r,
  deny /home/*/.ssh/** r,
}
EOF

apparmor_parser -r /etc/apparmor.d/usr.sbin.php-fpm8.1

4. Patching CVE-2024-44765

#!/bin/bash
# patch-cloudpanel.sh

# 1. Mettre à jour CloudPanel
cloudpanel update

# 2. Vérifier la version
cloudpanel --version
# Doit être >= 2.5.3 (patché)

# 3. Restreindre les permissions des configs nginx
chmod 640 /etc/nginx/sites-enabled/*
chown root:nginx /etc/nginx/sites-enabled/*

# 4. Empêcher la modification des vhost par les utilisateurs
# Vérifier que les fichiers ne sont pas modifiables par www-data
ls -la /etc/nginx/sites-enabled/

5. Détection de FastCGI cross-user

# detect_fastcgi_abuse.py
import socket
import struct

class FastCGIDetector:
    def __init__(self):
        self.suspicious_endpoints = [
            '127.0.0.1:8787',
            '127.0.0.1:9000',
            '127.0.0.1:9001'
        ]
    
    def scan_fastcgi_ports(self):
        """Scanner les ports FastCGI accessibles"""
        open_ports = []
        
        for endpoint in self.suspicious_endpoints:
            host, port = endpoint.split(':')
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.settimeout(2)
                result = sock.connect_ex((host, int(port)))
                if result == 0:
                    open_ports.append(endpoint)
                    print(f"[ALERT] Port FastCGI ouvert sans restriction: {endpoint}")
                sock.close()
            except Exception as e:
                print(f"[ERROR] Scan {endpoint}: {e}")
        
        return open_ports
    
    def test_cross_user_access(self, endpoint, target_user):
        """Tester l'accès cross-user via FastCGI"""
        # Construire une requête FastCGI minimale
        # Si on peut exécuter du code en tant que target_user, c'est vulnérable
        
        # Requête FastCGI avec SCRIPT_FILENAME pointant vers un fichier
        # appartenant à target_user
        
        fastcgi_request = self.build_fastcgi_request(
            script_filename=f'/home/{target_user}/htdocs/test.php',
            document_root=f'/home/{target_user}/htdocs'
        )
        
        # Envoyer et vérifier la réponse
        # Si le fichier est exécuté (pas d'erreur 403), c'est vulnérable
        
        return False  # Simplifié
    
    def build_fastcgi_request(self, script_filename, document_root):
        # Construction d'une requête FastCGI
        # Version 1, type 1 (BEGIN_REQUEST)
        # ...
        pass

# Utilisation
detector = FastCGIDetector()
open_ports = detector.scan_fastcgi_ports()

6. Monitoring des requêtes FastCGI suspectes

# nginx monitoring — loguer les requêtes FastCGI
server {
    listen 80;
    server_name _;
    
    location ~ \.php$ {
        # Loguer les requêtes suspectes
        access_log /var/log/nginx/fastcgi-access.log;
        
        # Restreindre le SCRIPT_FILENAME
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        
        # Ne PAS passer PHP_VALUE/PHP_ADMIN_VALUE
        fastcgi_param PHP_VALUE "";
        fastcgi_param PHP_ADMIN_VALUE "";
        
        # Vérifier que le fichier appartient à l'utilisateur
        # (via un script Lua ou un module nginx)
        
        fastcgi_pass unix:/run/php/$user.sock;
    }
}

Checklist de validation

  • CloudPanel mis à jour (>= 2.5.3, patch CVE-2024-44765)
  • sudo NOPASSWD supprimé pour tous les utilisateurs
  • PHP-FPM sur sockets UNIX (pas TCP exposé)
  • Un pool PHP-FPM par utilisateur (isolation)
  • chroot activé pour chaque pool
  • open_basedir configuré pour chaque site
  • disable_functions restreint (pas de exec/shell_exec/system)
  • AppArmor/SELinux pour isoler PHP-FPM
  • Pas de PHP_VALUE/PHP_ADMIN_VALUE passés depuis nginx
  • Permissions nginx vhost : root:nginx 640
  • Monitoring des ports FastCGI (scan régulier)
  • Détection de requêtes FastCGI cross-user

Anti-pattern associé

  • KNOW-ANT-019 — PHP-FPM TCP exposed with no access control and sudo NOPASSWD

Références