wpForo Forum <= 2.4.13 - Authenticated (Subscriber+) PHP Object Injection
Description
The wpForo Forum plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 2.4.13 via deserialization of untrusted input in the 'wpforo_display_array_data' function. This makes it possible for authenticated attackers, with Subscriber-level access and above, to inject a PHP Object. No known POP chain is present in the vulnerable software, which means this vulnerability has no impact unless another plugin or theme containing a POP chain is installed on the site. If a POP chain is present via an additional plugin or theme installed on the target system, it may allow the attacker to perform actions like delete arbitrary files, retrieve sensitive data, or execute code depending on the POP chain present.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.4.13What Changed in the Fix
Changes introduced in v2.4.14
Source Code
WordPress.org SVNThis research plan targets a PHP Object Injection vulnerability in **wpForo Forum (<= 2.4.13)**. The vulnerability resides in the `wpforo_display_array_data` function, which performs deserialization on untrusted data from user meta or cookies. ### 1. Vulnerability Summary * **Vulnerability:** PHP…
Show full research plan
This research plan targets a PHP Object Injection vulnerability in wpForo Forum (<= 2.4.13). The vulnerability resides in the wpforo_display_array_data function, which performs deserialization on untrusted data from user meta or cookies.
1. Vulnerability Summary
- Vulnerability: PHP Object Injection
- Sink:
wpforo_display_array_data()(likely usingmaybe_unserialize()orunserialize()internally). - Vulnerable Functionality: This function is a helper used to render array data (User Data, User Meta, Cookies) for display in the admin tools or front-end profile sections (e.g., GDPR data access or debug views).
- Source: User-controlled data stored in WordPress User Meta or sent via HTTP Cookies.
- Constraint: A POP chain is required to achieve Remote Code Execution (RCE) or other high-impact actions.
2. Attack Vector Analysis
- Endpoint: The wpForo front-end profile page or a specific AJAX action that invokes the "Debug" or "Data Display" features.
- HTTP Parameter:
$_COOKIE(specifically cookies prefixed withwpforo_, such aswpforo_read_topics) or metadata updated via the profile. - Authentication: Subscriber-level access is sufficient.
- Target Sink Usage: In
admin/tools-tabs/debug.php, the function is called as:
Whereecho wpforo_display_array_data( $_COOKIE, $keys );$keysincludewpforo_read_topics.
3. Code Flow
- The plugin registers a way for users to view their own data (often via a "Profile" -> "Account" or "Privacy" tab).
- The application invokes a controller that gathers the user's information.
- The controller calls
wpforo_display_array_data($data, $keys). - Inside
wpforo_display_array_data(), the code iterates over the$dataarray. - For each value, it calls
maybe_unserialize($value). - If
$valueis a malicious serialized string provided in a cookie (likewpforo_read_topics), an object is instantiated, triggering its__wakeup()or__destruct()magic methods.
4. Nonce Acquisition Strategy
The vulnerability is primarily triggered via direct page loads or AJAX requests that process cookies.
- Check for Nonce: Determine if the profile/debug view requires a nonce.
- Shortcode: wpForo uses the
[wpforo]shortcode on its main page. - Extraction:
- Navigate to the forum homepage (default
/community/). - Use
browser_evalto find localized data. - Search for
wpforo_varsor similar objects:// Example search window.wpforo_vars?.nonce
- Navigate to the forum homepage (default
- GDPR/Privacy Path: If the trigger is in the Account/Privacy tab, create a page to ensure the UI is loaded:
wp post create --post_type=page --post_status=publish --post_content='[wpforo]'
5. Exploitation Strategy
Step 1: Payload Selection
Since no POP chain is inherent to wpForo, use a generic stdClass for verification or a common WordPress core chain (like Requests_Utility_FilteredIterator if available) to trigger an observable effect (like an error or a request).
- Verification Payload:
O:8:"stdClass":1:{s:3:"poc";s:7:"success";} - Encoding: The payload must be URL-encoded as it will be placed in a cookie.
Step 2: Trigger via Cookie (Recommended)
- Identify the cookie prefix. The
wpforo_prefix()function usually returnswp_orwpforo_. - Set the cookie
wpforo_read_topicsto the serialized payload. - Request the profile "Debug" or "Account Data" view.
Request Template:
GET /community/?wpforo=profile&view=account HTTP/1.1
Host: target.local
Cookie: wpforo_read_topics=O%3A8%3A%22stdClass%22%3A1%3A%7Bs%3A3%3A%22poc%22%3Bs%3A7%3A%22success%22%3B%7D; [WORDPRESS_AUTH_COOKIES]
Step 3: Trigger via User Meta
- Update the user's nickname or another meta field via the profile settings to a serialized string.
- Navigate to the page that displays "User Meta Data" using
wpforo_display_array_data.
6. Test Data Setup
- Install wpForo 2.4.13.
- Create a Subscriber User:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password
- Identify the Forum Page: Find the page containing
[wpforo]. - Enable Debug/Tools (if necessary): Check if
wpforosettings allow members to see their own data logs.
7. Expected Results
- Successful Injection: The
maybe_unserializefunction will process the cookie. If a POP chain is used, the associated action (file deletion, DNS request, etc.) will occur. - Observation: If an invalid object is injected, it may cause a "Catchable fatal error" or "Object of class stdClass could not be converted to string" error if the plugin tries to echo the result of
wpforo_display_array_data.
8. Verification Steps
- Monitor Logs: Check the PHP error log for messages related to
unserialize(). - Verify Deserialization: Use a class that logs its execution to a file or database.
- Trace with WP-CLI:
wp eval "echo maybe_unserialize('O:8:\"stdClass\":1:{s:3:\"poc\";s:7:\"success\";}')->poc;"(to confirm behavior).
9. Alternative Approaches
- AJAX Endpoint: Search for
wp_ajax_wpforo_get_member_dataor similar. If it calls the vulnerable function without proper capability checks, it can be exploited via a POST request toadmin-ajax.php. - Server Info View: If the "Server" view in
debug.phpis accessible to non-admins due to a logic flaw, it might process other inputs (though it primarily uses$_SERVER). - User Data View: Target the
wpfuparameter indebug.php. If a Subscriber can access this tab, they can supply their own ID and trigger the processing of their own (maliciously crafted) meta.
Summary
The wpForo Forum plugin is vulnerable to PHP Object Injection via the wpforo_display_array_data function, which performs deserialization on untrusted input from cookies and user metadata. Authenticated attackers with Subscriber-level access can exploit this by providing a crafted PHP serialized object, which can lead to remote code execution if a suitable POP chain is available on the target system.
Vulnerable Code
// From admin/tools-tabs/debug.php (implementation of wpforo_display_array_data logic around line 195) foreach( $array as $k => $v ) { if( ( ! empty( $keys ) && ! in_array( $k, $keys ) && strpos( (string) $k, 'capabilities' ) === false ) || $k == 'user_pass' ) continue; if( is_serialized( $v ) || is_array( $v ) ) { $v = ( is_array( $v ) ) ? $v : @unserialize( $v ); $v_html = ''; if( is_array( $v ) && ! empty( $v ) ) { foreach( $v as $kk => $vv ) { if( is_serialized( $vv ) || is_array( $vv ) ) { $v_html = ''; $vv = ( is_array( $vv ) ) ? $vv : unserialize( $vv );
Security Fix
@@ -195,13 +195,13 @@ foreach( $array as $k => $v ) { if( ( ! empty( $keys ) && ! in_array( $k, $keys ) && strpos( (string) $k, 'capabilities' ) === false ) || $k == 'user_pass' ) continue; if( is_serialized( $v ) || is_array( $v ) ) { - $v = ( is_array( $v ) ) ? $v : @unserialize( $v ); + $v = ( is_array( $v ) ) ? $v : @unserialize( $v, [ 'allowed_classes' => false ] ); $v_html = ''; if( is_array( $v ) && ! empty( $v ) ) { foreach( $v as $kk => $vv ) { if( is_serialized( $vv ) || is_array( $vv ) ) { $v_html = ''; - $vv = ( is_array( $vv ) ) ? $vv : unserialize( $vv ); + $vv = ( is_array( $vv ) ) ? $vv : unserialize( $vv, [ 'allowed_classes' => false ] ); if( $k === wpforo_prefix( 'read_topics' ) ) { $v_html .= "<span class='wpf-sb-data'>" . count( $vv ) . "</span> "; } else {
Exploit Outline
The exploit targets the wpForo front-end profile or debug functionality that displays user-controlled data. 1. Authentication: The attacker authenticates as a Subscriber-level user. 2. Payload Preparation: The attacker crafts a PHP serialized object payload designed to leverage an existing POP chain (from other installed plugins/themes). 3. Injection Vector: The attacker sets a cookie containing the serialized payload, specifically targeting keys known to be processed by wpforo_display_array_data, such as 'wpforo_read_topics' (often prefixed based on site settings). Alternatively, user metadata fields can be updated via the profile settings with serialized data. 4. Execution Trigger: The attacker navigates to the 'Account' or 'Privacy' tab within their wpForo profile (e.g., `/?wpforo=profile&view=account`). When this page loads, the plugin calls wpforo_display_array_data on the malicious cookie or metadata, triggering unserialize() and the subsequent execution of the object's magic methods.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.