Authenticated RCE Patched in Rank Math SEO plugin

Published 28 November 2024
Table of Contents

Rank Math SEO plugin

.htaccess File Overwrite

3+ million
CVSS 7.2

This blog post is about an arbitrary .htaccess file overwrite vulnerability on the Rank Matho SEO plugin. If you’re a Rank Math SEO plugin user, please update the plugin to the latest version or at least to the version 1.0.232.

All paid Patchstack users are protected from this vulnerability. Sign up for the free Community account first, to scan for vulnerabilities and apply protection for only $5 / site per month with Patchstack. For plugin developers, we have security audit services and Enterprise API for hosting companies.

About Rank Math SEO plugin

The Rank Math SEO plugin, which has over 3 million active installations, is one of the most popular SEO plugins for managing the SEO of the WordPress site. It offers users with an easy way to setup and customize SEO.

The security vulnerability

In the version 1.0.231 and below, the plugin is vulnerable to an .htaccess overwrite vulnerability that can lead to remote code execution. The users with custom privileges like Titles & Meta Settings or General Settings capabilities can exploit this issue. By default, only administrators are provided with that privilege however, the custom privileges mentioned can be provided to users like Editor or Author. While this issue requires high/custom privilege to exploit, we decided to write a blog post due to the interesting nature of the vulnerability along with the high installation of the plugin. The vulnerability was patched in the version 1.0.232 and is tracked as the CVE-2024-11620.

Rank Math SEO: Arbitrary .hatccess Overwrite to RCE

The entrypoint for the vulnerability is the admin_post_ hook that calls the save_options() function. Calling this function only requires a valid nonce value that can be accessed through the General Settings page of the plugin for the users having enough privileges.

add_action( 'admin_post_' . $this->option_key, array( $this, 'save_options' ) );


public function save_options() {
	$url = wp_get_referer();
	if ( ! $url ) {
		$url = admin_url();
	}

	if (
		$this->can_save( 'options-page' )
		// check params.
		&& isset( $_POST['submit-cmb'], $_POST['action'] )
		&& $this->option_key === $_POST['action']
	) {

		$updated = $this->cmb
			->save_fields( $this->option_key, $this->cmb->object_type(), $_POST )
			->was_updated(); // Will be false if no values were changed/updated.

		$url = add_query_arg( 'settings-updated', $updated ? 'true' : 'false', $url );
	}

	wp_safe_redirect( esc_url_raw( $url ), 303 /* WP_Http::SEE_OTHER */ );
	exit;
}

After going through various function and action calls from the above source, the ultimate underlying vulnerable code gets executed that lies in the update_htaccess function:

private function update_htaccess() {
	if ( empty( Param::post( 'htaccess_accept_changes' ) ) ) {
		return;
	}

	// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Writing to .htaccess file and escaping for HTML will break functionality.
	$content = wp_unslash( $_POST['htaccess_content'] );
	if ( empty( $content ) ) {
		return;
	}

	if ( ! $this->do_htaccess_backup() ) {
		Helper::add_notification(
			esc_html__( 'Failed to backup .htaccess file. Please check file permissions.', 'rank-math' ),
			[ 'type' => 'error' ]
		);
		return;
	}
	if ( ! $this->do_htaccess_update( $content ) ) {
		Helper::add_notification(
			esc_html__( 'Failed to update .htaccess file. Please check file permissions.', 'rank-math' ),
			[ 'type' => 'error' ]
		);
		return;
	}

	Helper::add_notification( esc_html__( '.htaccess file updated successfully.', 'rank-math' ) );
}

If the request has the POST parameters called htaccess_accept_changes and htaccess_content, it goes to the do_htaccess_backup()function and creates a backup of the currently existing htaccess and then calls do_htaccess_update() function in order to actually update the content of the htaccess. It can be seen that there is no additional permission checks for executing this function.

To exploit this vulnerability, a .htaccess file with the below content would be enough. It makes all the files with a jpg extensions PHP executables. If the attacker uploads a .jpg file with malicious PHP code, the server will execute the PHP code in the jpg file that will lead to RCE.

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

<FilesMatch "\.jpg">
    SetHandler application/x-httpd-php
</FilesMatch>

</IfModule>

This techique has been discussed in the Patchstack Academy as well. Do check it out for more interesting cases and techniques for WordPress hacking.

The patch

The vulnerability was patched in the version 1.0.232. The vendor patched the issue by adding a proper permission check. In the patched version and onwards, the user now has to be a super-admin in a multisite instance, and has to have a ‘general‘ and ‘edit_htaccess‘ capability to update the .htaccess file. Even if all the above conditions are fulfilled, there is a check that only allows updating the file if it has not been disallowed in the config through the Helper::is_edit_allowed() function as seen in this changeset.

Conclusion

Whilst this vulnerability is not critical due to the high privilege required and has a low chance of being exploited in the wild, it still serves as an example of potential threats that are involved when a plugin has the ability to modify system files. It is crucial for the plugin/theme developers to beware of the threats that might be introduced when modifying the system files and strictly apply proper privilege check before allowing such actions to be made.

Want to learn more about finding and fixing vulnerabilities?

Explore our Academy to master the art of finding and patching vulnerabilities within the WordPress ecosystem. Dive deep into detailed guides on various vulnerability types, from discovery tactics for researchers to robust fixes for developers. Join us and contribute to our growing knowledge base.

Timeline

5 November, 2024We found the vulnerability and created a report.
7 November, 2024We reached out to the vendor regarding the vulnerabilities.
13 November, 2024The vendor patched the vulnerability and released the version 1.0.232.
22 November, 2024We published the vulnerability to the Patchstack Vulnerability Database.
28 November, 2024Security advisory article publicly released.

Help us make the Internet a safer place

Making the WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.

  • If you’re a plugin developer, join our mVDP program that makes it easier to report, manage and address vulnerabilities in your software.
  • If you’re a security researcher, join Patchstack Alliance to report vulnerabilities & earn rewards.

The latest in Security advisories

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.
crossmenu