Paid Membership Subscriptions – Effortless Memberships, Recurring Payments & Content Restriction <= 3.0.4 - Unauthenticated Server-Side Request Forgery
Description
The Paid Membership Subscriptions – Effortless Memberships, Recurring Payments & Content Restriction plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 3.0.4. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations originating from the web application which can be used to query and modify information from internal services.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NTechnical Details
<=3.0.4What Changed in the Fix
Changes introduced in v3.0.5
Source Code
WordPress.org SVNThis research plan focuses on identifying and exploiting an unauthenticated Server-Side Request Forgery (SSRF) in the **Paid Membership Subscriptions** plugin. ### 1. Vulnerability Summary * **Vulnerability:** Unauthenticated SSRF. * **Location:** Likely within the payment gateway callback or I…
Show full research plan
This research plan focuses on identifying and exploiting an unauthenticated Server-Side Request Forgery (SSRF) in the Paid Membership Subscriptions plugin.
1. Vulnerability Summary
- Vulnerability: Unauthenticated SSRF.
- Location: Likely within the payment gateway callback or IPN (Instant Payment Notification) handling logic, which is typically hooked to
initorwp_loadedto listen for external requests from payment providers (like PayPal). - Cause: The plugin accepts a URL or a target identifier from a user-controlled parameter (via
$_GETor$_POST) and passes it to a sink likewp_remote_get()orwp_remote_post()without validating that the host is an authorized external service. - Impact: Attackers can force the web server to make requests to internal services (e.g.,
http://localhost:6379for Redis,http://169.254.169.254for AWS metadata) or conduct port scanning of the internal network.
2. Attack Vector Analysis
- Endpoint: The vulnerability is reachable via the main WordPress index (
/) orwp-admin/admin-ajax.php, depending on how the handler is registered. - Action Trigger: Based on
assets/js/front-end.js, the plugin monitors parameters such aspms_gateway_payment_actionandpms_gateway_payment_id. - Vulnerable Parameter: Likely a parameter such as
ipn_url,webhook_url, or a specific action that triggers a remote request (e.g.,pms_gateway_payment_action=verify_remote). - Authentication: Unauthenticated (AV:N/PR:N).
3. Code Flow (Inferred from Patterns)
- Entry Point: The plugin registers a handler on the
inithook (as seen in the pattern inincludes/admin/class-admin-members.php). - Request Capture: The handler checks
$_REQUEST['pms_gateway_payment_action']. - URL Extraction: If the action matches a specific payment gateway (e.g.,
paypal_standardorpaypal_express), the code extracts a URL or constructs one based on input. - The Sink: The extracted URL is passed to
wp_remote_get()orwp_remote_request()to "verify" the transaction with the provider. - Missing Check: The code fails to use
wp_safe_remote_get()or lacks a whitelist check against the provided URL.
4. Nonce Acquisition Strategy
Payment IPN and callback handlers usually do not require nonces because they are designed to receive asynchronous notifications from external servers. If a nonce is required for a front-end AJAX action:
- Identify Shortcode: The plugin uses
[pms-register]or[pms-payment-form]. - Create Page:
wp post create --post_type=page --post_title="Register" --post_status=publish --post_content='[pms-register]' - Navigate & Extract: Use
browser_navigateto the new page. - Extract JS Variable: The plugin likely localizes data. Based on common PMS patterns, check for
pms_varsorpms_front_end_js.// Use browser_eval window.pms_vars?.nonce || window.pms_front_end_js?.nonce
5. Exploitation Strategy
The goal is to force the server to request an internal resource.
- Step 1: Locate the Sink.
Usegrepin the environment to find wherepms_gateway_payment_actionis handled and if it leads to an HTTP request.grep -rn "pms_gateway_payment_action" . grep -rn "wp_remote_get\|wp_remote_post" . - Step 2: Craft the SSRF Payload.
Assume the vulnerable action ispaypal_ipn_verifyand it accepts averify_urlparameter (inferred names). - Step 3: Execution via
http_request.
Note: If triggered via{ "method": "POST", "url": "http://localhost/wp-admin/admin-ajax.php", "headers": { "Content-Type": "application/x-www-form-urlencoded" }, "params": { "action": "pms_paypal_ipn_verify", "verify_url": "http://169.254.169.254/latest/meta-data/" } }init, send the request to the homepage (/) with the parameters.
6. Test Data Setup
- Activate Plugin: Ensure
paid-member-subscriptionsis active. - Configure Gateway: Enable "PayPal Standard" or "PayPal Express" in membership settings to ensure the vulnerable code paths are initialized.
wp option update pms_payments_settings '{"active_gateways":["paypal_standard"]}' --format=json - External Listener: Use a tool like Webhook.site or a local netcat listener to confirm the outgoing request if testing "Blind SSRF".
7. Expected Results
- Successful SSRF: The server response might include the content of the internal resource (if it's a "Partial SSRF" that returns body content) OR the attacker's listener receives a request from the WordPress server's IP address.
- Response Indicators: Look for internal service banners (e.g., "Redis", "HTTP/1.1 200 OK" from an internal management interface).
8. Verification Steps
- Access Logs: Check the server access logs or use a collaborator to confirm the request originated from the WP server.
- Internal Probe: Attempt to hit
http://localhost:80and check if the response contains the WordPress site's own HTML, confirming it can reach its own loopback.
9. Alternative Approaches
- Shortcode Vector: Check if any shortcodes (like
[pms-restrict]) take aurlparameter for "Remote Content" restriction. - File Inclusion Check: If the sink is
file_get_contents(), attempt to use thefile://wrapper to read/etc/passwd. - Protocol Smuggling: If
curlis used, try other protocols likegopher://to interact with internal services like Memcached or Redis.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.