Skip to content

Commit c6422cf

Browse files
committed
Fixed vulnerabilities reported by João Victor #339
1 parent af1f29c commit c6422cf

File tree

3 files changed

+88
-30
lines changed

3 files changed

+88
-30
lines changed

save.php

+65-18
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,29 @@
1818
*/
1919

2020
define('MAX_FILE_LIMIT', 1024 * 1024 * 2);//2 Megabytes max html file size
21+
define('ALLOW_PHP', false);//check if saved html contains php tag and don't save if not allowed
22+
define('ALLOWED_OEMBED_DOMAINS', [
23+
'https://www.youtube.com/',
24+
'https://www.vimeo.com/',
25+
'https://www.twitter.com/'
26+
]);//load urls only from allowed websites for oembed
2127

2228
function sanitizeFileName($file, $allowedExtension = 'html') {
29+
$basename = basename($file);
30+
$disallow = ['.htaccess', 'passwd'];
31+
if (in_array($basename, $disallow)) {
32+
showError('Filename not allowed!');
33+
return '';
34+
}
35+
2336
//sanitize, remove double dot .. and remove get parameters if any
24-
$file = __DIR__ . '/' . preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file)));
37+
$file = preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file)));
38+
39+
if ($file) {
40+
$file = __DIR__ . DIRECTORY_SEPARATOR . $file;
41+
} else {
42+
return '';
43+
}
2544

