Skip to content

Commit 3ddd833

Browse files
committed
fix(attach): authenticated arbitrary file deletion
1 parent 9edbd9a commit 3ddd833

File tree

1 file changed

+54
-52
lines changed

1 file changed

+54
-52
lines changed

tools/attach/libs/attach.lib.php

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,27 @@
1414
if (!class_exists('attach')) {
1515
class attach
1616
{
17-
public $wiki = ''; //objet wiki courant
18-
public $attachConfig = []; //configuration de l'action
19-
public $file = ''; //nom du fichier
17+
public $wiki = ''; // objet wiki courant
18+
public $attachConfig = []; // configuration de l'action
19+
public $file = ''; // nom du fichier
2020
public $height;
2121
public $width;
22-
public $desc = ''; //description du fichier
23-
public $link = ''; //url de lien (image sensible)
24-
public $caption = ''; //texte de la vignette au survol
25-
public $legend = ''; //texte en dessous de l'image
26-
public $nofullimagelink = ''; //mettre un lien vers l'image entiere
27-
public $isPicture = 0; //indique si c'est une image
28-
public $isAudio = 0; //indique si c'est un fichier audio
29-
public $isFreeMindMindMap = 0; //indique si c'est un fichier mindmap freemind
30-
public $isWma = 0; //indique si c'est un fichier wma
31-
public $isPDF = 0; //indique si c'est un fichier pdf
32-
public $displayPDF = 0; //indique s'il faut afficher le fichier pdf
33-
public $classes = 'attached_file'; //classe pour afficher une image
34-
public $attachErr = ''; //message d'erreur
35-
public $pageId = 0; //identifiant de la page
36-
public $isSafeMode = true; //indicateur du safe mode de PHP
37-
public $data = ''; //indicateur du safe mode de PHP
22+
public $desc = ''; // description du fichier
23+
public $link = ''; // url de lien (image sensible)
24+
public $caption = ''; // texte de la vignette au survol
25+
public $legend = ''; // texte en dessous de l'image
26+
public $nofullimagelink = ''; // mettre un lien vers l'image entiere
27+
public $isPicture = 0; // indique si c'est une image
28+
public $isAudio = 0; // indique si c'est un fichier audio
29+
public $isFreeMindMindMap = 0; // indique si c'est un fichier mindmap freemind
30+
public $isWma = 0; // indique si c'est un fichier wma
31+
public $isPDF = 0; // indique si c'est un fichier pdf
32+
public $displayPDF = 0; // indique s'il faut afficher le fichier pdf
33+
public $classes = 'attached_file'; // classe pour afficher une image
34+
public $attachErr = ''; // message d'erreur
35+
public $pageId = 0; // identifiant de la page
36+
public $isSafeMode = true; // indicateur du safe mode de PHP
37+
public $data = ''; // indicateur du safe mode de PHP
3838
private $params;
3939

4040
/**
@@ -185,7 +185,7 @@ public function GetFullFilename($newName = false)
185185
)
186186
);
187187

188-
//decompose le nom du fichier en nom+extension ou en page/nom+extension
188+
// decompose le nom du fichier en nom+extension ou en page/nom+extension
189189
if (preg_match('`^((.+)/)?(.*)\.(.*)$`', str_replace(' ', '_', $this->file), $match)) {
190190
list(, , $file['page'], $file['name'], $file['ext']) = $match;
191191
if (!$this->isPicture() && !$this->isAudio() && !$this->isVideo() && !$this->isFreeMindMindMap() && !$this->isWma() && !$this->isFlashvideo()) {
@@ -194,10 +194,10 @@ public function GetFullFilename($newName = false)
194194
} else {
195195
return false;
196196
}
197-
//recuperation du chemin d'upload
197+
// recuperation du chemin d'upload
198198
$path = $this->GetUploadPath($this->isSafeMode);
199199
$page_tag = $file['page'] ? $file['page'] : $this->wiki->GetPageTag();
200-
//generation du nom ou recherche de fichier ?
200+
// generation du nom ou recherche de fichier ?
201201
if ($newName) {
202202
$full_file_name = $file['name'] . '_' . $pagedate . '_' . $this->getDate() . '.' . $file['ext'];
203203
if ($this->isSafeMode) {
@@ -207,12 +207,12 @@ public function GetFullFilename($newName = false)
207207
}
208208
} else {
209209
$isActionBuilderPreview = $this->wiki->GetPageTag() == 'root';
210-
//recherche du fichier
210+
// recherche du fichier
211211
if ($isActionBuilderPreview) {
212212
// bazar action builder, preview action
213213
$searchPattern = '`' . $file['name'] . '_\d{14}_\d{14}\.' . $file['ext'] . '$`';
214214
} elseif ($this->isSafeMode) {
215-
//TODO Recherche dans le cas ou safe_mode=on
215+
// TODO Recherche dans le cas ou safe_mode=on
216216
$searchPattern = '`^' . $page_tag . '_' . $file['name'] . '_\d{14}_\d{14}\.' . $file['ext'] . '$`';
217217
} else {
218218
$searchPattern = '`^' . $file['name'] . '_\d{14}_\d{14}\.' . $file['ext'] . '$`';
@@ -330,7 +330,7 @@ public function parseDate($sDate)
330330
$pattern = '`^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$`';
331331
$res = '';
332332
if (preg_match($pattern, $sDate, $m)) {
333-
//list(,$res['year'],$res['month'],$res['day'],$res['hour'],$res['min'],$res['sec'])=$m;
333+
// list(,$res['year'],$res['month'],$res['day'],$res['hour'],$res['min'],$res['sec'])=$m;
334334
$res = $m[1] . '-' . $m[2] . '-' . $m[3] . ' ' . $m[4] . ':' . $m[5] . ':' . $m[6];
335335
}
336336

@@ -362,17 +362,17 @@ public function decodeLongFilename($filename)
362362
$afile['path'] = dirname($filename);
363363
if (preg_match('`^(.*)_(\d{14})_(\d{14})\.(.*)(trash\d{14})?$`', $afile['realname'], $m)) {
364364
$afile['name'] = $m[1];
365-
//suppression du nom de la page si safe_mode=on
365+
// suppression du nom de la page si safe_mode=on
366366
if ($this->isSafeMode) {
367367
$afile['name'] = preg_replace('`^(' . $this->wiki->tag . ')_(.*)$`i', '$2', $afile['name']);
368368
}
369369
$afile['datepage'] = $m[2];
370370
$afile['dateupload'] = $m[3];
371371
$afile['trashdate'] = preg_replace('`(.*)trash(\d{14})`', '$2', $m[4]);
372-
//suppression de trashxxxxxxxxxxxxxx eventuel
372+
// suppression de trashxxxxxxxxxxxxxx eventuel
373373
$afile['ext'] = preg_replace('`^(.*)(trash\d{14})$`', '$1', $m[4]);
374374
$afile['ext'] = rtrim($afile['ext'], '_');
375-
//$afile['ext'] = rtrim($m[4],'_');
375+
// $afile['ext'] = rtrim($m[4],'_');
376376
}
377377

378378
return $afile;
@@ -408,7 +408,7 @@ public function searchFiles($filepattern, $start_dir)
408408
*/
409409
public function CheckParams()
410410
{
411-
//recuperation des parametres necessaire
411+
// recuperation des parametres necessaire
412412
$this->file = $this->wiki->GetParameter('attachfile');
413413
if (empty($this->file)) {
414414
$this->file = $this->wiki->GetParameter('file');
@@ -420,20 +420,20 @@ public function CheckParams()
420420
}
421421
$this->desc = htmlentities(strip_tags($this->desc)); // avoid XSS
422422

423-
$this->link = $this->wiki->GetParameter('attachlink'); //url de lien - uniquement si c'est une image
423+
$this->link = $this->wiki->GetParameter('attachlink'); // url de lien - uniquement si c'est une image
424424
if (empty($this->link)) {
425425
$this->link = $this->wiki->GetParameter('link');
426426
}
427427

428-
$this->caption = $this->wiki->GetParameter('caption'); //texte de la vignette (au survol)
429-
$this->legend = $this->wiki->GetParameter('legend'); //texte de la vignette (en dessous)
428+
$this->caption = $this->wiki->GetParameter('caption'); // texte de la vignette (au survol)
429+
$this->legend = $this->wiki->GetParameter('legend'); // texte de la vignette (en dessous)
430430
$this->nofullimagelink = $this->wiki->GetParameter('nofullimagelink');
431431
$this->height = $this->wiki->GetParameter('height');
432432
$this->width = $this->wiki->GetParameter('width');
433433
$this->displayPDF = $this->wiki->GetParameter('displaypdf');
434-
$this->data = $this->wiki->services->get(\YesWiki\Templates\Service\Utils::class)->getDataParameter();
434+
$this->data = $this->wiki->services->get(YesWiki\Templates\Service\Utils::class)->getDataParameter();
435435

436-
//test de validité des parametres
436+
// test de validité des parametres
437437
if (empty($this->file)) {
438438
$this->attachErr = '<div class="alert alert-danger"><strong>' . _t('ATTACH_ACTION_ATTACH') . '</strong> : ' . _t('ATTACH_PARAM_FILE_NOT_FOUND') . '.</div>' . "\n";
439439
}
@@ -510,10 +510,10 @@ public function showAsImage($fullFilename)
510510
$height = $height - 20;
511511
}
512512

513-
//c'est une image : balise <IMG..../>
513+
// c'est une image : balise <IMG..../>
514514
$img = '<img loading="lazy" class="img-responsive" src="' . $this->GetScriptPath() . $img_name . '" ' .
515515
'alt="' . $this->desc . ($this->link ? "\nLien vers: $this->link" : '') . '" width="' . $width . '" height="' . $height . '" />';
516-
//test si c'est une image sensible
516+
// test si c'est une image sensible
517517
$classDataForLinks =
518518
strstr($this->classes, 'new-window')
519519
? ' class="new-window"'
@@ -553,7 +553,7 @@ public function showAsImage($fullFilename)
553553
$output = ($notAligned ? '<div>' : '') . (isset($link) ? $link : '') . "<figure class=\"$this->classes\" $data>$img$caption$legend</figure>" . (isset($link) ? '</a>' : '') . ($notAligned ? '</div>' : '');
554554

555555
echo $output;
556-
//$this->showUpdateLink();
556+
// $this->showUpdateLink();
557557
}
558558

559559
/**
@@ -674,13 +674,13 @@ public function doAttach()
674674
return;
675675
}
676676
$fullFilename = $this->GetFullFilename();
677-
//test d'existance du fichier
677+
// test d'existance du fichier
678678
if ((!file_exists($fullFilename)) || ($fullFilename == '')) {
679679
$this->showFileNotExits();
680680

681681
return;
682682
}
683-
//le fichier existe : affichage en fonction du type
683+
// le fichier existe : affichage en fonction du type
684684
if ($this->isPicture()) {
685685
$this->showAsImage($fullFilename);
686686
} elseif ($this->isVideo() || $this->isFlashvideo()) {
@@ -751,8 +751,8 @@ public function performUpload()
751751
if ($this->wiki->config['authorized-extensions'] && !in_array($ext, array_keys($this->wiki->config['authorized-extensions']))) {
752752
$_FILES['upFile']['error'] = 5;
753753
}
754-
$destFile = $this->GetFullFilename(true); //nom du fichier destination
755-
//test de la taille du fichier recu
754+
$destFile = $this->GetFullFilename(true); // nom du fichier destination
755+
// test de la taille du fichier recu
756756
if ($_FILES['upFile']['error'] == 0) {
757757
$size = filesize($_FILES['upFile']['tmp_name']);
758758
if ($size > $this->attachConfig['max_file_size']) {
@@ -823,8 +823,8 @@ public function doDownload()
823823
header('Cache-Control: no-store, no-cache, must-revalidate'); // HTTP/1.1
824824
header('Cache-Control: pre-check=0, post-check=0, max-age=0'); // HTTP/1.1
825825
header('Content-Transfer-Encoding: none');
826-
header('Content-Type: application/octet-stream; name="' . $dlFilename . '"'); //This should work for the rest
827-
header('Content-Type: application/octetstream; name="' . $dlFilename . '"'); //This should work for IE & Opera
826+
header('Content-Type: application/octet-stream; name="' . $dlFilename . '"'); // This should work for the rest
827+
header('Content-Type: application/octetstream; name="' . $dlFilename . '"'); // This should work for IE & Opera
828828
if (in_array(preg_replace("/^.*\.([^.]+$)/", '$1', $dlFilename), ['txt', 'md', 'png', 'svg', 'jpeg', 'jpg', 'mp3'])) {
829829
header('Content-Type: ' . mime_content_type($fullFilename) . '; name="' . $dlFilename . '"');
830830
}
@@ -866,7 +866,7 @@ public function doFileManager($isAction = false)
866866
$this->fmShow(true, $isAction);
867867
break;
868868
case 'emptytrash':
869-
$this->fmEmptyTrash(); //pas de break car apres un emptytrash => retour au gestionnaire
869+
$this->fmEmptyTrash(); // pas de break car apres un emptytrash => retour au gestionnaire
870870
// no break
871871
default:
872872
$this->fmShow(false, $isAction);
@@ -999,8 +999,10 @@ public function fmEmptyTrash()
999999
public function fmErase()
10001000
{
10011001
$path = $this->GetUploadPath();
1002-
$filename = $path . '/' . ($_GET['file'] ? $_GET['file'] : '');
1003-
if (file_exists($filename)) {
1002+
// Sanitize file path
1003+
$filename = $this->GetUploadPath() . '/' . basename(realpath($_GET['file'] ? $_GET['file'] : ''));
1004+
// Make sure that the filename ends with trash and a date
1005+
if (file_exists($filename) && preg_match('/trash\d{14}$/', $filename)) {
10041006
unlink($filename);
10051007
}
10061008
}
@@ -1077,7 +1079,7 @@ function ByNameByRevFile($f1, $f2)
10771079
$f2Name = $f2['name'] . '.' . $f2['ext'];
10781080
$res = strcasecmp($f1Name, $f2Name);
10791081
if ($res == 0) {
1080-
//si meme nom => compare la revision du fichier
1082+
// si meme nom => compare la revision du fichier
10811083
$res = strcasecmp($f1['dateupload'], $f2['dateupload']);
10821084
}
10831085

@@ -1140,13 +1142,13 @@ public function redimensionner_image($image_src, $image_dest, $largeur, $hauteur
11401142
// get image info except for webp (code copier from Zebra_Image)
11411143
if (
11421144
!(
1143-
version_compare(PHP_VERSION, '7.0.0') >= 0 &&
1144-
version_compare(PHP_VERSION, '7.1.0') < 0 &&
1145-
(
1145+
version_compare(PHP_VERSION, '7.0.0') >= 0
1146+
&& version_compare(PHP_VERSION, '7.1.0') < 0
1147+
&& (
11461148
$imgTrans->source_type = strtolower(substr($imgTrans->source_path, strrpos($imgTrans->source_path, '.') + 1))
11471149
) === 'webp'
1148-
) &&
1149-
!list($sourceImageWidth, $sourceImageHeight, $sourceImageType) = @getimagesize($imgTrans->source_path)
1150+
)
1151+
&& !list($sourceImageWidth, $sourceImageHeight, $sourceImageType) = @getimagesize($imgTrans->source_path)
11501152
) {
11511153
return false;
11521154
}

0 commit comments

Comments
 (0)