Authenticated RCE in JetElements For Elementor Plugin

Published 3 August 2023
Rafie Muhammad
Security Researcher at Patchstack
Table of Contents

This blog post is about the JetElements For Elementor plugin vulnerability. If you're a JetElements For Elementor user, please update the plugin to at least version 2.6.11.

Patchstack Developer and Business users are protected from the vulnerability. You can also sign up for the Patchstack Community plan to be notified about vulnerabilities as soon as they become disclosed.

For plugin developers, we have security audit services and Threat Intelligence Feed API for hosting companies.

About the JetElements For Elementor Plugin

The plugin JetElements For Elementor (versions 2.6.10 and below, premium version), which is estimated to have around 300,000 active installation, is suffering from an authenticated RCE vulnerability. The JetElements For Elementor plugin is known as the more popular Elementor addon premium plugin in WordPress. This plugin is developed by Crocoblock.

This plugin is a premium Elementor addon plugin that helps to add and customize any content on the website. This plugin contains 40+ widgets to create designs, as well as static and dynamic content elements. Most of the widgets support dynamic fields from JetEngine.

The security vulnerability

The JetElements For Elementor plugin suffers from an authenticated Remote Code Execution where user with a minimum role of Contributor able to execute arbitrary PHP function to achieve code execution. The described vulnerability was fixed in version 2.6.11 and assigned CVE-2023-39157.

The underlying vulnerability exist in the render_meta function:

public function render_meta( $position = '', $base = '', $context = array( 'before' ) ) {

    $config_key    = $position . '_meta';
    $show_key      = 'show_' . $position . '_meta';
    $position_key  = 'meta_' . $position . '_position';
    $meta_show     = $this->get_attr( $show_key );
    $meta_position = $this->get_attr( $position_key );
    $meta_config   = $this->get_attr( $config_key );

    if ( 'yes' !== $meta_show ) {
        return;
    }

    if ( ! $meta_position || ! in_array( $meta_position, $context ) ) {
        return;
    }

    if ( empty( $meta_config ) ) {
        return;
    }

    $result = '';

    foreach ( $meta_config as $meta ) {

        if ( empty( $meta['meta_key'] ) ) {
            continue;
        }

        $key      = $meta['meta_key'];
        $callback = ! empty( $meta['meta_callback'] ) ? $meta['meta_callback'] : false;
        $value    = get_post_meta( get_the_ID(), $key, false );

        if ( ! $value ) {
            continue;
        }

        $callback_args = array( $value[0] );

------------------------- CUT HERE -------------------------

        if ( ! empty( $callback ) && is_callable( $callback ) ) {
            $meta_val = call_user_func_array( $callback, $callback_args );
        } else {
            $meta_val = $value[0];
        }
------------------------- CUT HERE -------------------------

Note that there is a call for PHP built-in function call_user_func_array with supplied input parameters $callback and $callback_args. Basically, the function will call any function we supply in the $callback parameter and will pass the $callback_args as the arguments of the called function.

The render_meta function itself could be called in the posts widget if user decide to "Show Meta" on the "Custom Fields" of the posts widget setting:

In the "Show Meta" feature, we could specify meta key, label and a callback function that will be used to prepare the meta. As we can see, there are multiple default options such as get_permalink and get_the_title function.

If you have familiarized yourself with Elementor data structure, all of the particle and element data of a post or page will be stored in the post meta with _elementor_data as the meta key. This _elementor_data will also contain the "Label" value that we specified on the "Show Meta" feature.

Back to the initial render_meta function, note that the $callback parameter is coming from $meta['meta_callback'] which a user can fully control, since there is no check being applied on which callback the user could use. For the $callback_args parameter, it's coming from the $value variable that is originally constructed from get_post_meta( get_the_ID(), $key, false ). Since $key in this case is fetched from $meta['meta_key'] which we can also fully control, we can specify any post meta key in which we can partially or fully control to achieve RCE.

Summarizing all of the details, we can simply supply the callback function with PHP system or shell_exec function, set the meta key to _elementor_data and finally put our injected OS command in the "Label" of the "Show Meta" feature. In order to activate the RCE, the drafted post need to be published by privileged user. The RCE will then be triggered each time the post is visited.

The patch

For fixing the issue, simply use a whitelist check on the callback function that can be used should be enough to patch the vulnerability. The vendor decided to create a wrapper function allowed_meta_callbacks that returns a list of allowed functions and only allows callback functions that are in the allowed list. The patch can be seen below:

Conclusion

In some cases, a theme or plugin needs to have a feature for the user to be able to call a custom or chosen function to execute. Doing so, a built-in PHP function can be used to achieve this with functions such as call_user_func or call_user_func_array. Keep in mind to always restrict the callback function that can be used and additionally also check the arguments that will be passed. We recommend using a whitelist check instead of blacklist check to prevent more cases of arbitrary function execution.

Timeline

03 July, 2023We found the vulnerability and reached out to the plugin vendor.
05 July, 2023JetElements For Elementor version 2.6.11 released to patch the reported issues.
03 August, 2023Added the vulnerabilities to the Patchstack vulnerability database and Security advisory article publicly released.

Help us make the Internet a safer place

Making the WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.

  • If you're a plugin developer, join our mVDP program that makes it easier to report, manage and address vulnerabilities in your software.
  • If you're a security researcher, join Patchstack Alliance to report vulnerabilities & earn rewards.

The latest in Security Advisories

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.
crossmenu