2645
//allow only .html extension
2746
if ($allowedExtension) {
@@ -35,19 +54,38 @@ function showError($error) {
3554
die($error);
3655
}
3756

57+
function validOembedUrl($url) {
58+
foreach (ALLOWED_OEMBED_DOMAINS as $domain) {
59+
if (strpos($url, $domain) === 0) {
60+
return true;
61+
}
62+
}
63+
64+
return false;
65+
}
66+
3867
$html = '';
3968
$file = '';
4069
$action = '';
4170

4271
if (isset($_POST['startTemplateUrl']) && !empty($_POST['startTemplateUrl'])) {
4372
$startTemplateUrl = sanitizeFileName($_POST['startTemplateUrl']);
44-
$html = file_get_contents($startTemplateUrl);
73+
$html = '';
74+
if ($startTemplateUrl) {
75+
$html = file_get_contents($startTemplateUrl);
76+
}
4577
} else if (isset($_POST['html'])){
4678
$html = substr($_POST['html'], 0, MAX_FILE_LIMIT);
79+
if (!ALLOW_PHP) {
80+
//if (strpos($html, '<?php') !== false) {
81+
if (preg_match('@<\?php|<\? |<\?=|<\s*script\s*language\s*=\s*"\s*php\s*"\s*>@', $html)) {
82+
showError('PHP not allowed!');
83+
}
84+
}
4785
}
4886

4987
if (isset($_POST['file'])) {
50-
$file = sanitizeFileName($_POST['file'], false);
88+
$file = sanitizeFileName($_POST['file']);
5189
}
5290

5391
if (isset($_GET['action'])) {
@@ -58,7 +96,7 @@ function showError($error) {
5896
//file manager actions, delete and rename
5997
switch ($action) {
6098
case 'rename':
61-
$newfile = sanitizeFileName($_POST['newfile'], false);
99+
$newfile = sanitizeFileName($_POST['newfile']);
62100
if ($file && $newfile) {
63101
if (rename($file, $newfile)) {
64102
echo "File '$file' renamed to '$newfile'";
@@ -85,28 +123,37 @@ function showError($error) {
85123
if ($type && $name && $html) {
86124

87125
$file = sanitizeFileName("$type/$name");
88-
$dir = dirname($file);
89-
if (!is_dir($dir)) {
90-
echo "$dir folder does not exist\n";
91-
if (mkdir($dir, 0777, true)) {
92-
echo "$dir folder was created\n";
126+
if ($file) {
127+
$dir = dirname($file);
128+
if (!is_dir($dir)) {
129+
echo "$dir folder does not exist\n";
130+
if (mkdir($dir, 0777, true)) {
131+
echo "$dir folder was created\n";
132+
} else {
133+
showError("Error creating folder '$dir'\n");
134+
}
135+
}
136+
137+
if (file_put_contents($file, $html)) {
138+
echo "File saved '$file'";
93139
} else {
94-
showError("Error creating folder '$dir'\n");
95-
}
96-
}
97-
98-
if (file_put_contents($file, $html)) {
99-
echo "File saved '$file'";
140+
showError("Error saving file '$file'\nPossible causes are missing write permission or incorrect file path!");
141+
}
100142
} else {
101-
showError("Error saving file '$file'\nPossible causes are missing write permission or incorrect file path!");
143+
showError('Invalid filename!');
102144
}
103145
} else {
104146
showError("Missing reusable element data!\n");
105147
}
106148
break;
107149
case 'oembedProxy':
108-
header('Content-Type: application/json');
109-
echo file_get_contents($_GET['url']);
150+
$url = $_GET['url'] ?? '';
151+
if (validOembedUrl($url)) {
152+
header('Content-Type: application/json');
153+
echo file_get_contents($url);
154+
} else {
155+
showError('Invalid url!');
156+
}
110157
break;
111158
default:
112159
showError("Invalid action '$action'!");

scan.php

+9-3
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@
1919

2020
//scan media folder for all files to display in media modal
2121

22-
if (isset($_POST['mediaPath'])) {
23-
define('UPLOAD_PATH', $_POST['mediaPath']);
22+
function sanitizePath($path) {
23+
//sanitize, remove double dot .. and remove get parameters if any
24+
$path = preg_replace('@/+@' , DIRECTORY_SEPARATOR, preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $path))));
25+
return $path;
26+
}
27+
28+
if (isset($_POST['mediaPath']) && ($path = sanitizePath(substr($_POST['mediaPath'], 0, 256)))) {
29+
define('UPLOAD_PATH', $path);
2430
} else {
2531
define('UPLOAD_PATH', 'media');
2632
}
2733

28-
$scandir = __DIR__ . '/' . UPLOAD_PATH;
34+
$scandir = __DIR__ . DIRECTORY_SEPARATOR. UPLOAD_PATH;
2935

3036
// Run the recursive function
3137
// This function scans the files folder recursively, and builds a large array

upload.php

+14-9
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*/
2323

2424
$uploadDenyExtensions = ['php'];
25-
$uploadAllowExtensions = ['ico','jpg','jpeg','png','gif','webp'];
25+
$uploadAllowExtensions = ['ico','jpg','jpeg','png','gif','webp','svg'];
2626

2727
function showError($error) {
2828
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
@@ -31,36 +31,41 @@ function showError($error) {
3131

3232
function sanitizeFileName($file)
3333
{
34+
$disallow = ['.htaccess', 'passwd'];
35+
$file = str_replace($disallow, '', $file);
36+
3437
//sanitize, remove double dot .. and remove get parameters if any
3538
$file = preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file)));
39+
3640
return $file;
3741
}
3842

39-
40-
define('UPLOAD_FOLDER', __DIR__ . '/');
43+
define('UPLOAD_FOLDER', __DIR__ . DIRECTORY_SEPARATOR);
4144
if (isset($_POST['mediaPath'])) {
42-
define('UPLOAD_PATH', sanitizeFileName($_POST['mediaPath']) .'/');
45+
define('UPLOAD_PATH', sanitizeFileName($_POST['mediaPath']) . DIRECTORY_SEPARATOR);
4346
} else {
44-
define('UPLOAD_PATH', '/');
47+
define('UPLOAD_PATH', DIRECTORY_SEPARATOR);
48+
}
49+
50+
$fileName = sanitizeFileName($_FILES['file']['name']);
51+
if (!$fileName) {
52+
showError('Invalid filename!');
4553
}
4654

47-
$fileName = $_FILES['file']['name'];
4855
$extension = strtolower(substr($fileName, strrpos($fileName, '.') + 1));
4956

5057
//check if extension is on deny list
5158
if (in_array($extension, $uploadDenyExtensions)) {
5259
showError("File type $extension not allowed!");
5360
}
5461

55-
/*
5662
//comment deny code above and uncomment this code to change to a more restrictive allowed list
5763
// check if extension is on allow list
5864
if (!in_array($extension, $uploadAllowExtensions)) {
5965
showError("File type $extension not allowed!");
6066
}
61-
*/
6267

63-
$destination = UPLOAD_FOLDER . UPLOAD_PATH . '/' . $fileName;
68+
$destination = UPLOAD_FOLDER . UPLOAD_PATH . DIRECTORY_SEPARATOR . $fileName;
6469
move_uploaded_file($_FILES['file']['tmp_name'], $destination);
6570

6671
if (isset($_POST['onlyFilename'])) {

0 commit comments

Comments
 (0)